13a3c9242SWarner Losh#!/usr/bin/env perl 23a3c9242SWarner Losh# (c) 2001, Dave Jones. (the file handling bit) 33a3c9242SWarner Losh# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) 43a3c9242SWarner Losh# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) 53a3c9242SWarner Losh# (c) 2008-2010 Andy Whitcroft <apw@canonical.com> 63a3c9242SWarner Losh# Licensed under the terms of the GNU GPL License version 2 73a3c9242SWarner Losh 83a3c9242SWarner Loshuse strict; 93a3c9242SWarner Loshuse warnings; 103a3c9242SWarner Loshuse Term::ANSIColor qw(:constants); 113a3c9242SWarner Losh 123a3c9242SWarner Loshmy $P = $0; 133a3c9242SWarner Losh$P =~ s@.*/@@g; 143a3c9242SWarner Losh 15*0207010fSWarner Loshour $SrcFile = qr{\.(?:h|c|cpp|hpp|hh|cc|S|sh)$}; 163a3c9242SWarner Losh 173a3c9242SWarner Loshmy $V = '0.31'; 183a3c9242SWarner Losh 193a3c9242SWarner Loshuse Getopt::Long qw(:config no_auto_abbrev); 203a3c9242SWarner Losh 213a3c9242SWarner Loshmy $quiet = 0; 223a3c9242SWarner Loshmy $tree = 1; 233a3c9242SWarner Loshmy $chk_signoff = 1; 243a3c9242SWarner Loshmy $chk_patch = undef; 253a3c9242SWarner Loshmy $chk_branch = undef; 263a3c9242SWarner Loshmy $tst_only; 273a3c9242SWarner Loshmy $emacs = 0; 280949b237SWarner Loshmy $github = 0; 293a3c9242SWarner Loshmy $terse = 0; 303a3c9242SWarner Loshmy $file = undef; 313a3c9242SWarner Loshmy $color = "auto"; 323a3c9242SWarner Loshmy $no_warnings = 0; 333a3c9242SWarner Loshmy $summary = 1; 343a3c9242SWarner Loshmy $mailback = 0; 353a3c9242SWarner Loshmy $summary_file = 0; 363a3c9242SWarner Loshmy $root; 373a3c9242SWarner Loshmy %debug; 383a3c9242SWarner Loshmy $help = 0; 393a3c9242SWarner Losh 403a3c9242SWarner Loshsub help { 413a3c9242SWarner Losh my ($exitcode) = @_; 423a3c9242SWarner Losh 433a3c9242SWarner Losh print << "EOM"; 443a3c9242SWarner LoshUsage: 453a3c9242SWarner Losh 463a3c9242SWarner Losh $P [OPTION]... [FILE]... 473a3c9242SWarner Losh $P [OPTION]... [GIT-REV-LIST] 483a3c9242SWarner Losh 493a3c9242SWarner LoshVersion: $V 503a3c9242SWarner Losh 513a3c9242SWarner LoshOptions: 523a3c9242SWarner Losh -q, --quiet quiet 533a3c9242SWarner Losh --patch treat FILE as patchfile 543a3c9242SWarner Losh --branch treat args as GIT revision list 553a3c9242SWarner Losh --emacs emacs compile window format 563a3c9242SWarner Losh --terse one line per report 573a3c9242SWarner Losh -f, --file treat FILE as regular source file 583a3c9242SWarner Losh --strict fail if only warnings are found 593a3c9242SWarner Losh --no-summary suppress the per-file summary 603a3c9242SWarner Losh --mailback only produce a report in case of warnings/errors 613a3c9242SWarner Losh --summary-file include the filename in summary 623a3c9242SWarner Losh --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of 633a3c9242SWarner Losh 'values', 'possible', 'type', and 'attr' (default 643a3c9242SWarner Losh is all off) 653a3c9242SWarner Losh --test-only=WORD report only warnings/errors containing WORD 663a3c9242SWarner Losh literally 673a3c9242SWarner Losh --color[=WHEN] Use colors 'always', 'never', or only when output 683a3c9242SWarner Losh is a terminal ('auto'). Default is 'auto'. 693a3c9242SWarner Losh -h, --help, --version display this help and exit 703a3c9242SWarner Losh 713a3c9242SWarner LoshWhen FILE is - read standard input. 723a3c9242SWarner LoshEOM 733a3c9242SWarner Losh 743a3c9242SWarner Losh exit($exitcode); 753a3c9242SWarner Losh} 763a3c9242SWarner Losh 773a3c9242SWarner Losh# Use at your own risk 783a3c9242SWarner Loshprint "\n", MAGENTA, "WARNING:", RESET, " This code is highly experimental ... likely isn't a great style(9) match yet\n\n"; 793a3c9242SWarner Losh 803a3c9242SWarner Losh# Perl's Getopt::Long allows options to take optional arguments after a space. 813a3c9242SWarner Losh# Prevent --color by itself from consuming other arguments 823a3c9242SWarner Loshforeach (@ARGV) { 833a3c9242SWarner Losh if ($_ eq "--color" || $_ eq "-color") { 843a3c9242SWarner Losh $_ = "--color=$color"; 853a3c9242SWarner Losh } 863a3c9242SWarner Losh} 873a3c9242SWarner Losh 883a3c9242SWarner LoshGetOptions( 893a3c9242SWarner Losh 'q|quiet+' => \$quiet, 903a3c9242SWarner Losh 'tree!' => \$tree, 913a3c9242SWarner Losh 'signoff!' => \$chk_signoff, 923a3c9242SWarner Losh 'patch!' => \$chk_patch, 933a3c9242SWarner Losh 'branch!' => \$chk_branch, 943a3c9242SWarner Losh 'emacs!' => \$emacs, 950949b237SWarner Losh 'github!' => \$github, 963a3c9242SWarner Losh 'terse!' => \$terse, 973a3c9242SWarner Losh 'f|file!' => \$file, 983a3c9242SWarner Losh 'strict!' => \$no_warnings, 993a3c9242SWarner Losh 'root=s' => \$root, 1003a3c9242SWarner Losh 'summary!' => \$summary, 1013a3c9242SWarner Losh 'mailback!' => \$mailback, 1023a3c9242SWarner Losh 'summary-file!' => \$summary_file, 1033a3c9242SWarner Losh 1043a3c9242SWarner Losh 'debug=s' => \%debug, 1053a3c9242SWarner Losh 'test-only=s' => \$tst_only, 1063a3c9242SWarner Losh 'color=s' => \$color, 1073a3c9242SWarner Losh 'no-color' => sub { $color = 'never'; }, 1083a3c9242SWarner Losh 'h|help' => \$help, 1093a3c9242SWarner Losh 'version' => \$help 1103a3c9242SWarner Losh) or help(1); 1113a3c9242SWarner Losh 1123a3c9242SWarner Loshhelp(0) if ($help); 1133a3c9242SWarner Losh 1143a3c9242SWarner Loshmy $exit = 0; 1153a3c9242SWarner Losh 1163a3c9242SWarner Loshif ($#ARGV < 0) { 1173a3c9242SWarner Losh print "$P: no input files\n"; 1183a3c9242SWarner Losh exit(1); 1193a3c9242SWarner Losh} 1203a3c9242SWarner Losh 1213a3c9242SWarner Loshif (!defined $chk_branch && !defined $chk_patch && !defined $file) { 1223a3c9242SWarner Losh $chk_branch = $ARGV[0] =~ /.\.\./ ? 1 : 0; 1233a3c9242SWarner Losh $file = $ARGV[0] =~ /$SrcFile/ ? 1 : 0; 1243a3c9242SWarner Losh $chk_patch = $chk_branch || $file ? 0 : 1; 1253a3c9242SWarner Losh} elsif (!defined $chk_branch && !defined $chk_patch) { 1263a3c9242SWarner Losh if ($file) { 1273a3c9242SWarner Losh $chk_branch = $chk_patch = 0; 1283a3c9242SWarner Losh } else { 1293a3c9242SWarner Losh $chk_branch = $ARGV[0] =~ /.\.\./ ? 1 : 0; 1303a3c9242SWarner Losh $chk_patch = $chk_branch ? 0 : 1; 1313a3c9242SWarner Losh } 1323a3c9242SWarner Losh} elsif (!defined $chk_branch && !defined $file) { 1333a3c9242SWarner Losh if ($chk_patch) { 1343a3c9242SWarner Losh $chk_branch = $file = 0; 1353a3c9242SWarner Losh } else { 1363a3c9242SWarner Losh $chk_branch = $ARGV[0] =~ /.\.\./ ? 1 : 0; 1373a3c9242SWarner Losh $file = $chk_branch ? 0 : 1; 1383a3c9242SWarner Losh } 1393a3c9242SWarner Losh} elsif (!defined $chk_patch && !defined $file) { 1403a3c9242SWarner Losh if ($chk_branch) { 1413a3c9242SWarner Losh $chk_patch = $file = 0; 1423a3c9242SWarner Losh } else { 1433a3c9242SWarner Losh $file = $ARGV[0] =~ /$SrcFile/ ? 1 : 0; 1443a3c9242SWarner Losh $chk_patch = $file ? 0 : 1; 1453a3c9242SWarner Losh } 1463a3c9242SWarner Losh} elsif (!defined $chk_branch) { 1473a3c9242SWarner Losh $chk_branch = $chk_patch || $file ? 0 : 1; 1483a3c9242SWarner Losh} elsif (!defined $chk_patch) { 1493a3c9242SWarner Losh $chk_patch = $chk_branch || $file ? 0 : 1; 1503a3c9242SWarner Losh} elsif (!defined $file) { 1513a3c9242SWarner Losh $file = $chk_patch || $chk_branch ? 0 : 1; 1523a3c9242SWarner Losh} 1533a3c9242SWarner Losh 1543a3c9242SWarner Loshif (($chk_patch && $chk_branch) || 1553a3c9242SWarner Losh ($chk_patch && $file) || 1563a3c9242SWarner Losh ($chk_branch && $file)) { 1573a3c9242SWarner Losh die "Only one of --file, --branch, --patch is permitted\n"; 1583a3c9242SWarner Losh} 1593a3c9242SWarner Loshif (!$chk_patch && !$chk_branch && !$file) { 1603a3c9242SWarner Losh die "One of --file, --branch, --patch is required\n"; 1613a3c9242SWarner Losh} 1623a3c9242SWarner Losh 1633a3c9242SWarner Loshif ($color =~ /^always$/i) { 1643a3c9242SWarner Losh $color = 1; 1653a3c9242SWarner Losh} elsif ($color =~ /^never$/i) { 1663a3c9242SWarner Losh $color = 0; 1673a3c9242SWarner Losh} elsif ($color =~ /^auto$/i) { 1683a3c9242SWarner Losh $color = (-t STDOUT); 1693a3c9242SWarner Losh} else { 1703a3c9242SWarner Losh die "Invalid color mode: $color\n"; 1713a3c9242SWarner Losh} 1723a3c9242SWarner Losh 1733a3c9242SWarner Loshmy $dbg_values = 0; 1743a3c9242SWarner Loshmy $dbg_possible = 0; 1753a3c9242SWarner Loshmy $dbg_adv_dcs = 0; 1763a3c9242SWarner Loshmy $dbg_adv_checking = 0; 1773a3c9242SWarner Loshmy $dbg_adv_apw = 0; 1783a3c9242SWarner Loshfor my $key (keys %debug) { 1793a3c9242SWarner Losh ## no critic 1803a3c9242SWarner Losh eval "\${dbg_$key} = '$debug{$key}';"; 1813a3c9242SWarner Losh die "$@" if ($@); 1823a3c9242SWarner Losh} 1833a3c9242SWarner Losh 1843a3c9242SWarner Loshmy $rpt_cleaners = 0; 1853a3c9242SWarner Losh 1863a3c9242SWarner Loshif ($terse) { 1873a3c9242SWarner Losh $emacs = 1; 1883a3c9242SWarner Losh $quiet++; 1893a3c9242SWarner Losh} 1903a3c9242SWarner Losh 1913a3c9242SWarner Loshmy $emitted_corrupt = 0; 1923a3c9242SWarner Losh 1933a3c9242SWarner Loshour $Ident = qr{ 1943a3c9242SWarner Losh [A-Za-z_][A-Za-z\d_]* 1953a3c9242SWarner Losh (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* 1963a3c9242SWarner Losh }x; 1973a3c9242SWarner Loshour $Storage = qr{extern|static|asmlinkage}; 1983a3c9242SWarner Loshour $Sparse = qr{ 1993a3c9242SWarner Losh __force 2003a3c9242SWarner Losh }x; 2013a3c9242SWarner Losh 2023a3c9242SWarner Losh# Notes to $Attribute: 2033a3c9242SWarner Loshour $Attribute = qr{ 2043a3c9242SWarner Losh const| 20542255af6SMateusz Piotrowski _*restrict| 2063a3c9242SWarner Losh volatile| 2073a3c9242SWarner Losh QEMU_NORETURN| 2083a3c9242SWarner Losh QEMU_WARN_UNUSED_RESULT| 2093a3c9242SWarner Losh QEMU_SENTINEL| 2103a3c9242SWarner Losh QEMU_PACKED| 2113a3c9242SWarner Losh GCC_FMT_ATTR 2123a3c9242SWarner Losh }x; 2133a3c9242SWarner Loshour $Modifier; 2143a3c9242SWarner Loshour $Inline = qr{inline}; 2153a3c9242SWarner Loshour $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; 2163a3c9242SWarner Loshour $Lval = qr{$Ident(?:$Member)*}; 2173a3c9242SWarner Losh 2183a3c9242SWarner Loshour $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; 2193a3c9242SWarner Loshour $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; 2203a3c9242SWarner Loshour $Compare = qr{<=|>=|==|!=|<|>}; 2213a3c9242SWarner Loshour $Operators = qr{ 2223a3c9242SWarner Losh <=|>=|==|!=| 2233a3c9242SWarner Losh =>|->|<<|>>|<|>|!|~| 2243a3c9242SWarner Losh &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% 2253a3c9242SWarner Losh }x; 2263a3c9242SWarner Losh 2273a3c9242SWarner Loshour $NonptrType; 2283a3c9242SWarner Loshour $Type; 2293a3c9242SWarner Loshour $Declare; 2303a3c9242SWarner Losh 2313a3c9242SWarner Loshour $NON_ASCII_UTF8 = qr{ 2323a3c9242SWarner Losh [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte 2333a3c9242SWarner Losh | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs 2343a3c9242SWarner Losh | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 2353a3c9242SWarner Losh | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates 2363a3c9242SWarner Losh | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 2373a3c9242SWarner Losh | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 2383a3c9242SWarner Losh | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 2393a3c9242SWarner Losh}x; 2403a3c9242SWarner Losh 2413a3c9242SWarner Loshour $UTF8 = qr{ 2423a3c9242SWarner Losh [\x09\x0A\x0D\x20-\x7E] # ASCII 2433a3c9242SWarner Losh | $NON_ASCII_UTF8 2443a3c9242SWarner Losh}x; 2453a3c9242SWarner Losh 2463a3c9242SWarner Losh# some readers default to ISO-8859-1 when showing email source. detect 2473a3c9242SWarner Losh# when UTF-8 is incorrectly interpreted as ISO-8859-1 and reencoded back. 2483a3c9242SWarner Losh# False positives are possible but very unlikely. 2493a3c9242SWarner Loshour $UTF8_MOJIBAKE = qr{ 2503a3c9242SWarner Losh \xC3[\x82-\x9F] \xC2[\x80-\xBF] # c2-df 80-bf 2513a3c9242SWarner Losh | \xC3\xA0 \xC2[\xA0-\xBF] \xC2[\x80-\xBF] # e0 a0-bf 80-bf 2523a3c9242SWarner Losh | \xC3[\xA1-\xAC\xAE\xAF] (?: \xC2[\x80-\xBF]){2} # e1-ec/ee/ef 80-bf 80-bf 2533a3c9242SWarner Losh | \xC3\xAD \xC2[\x80-\x9F] \xC2[\x80-\xBF] # ed 80-9f 80-bf 2543a3c9242SWarner Losh | \xC3\xB0 \xC2[\x90-\xBF] (?: \xC2[\x80-\xBF]){2} # f0 90-bf 80-bf 80-bf 2553a3c9242SWarner Losh | \xC3[\xB1-\xB3] (?: \xC2[\x80-\xBF]){3} # f1-f3 80-bf 80-bf 80-bf 2563a3c9242SWarner Losh | \xC3\xB4 \xC2[\x80-\x8F] (?: \xC2[\x80-\xBF]){2} # f4 80-b8 80-bf 80-bf 2573a3c9242SWarner Losh}x; 2583a3c9242SWarner Losh 2593a3c9242SWarner Losh# There are still some false positives, but this catches most 2603a3c9242SWarner Losh# common cases. 2613a3c9242SWarner Loshour $typeTypedefs = qr{(?x: 2623a3c9242SWarner Losh (?![KMGTPE]iB) # IEC binary prefix (do not match) 2633a3c9242SWarner Losh [A-Z][A-Z\d_]*[a-z][A-Za-z\d_]* # camelcase 2643a3c9242SWarner Losh | [A-Z][A-Z\d_]*AIOCB # all uppercase 2653a3c9242SWarner Losh | [A-Z][A-Z\d_]*CPU # all uppercase 2663a3c9242SWarner Losh | QEMUBH # all uppercase 2673a3c9242SWarner Losh)}; 2683a3c9242SWarner Losh 2693a3c9242SWarner Loshour @typeList = ( 2703a3c9242SWarner Losh qr{void}, 2713a3c9242SWarner Losh qr{(?:unsigned\s+)?char}, 2723a3c9242SWarner Losh qr{(?:unsigned\s+)?short}, 2733a3c9242SWarner Losh qr{(?:unsigned\s+)?int}, 2743a3c9242SWarner Losh qr{(?:unsigned\s+)?long}, 2753a3c9242SWarner Losh qr{(?:unsigned\s+)?long\s+int}, 2763a3c9242SWarner Losh qr{(?:unsigned\s+)?long\s+long}, 2773a3c9242SWarner Losh qr{(?:unsigned\s+)?long\s+long\s+int}, 2783a3c9242SWarner Losh qr{unsigned}, 2793a3c9242SWarner Losh qr{float}, 2803a3c9242SWarner Losh qr{double}, 2813a3c9242SWarner Losh qr{bool}, 2823a3c9242SWarner Losh qr{struct\s+$Ident}, 2833a3c9242SWarner Losh qr{union\s+$Ident}, 2843a3c9242SWarner Losh qr{enum\s+$Ident}, 2853a3c9242SWarner Losh qr{${Ident}_t}, 2863a3c9242SWarner Losh qr{${Ident}_handler}, 2873a3c9242SWarner Losh qr{${Ident}_handler_fn}, 2883a3c9242SWarner Losh qr{target_(?:u)?long}, 2893a3c9242SWarner Losh qr{hwaddr}, 2903a3c9242SWarner Losh); 2913a3c9242SWarner Losh 2923a3c9242SWarner Losh# This can be modified by sub possible. Since it can be empty, be careful 2933a3c9242SWarner Losh# about regexes that always match, because they can cause infinite loops. 2943a3c9242SWarner Loshour @modifierList = ( 2953a3c9242SWarner Losh); 2963a3c9242SWarner Losh 2973a3c9242SWarner Loshsub build_types { 2983a3c9242SWarner Losh my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; 2993a3c9242SWarner Losh if (@modifierList > 0) { 3003a3c9242SWarner Losh my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; 3013a3c9242SWarner Losh $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; 3023a3c9242SWarner Losh } else { 3033a3c9242SWarner Losh $Modifier = qr{(?:$Attribute|$Sparse)}; 3043a3c9242SWarner Losh } 3053a3c9242SWarner Losh $NonptrType = qr{ 3063a3c9242SWarner Losh (?:$Modifier\s+|const\s+)* 3073a3c9242SWarner Losh (?: 3083a3c9242SWarner Losh (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| 3093a3c9242SWarner Losh (?:$typeTypedefs\b)| 3103a3c9242SWarner Losh (?:${all}\b) 3113a3c9242SWarner Losh ) 3123a3c9242SWarner Losh (?:\s+$Modifier|\s+const)* 3133a3c9242SWarner Losh }x; 3143a3c9242SWarner Losh $Type = qr{ 3153a3c9242SWarner Losh $NonptrType 3163a3c9242SWarner Losh (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? 3173a3c9242SWarner Losh (?:\s+$Inline|\s+$Modifier)* 3183a3c9242SWarner Losh }x; 3193a3c9242SWarner Losh $Declare = qr{(?:$Storage\s+)?$Type}; 3203a3c9242SWarner Losh} 3213a3c9242SWarner Loshbuild_types(); 3223a3c9242SWarner Losh 3233a3c9242SWarner Losh$chk_signoff = 0 if ($file); 3243a3c9242SWarner Losh 3253a3c9242SWarner Loshmy @rawlines = (); 3263a3c9242SWarner Loshmy @lines = (); 3273a3c9242SWarner Loshmy $vname; 3283a3c9242SWarner Loshif ($chk_branch) { 3293a3c9242SWarner Losh my @patches; 3303a3c9242SWarner Losh my %git_commits = (); 3313a3c9242SWarner Losh my $HASH; 3323a3c9242SWarner Losh open($HASH, "-|", "git", "log", "--reverse", "--no-merges", "--format=%H %s", $ARGV[0]) || 3333a3c9242SWarner Losh die "$P: git log --reverse --no-merges --format='%H %s' $ARGV[0] failed - $!\n"; 3343a3c9242SWarner Losh 3353a3c9242SWarner Losh for my $line (<$HASH>) { 3363a3c9242SWarner Losh $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; 3373a3c9242SWarner Losh next if (!defined($1) || !defined($2)); 3383a3c9242SWarner Losh my $sha1 = $1; 3393a3c9242SWarner Losh my $subject = $2; 3403a3c9242SWarner Losh push(@patches, $sha1); 3413a3c9242SWarner Losh $git_commits{$sha1} = $subject; 3423a3c9242SWarner Losh } 3433a3c9242SWarner Losh 3443a3c9242SWarner Losh close $HASH; 3453a3c9242SWarner Losh 3463a3c9242SWarner Losh die "$P: no revisions returned for revlist '$ARGV[0]'\n" 3473a3c9242SWarner Losh unless @patches; 3483a3c9242SWarner Losh 3493a3c9242SWarner Losh my $i = 1; 3503a3c9242SWarner Losh my $num_patches = @patches; 3513a3c9242SWarner Losh for my $hash (@patches) { 3523a3c9242SWarner Losh my $FILE; 3533a3c9242SWarner Losh open($FILE, '-|', "git", "show", "--patch-with-stat", $hash) || 3543a3c9242SWarner Losh die "$P: git show $hash - $!\n"; 3553a3c9242SWarner Losh while (<$FILE>) { 3563a3c9242SWarner Losh chomp; 3573a3c9242SWarner Losh push(@rawlines, $_); 3583a3c9242SWarner Losh } 3593a3c9242SWarner Losh close($FILE); 3603a3c9242SWarner Losh $vname = substr($hash, 0, 12) . ' (' . $git_commits{$hash} . ')'; 3613a3c9242SWarner Losh if ($num_patches > 1 && $quiet == 0) { 3623a3c9242SWarner Losh my $prefix = "$i/$num_patches"; 3633a3c9242SWarner Losh $prefix = BLUE . BOLD . $prefix . RESET if $color; 3643a3c9242SWarner Losh print "$prefix Checking commit $vname\n"; 3653a3c9242SWarner Losh $vname = "Patch $i/$num_patches"; 3663a3c9242SWarner Losh } else { 3673a3c9242SWarner Losh $vname = "Commit " . $vname; 3683a3c9242SWarner Losh } 3693a3c9242SWarner Losh if (!process($hash)) { 3703a3c9242SWarner Losh $exit = 1; 3713a3c9242SWarner Losh print "\n" if ($num_patches > 1 && $quiet == 0); 3723a3c9242SWarner Losh } 3733a3c9242SWarner Losh @rawlines = (); 3743a3c9242SWarner Losh @lines = (); 3753a3c9242SWarner Losh $i++; 3763a3c9242SWarner Losh } 3773a3c9242SWarner Losh} else { 3783a3c9242SWarner Losh for my $filename (@ARGV) { 3793a3c9242SWarner Losh my $FILE; 3803a3c9242SWarner Losh if ($file) { 3813a3c9242SWarner Losh open($FILE, '-|', "diff -u /dev/null $filename") || 3823a3c9242SWarner Losh die "$P: $filename: diff failed - $!\n"; 3833a3c9242SWarner Losh } elsif ($filename eq '-') { 3843a3c9242SWarner Losh open($FILE, '<&STDIN'); 3853a3c9242SWarner Losh } else { 3863a3c9242SWarner Losh open($FILE, '<', "$filename") || 3873a3c9242SWarner Losh die "$P: $filename: open failed - $!\n"; 3883a3c9242SWarner Losh } 3893a3c9242SWarner Losh if ($filename eq '-') { 3903a3c9242SWarner Losh $vname = 'Your patch'; 3913a3c9242SWarner Losh } else { 3923a3c9242SWarner Losh $vname = $filename; 3933a3c9242SWarner Losh } 3943a3c9242SWarner Losh print "Checking $filename...\n" if @ARGV > 1 && $quiet == 0; 3953a3c9242SWarner Losh while (<$FILE>) { 3963a3c9242SWarner Losh chomp; 3973a3c9242SWarner Losh push(@rawlines, $_); 3983a3c9242SWarner Losh } 3993a3c9242SWarner Losh close($FILE); 4003a3c9242SWarner Losh if (!process($filename)) { 4013a3c9242SWarner Losh $exit = 1; 4023a3c9242SWarner Losh } 4033a3c9242SWarner Losh @rawlines = (); 4043a3c9242SWarner Losh @lines = (); 4053a3c9242SWarner Losh } 4063a3c9242SWarner Losh} 4073a3c9242SWarner Losh 4083a3c9242SWarner Loshexit($exit); 4093a3c9242SWarner Losh 4103a3c9242SWarner Loshsub top_of_kernel_tree { 4113a3c9242SWarner Losh my ($root) = @_; 4123a3c9242SWarner Losh 4133a3c9242SWarner Losh my @tree_check = ( 4143a3c9242SWarner Losh "Makefile.inc1", "README.md", "sys", 4153a3c9242SWarner Losh "usr.sbin" 4163a3c9242SWarner Losh ); 4173a3c9242SWarner Losh 4183a3c9242SWarner Losh foreach my $check (@tree_check) { 4193a3c9242SWarner Losh if (! -e $root . '/' . $check) { 4203a3c9242SWarner Losh return 0; 4213a3c9242SWarner Losh } 4223a3c9242SWarner Losh } 4233a3c9242SWarner Losh return 1; 4243a3c9242SWarner Losh} 4253a3c9242SWarner Losh 4263a3c9242SWarner Loshsub expand_tabs { 4273a3c9242SWarner Losh my ($str) = @_; 4283a3c9242SWarner Losh 4293a3c9242SWarner Losh my $res = ''; 4303a3c9242SWarner Losh my $n = 0; 4313a3c9242SWarner Losh for my $c (split(//, $str)) { 4323a3c9242SWarner Losh if ($c eq "\t") { 4333a3c9242SWarner Losh $res .= ' '; 4343a3c9242SWarner Losh $n++; 4353a3c9242SWarner Losh for (; ($n % 8) != 0; $n++) { 4363a3c9242SWarner Losh $res .= ' '; 4373a3c9242SWarner Losh } 4383a3c9242SWarner Losh next; 4393a3c9242SWarner Losh } 4403a3c9242SWarner Losh $res .= $c; 4413a3c9242SWarner Losh $n++; 4423a3c9242SWarner Losh } 4433a3c9242SWarner Losh 4443a3c9242SWarner Losh return $res; 4453a3c9242SWarner Losh} 4463a3c9242SWarner Loshsub copy_spacing { 4473a3c9242SWarner Losh (my $res = shift) =~ tr/\t/ /c; 4483a3c9242SWarner Losh return $res; 4493a3c9242SWarner Losh} 4503a3c9242SWarner Losh 4513a3c9242SWarner Loshsub line_stats { 4523a3c9242SWarner Losh my ($line) = @_; 4533a3c9242SWarner Losh 4543a3c9242SWarner Losh # Drop the diff line leader and expand tabs 4553a3c9242SWarner Losh $line =~ s/^.//; 4563a3c9242SWarner Losh $line = expand_tabs($line); 4573a3c9242SWarner Losh 4583a3c9242SWarner Losh # Pick the indent from the front of the line. 4593a3c9242SWarner Losh my ($white) = ($line =~ /^(\s*)/); 4603a3c9242SWarner Losh 4613a3c9242SWarner Losh return (length($line), length($white)); 4623a3c9242SWarner Losh} 4633a3c9242SWarner Losh 4643a3c9242SWarner Loshmy $sanitise_quote = ''; 4653a3c9242SWarner Losh 4663a3c9242SWarner Loshsub sanitise_line_reset { 4673a3c9242SWarner Losh my ($in_comment) = @_; 4683a3c9242SWarner Losh 4693a3c9242SWarner Losh if ($in_comment) { 4703a3c9242SWarner Losh $sanitise_quote = '*/'; 4713a3c9242SWarner Losh } else { 4723a3c9242SWarner Losh $sanitise_quote = ''; 4733a3c9242SWarner Losh } 4743a3c9242SWarner Losh} 4753a3c9242SWarner Loshsub sanitise_line { 4763a3c9242SWarner Losh my ($line) = @_; 4773a3c9242SWarner Losh 4783a3c9242SWarner Losh my $res = ''; 4793a3c9242SWarner Losh my $l = ''; 4803a3c9242SWarner Losh 4813a3c9242SWarner Losh my $qlen = 0; 4823a3c9242SWarner Losh my $off = 0; 4833a3c9242SWarner Losh my $c; 4843a3c9242SWarner Losh 4853a3c9242SWarner Losh # Always copy over the diff marker. 4863a3c9242SWarner Losh $res = substr($line, 0, 1); 4873a3c9242SWarner Losh 4883a3c9242SWarner Losh for ($off = 1; $off < length($line); $off++) { 4893a3c9242SWarner Losh $c = substr($line, $off, 1); 4903a3c9242SWarner Losh 4913a3c9242SWarner Losh # Comments we are wacking completely including the begin 4923a3c9242SWarner Losh # and end, all to $;. 4933a3c9242SWarner Losh if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { 4943a3c9242SWarner Losh $sanitise_quote = '*/'; 4953a3c9242SWarner Losh 4963a3c9242SWarner Losh substr($res, $off, 2, "$;$;"); 4973a3c9242SWarner Losh $off++; 4983a3c9242SWarner Losh next; 4993a3c9242SWarner Losh } 5003a3c9242SWarner Losh if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { 5013a3c9242SWarner Losh $sanitise_quote = ''; 5023a3c9242SWarner Losh substr($res, $off, 2, "$;$;"); 5033a3c9242SWarner Losh $off++; 5043a3c9242SWarner Losh next; 5053a3c9242SWarner Losh } 5063a3c9242SWarner Losh if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { 5073a3c9242SWarner Losh $sanitise_quote = '//'; 5083a3c9242SWarner Losh 5093a3c9242SWarner Losh substr($res, $off, 2, $sanitise_quote); 5103a3c9242SWarner Losh $off++; 5113a3c9242SWarner Losh next; 5123a3c9242SWarner Losh } 5133a3c9242SWarner Losh 5143a3c9242SWarner Losh # A \ in a string means ignore the next character. 5153a3c9242SWarner Losh if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && 5163a3c9242SWarner Losh $c eq "\\") { 5173a3c9242SWarner Losh substr($res, $off, 2, 'XX'); 5183a3c9242SWarner Losh $off++; 5193a3c9242SWarner Losh next; 5203a3c9242SWarner Losh } 5213a3c9242SWarner Losh # Regular quotes. 5223a3c9242SWarner Losh if ($c eq "'" || $c eq '"') { 5233a3c9242SWarner Losh if ($sanitise_quote eq '') { 5243a3c9242SWarner Losh $sanitise_quote = $c; 5253a3c9242SWarner Losh 5263a3c9242SWarner Losh substr($res, $off, 1, $c); 5273a3c9242SWarner Losh next; 5283a3c9242SWarner Losh } elsif ($sanitise_quote eq $c) { 5293a3c9242SWarner Losh $sanitise_quote = ''; 5303a3c9242SWarner Losh } 5313a3c9242SWarner Losh } 5323a3c9242SWarner Losh 5333a3c9242SWarner Losh #print "c<$c> SQ<$sanitise_quote>\n"; 5343a3c9242SWarner Losh if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { 5353a3c9242SWarner Losh substr($res, $off, 1, $;); 5363a3c9242SWarner Losh } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { 5373a3c9242SWarner Losh substr($res, $off, 1, $;); 5383a3c9242SWarner Losh } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { 5393a3c9242SWarner Losh substr($res, $off, 1, 'X'); 5403a3c9242SWarner Losh } else { 5413a3c9242SWarner Losh substr($res, $off, 1, $c); 5423a3c9242SWarner Losh } 5433a3c9242SWarner Losh } 5443a3c9242SWarner Losh 5453a3c9242SWarner Losh if ($sanitise_quote eq '//') { 5463a3c9242SWarner Losh $sanitise_quote = ''; 5473a3c9242SWarner Losh } 5483a3c9242SWarner Losh 5493a3c9242SWarner Losh # The pathname on a #include may be surrounded by '<' and '>'. 5503a3c9242SWarner Losh if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { 5513a3c9242SWarner Losh my $clean = 'X' x length($1); 5523a3c9242SWarner Losh $res =~ s@\<.*\>@<$clean>@; 5533a3c9242SWarner Losh 5543a3c9242SWarner Losh # The whole of a #error is a string. 5553a3c9242SWarner Losh } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { 5563a3c9242SWarner Losh my $clean = 'X' x length($1); 5573a3c9242SWarner Losh $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; 5583a3c9242SWarner Losh } 5593a3c9242SWarner Losh 5603a3c9242SWarner Losh return $res; 5613a3c9242SWarner Losh} 5623a3c9242SWarner Losh 5633a3c9242SWarner Loshsub ctx_statement_block { 5643a3c9242SWarner Losh my ($linenr, $remain, $off) = @_; 5653a3c9242SWarner Losh my $line = $linenr - 1; 5663a3c9242SWarner Losh my $blk = ''; 5673a3c9242SWarner Losh my $soff = $off; 5683a3c9242SWarner Losh my $coff = $off - 1; 5693a3c9242SWarner Losh my $coff_set = 0; 5703a3c9242SWarner Losh 5713a3c9242SWarner Losh my $loff = 0; 5723a3c9242SWarner Losh 5733a3c9242SWarner Losh my $type = ''; 5743a3c9242SWarner Losh my $level = 0; 5753a3c9242SWarner Losh my @stack = (); 5763a3c9242SWarner Losh my $p; 5773a3c9242SWarner Losh my $c; 5783a3c9242SWarner Losh my $len = 0; 5793a3c9242SWarner Losh 5803a3c9242SWarner Losh my $remainder; 5813a3c9242SWarner Losh while (1) { 5823a3c9242SWarner Losh @stack = (['', 0]) if ($#stack == -1); 5833a3c9242SWarner Losh 5843a3c9242SWarner Losh #warn "CSB: blk<$blk> remain<$remain>\n"; 5853a3c9242SWarner Losh # If we are about to drop off the end, pull in more 5863a3c9242SWarner Losh # context. 5873a3c9242SWarner Losh if ($off >= $len) { 5883a3c9242SWarner Losh for (; $remain > 0; $line++) { 5893a3c9242SWarner Losh last if (!defined $lines[$line]); 5903a3c9242SWarner Losh next if ($lines[$line] =~ /^-/); 5913a3c9242SWarner Losh $remain--; 5923a3c9242SWarner Losh $loff = $len; 5933a3c9242SWarner Losh $blk .= $lines[$line] . "\n"; 5943a3c9242SWarner Losh $len = length($blk); 5953a3c9242SWarner Losh $line++; 5963a3c9242SWarner Losh last; 5973a3c9242SWarner Losh } 5983a3c9242SWarner Losh # Bail if there is no further context. 5993a3c9242SWarner Losh #warn "CSB: blk<$blk> off<$off> len<$len>\n"; 6003a3c9242SWarner Losh if ($off >= $len) { 6013a3c9242SWarner Losh last; 6023a3c9242SWarner Losh } 6033a3c9242SWarner Losh } 6043a3c9242SWarner Losh $p = $c; 6053a3c9242SWarner Losh $c = substr($blk, $off, 1); 6063a3c9242SWarner Losh $remainder = substr($blk, $off); 6073a3c9242SWarner Losh 6083a3c9242SWarner Losh #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; 6093a3c9242SWarner Losh 6103a3c9242SWarner Losh # Handle nested #if/#else. 6113a3c9242SWarner Losh if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { 6123a3c9242SWarner Losh push(@stack, [ $type, $level ]); 6133a3c9242SWarner Losh } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { 6143a3c9242SWarner Losh ($type, $level) = @{$stack[$#stack - 1]}; 6153a3c9242SWarner Losh } elsif ($remainder =~ /^#\s*endif\b/) { 6163a3c9242SWarner Losh ($type, $level) = @{pop(@stack)}; 6173a3c9242SWarner Losh } 6183a3c9242SWarner Losh 6193a3c9242SWarner Losh # Statement ends at the ';' or a close '}' at the 6203a3c9242SWarner Losh # outermost level. 6213a3c9242SWarner Losh if ($level == 0 && $c eq ';') { 6223a3c9242SWarner Losh last; 6233a3c9242SWarner Losh } 6243a3c9242SWarner Losh 6253a3c9242SWarner Losh # An else is really a conditional as long as its not else if 6263a3c9242SWarner Losh if ($level == 0 && $coff_set == 0 && 6273a3c9242SWarner Losh (!defined($p) || $p =~ /(?:\s|\}|\+)/) && 6283a3c9242SWarner Losh $remainder =~ /^(else)(?:\s|{)/ && 6293a3c9242SWarner Losh $remainder !~ /^else\s+if\b/) { 6303a3c9242SWarner Losh $coff = $off + length($1) - 1; 6313a3c9242SWarner Losh $coff_set = 1; 6323a3c9242SWarner Losh #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; 6333a3c9242SWarner Losh #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; 6343a3c9242SWarner Losh } 6353a3c9242SWarner Losh 6363a3c9242SWarner Losh if (($type eq '' || $type eq '(') && $c eq '(') { 6373a3c9242SWarner Losh $level++; 6383a3c9242SWarner Losh $type = '('; 6393a3c9242SWarner Losh } 6403a3c9242SWarner Losh if ($type eq '(' && $c eq ')') { 6413a3c9242SWarner Losh $level--; 6423a3c9242SWarner Losh $type = ($level != 0)? '(' : ''; 6433a3c9242SWarner Losh 6443a3c9242SWarner Losh if ($level == 0 && $coff < $soff) { 6453a3c9242SWarner Losh $coff = $off; 6463a3c9242SWarner Losh $coff_set = 1; 6473a3c9242SWarner Losh #warn "CSB: mark coff<$coff>\n"; 6483a3c9242SWarner Losh } 6493a3c9242SWarner Losh } 6503a3c9242SWarner Losh if (($type eq '' || $type eq '{') && $c eq '{') { 6513a3c9242SWarner Losh $level++; 6523a3c9242SWarner Losh $type = '{'; 6533a3c9242SWarner Losh } 6543a3c9242SWarner Losh if ($type eq '{' && $c eq '}') { 6553a3c9242SWarner Losh $level--; 6563a3c9242SWarner Losh $type = ($level != 0)? '{' : ''; 6573a3c9242SWarner Losh 6583a3c9242SWarner Losh if ($level == 0) { 6593a3c9242SWarner Losh if (substr($blk, $off + 1, 1) eq ';') { 6603a3c9242SWarner Losh $off++; 6613a3c9242SWarner Losh } 6623a3c9242SWarner Losh last; 6633a3c9242SWarner Losh } 6643a3c9242SWarner Losh } 6653a3c9242SWarner Losh $off++; 6663a3c9242SWarner Losh } 6673a3c9242SWarner Losh # We are truly at the end, so shuffle to the next line. 6683a3c9242SWarner Losh if ($off == $len) { 6693a3c9242SWarner Losh $loff = $len + 1; 6703a3c9242SWarner Losh $line++; 6713a3c9242SWarner Losh $remain--; 6723a3c9242SWarner Losh } 6733a3c9242SWarner Losh 6743a3c9242SWarner Losh my $statement = substr($blk, $soff, $off - $soff + 1); 6753a3c9242SWarner Losh my $condition = substr($blk, $soff, $coff - $soff + 1); 6763a3c9242SWarner Losh 6773a3c9242SWarner Losh #warn "STATEMENT<$statement>\n"; 6783a3c9242SWarner Losh #warn "CONDITION<$condition>\n"; 6793a3c9242SWarner Losh 6803a3c9242SWarner Losh #print "coff<$coff> soff<$off> loff<$loff>\n"; 6813a3c9242SWarner Losh 6823a3c9242SWarner Losh return ($statement, $condition, 6833a3c9242SWarner Losh $line, $remain + 1, $off - $loff + 1, $level); 6843a3c9242SWarner Losh} 6853a3c9242SWarner Losh 6863a3c9242SWarner Loshsub statement_lines { 6873a3c9242SWarner Losh my ($stmt) = @_; 6883a3c9242SWarner Losh 6893a3c9242SWarner Losh # Strip the diff line prefixes and rip blank lines at start and end. 6903a3c9242SWarner Losh $stmt =~ s/(^|\n)./$1/g; 6913a3c9242SWarner Losh $stmt =~ s/^\s*//; 6923a3c9242SWarner Losh $stmt =~ s/\s*$//; 6933a3c9242SWarner Losh 6943a3c9242SWarner Losh my @stmt_lines = ($stmt =~ /\n/g); 6953a3c9242SWarner Losh 6963a3c9242SWarner Losh return $#stmt_lines + 2; 6973a3c9242SWarner Losh} 6983a3c9242SWarner Losh 6993a3c9242SWarner Loshsub statement_rawlines { 7003a3c9242SWarner Losh my ($stmt) = @_; 7013a3c9242SWarner Losh 7023a3c9242SWarner Losh my @stmt_lines = ($stmt =~ /\n/g); 7033a3c9242SWarner Losh 7043a3c9242SWarner Losh return $#stmt_lines + 2; 7053a3c9242SWarner Losh} 7063a3c9242SWarner Losh 7073a3c9242SWarner Loshsub statement_block_size { 7083a3c9242SWarner Losh my ($stmt) = @_; 7093a3c9242SWarner Losh 7103a3c9242SWarner Losh $stmt =~ s/(^|\n)./$1/g; 7113a3c9242SWarner Losh $stmt =~ s/^\s*\{//; 7123a3c9242SWarner Losh $stmt =~ s/}\s*$//; 7133a3c9242SWarner Losh $stmt =~ s/^\s*//; 7143a3c9242SWarner Losh $stmt =~ s/\s*$//; 7153a3c9242SWarner Losh 7163a3c9242SWarner Losh my @stmt_lines = ($stmt =~ /\n/g); 7173a3c9242SWarner Losh my @stmt_statements = ($stmt =~ /;/g); 7183a3c9242SWarner Losh 7193a3c9242SWarner Losh my $stmt_lines = $#stmt_lines + 2; 7203a3c9242SWarner Losh my $stmt_statements = $#stmt_statements + 1; 7213a3c9242SWarner Losh 7223a3c9242SWarner Losh if ($stmt_lines > $stmt_statements) { 7233a3c9242SWarner Losh return $stmt_lines; 7243a3c9242SWarner Losh } else { 7253a3c9242SWarner Losh return $stmt_statements; 7263a3c9242SWarner Losh } 7273a3c9242SWarner Losh} 7283a3c9242SWarner Losh 7293a3c9242SWarner Loshsub ctx_statement_full { 7303a3c9242SWarner Losh my ($linenr, $remain, $off) = @_; 7313a3c9242SWarner Losh my ($statement, $condition, $level); 7323a3c9242SWarner Losh 7333a3c9242SWarner Losh my (@chunks); 7343a3c9242SWarner Losh 7353a3c9242SWarner Losh # Grab the first conditional/block pair. 7363a3c9242SWarner Losh ($statement, $condition, $linenr, $remain, $off, $level) = 7373a3c9242SWarner Losh ctx_statement_block($linenr, $remain, $off); 7383a3c9242SWarner Losh #print "F: c<$condition> s<$statement> remain<$remain>\n"; 7393a3c9242SWarner Losh push(@chunks, [ $condition, $statement ]); 7403a3c9242SWarner Losh if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { 7413a3c9242SWarner Losh return ($level, $linenr, @chunks); 7423a3c9242SWarner Losh } 7433a3c9242SWarner Losh 7443a3c9242SWarner Losh # Pull in the following conditional/block pairs and see if they 7453a3c9242SWarner Losh # could continue the statement. 7463a3c9242SWarner Losh for (;;) { 7473a3c9242SWarner Losh ($statement, $condition, $linenr, $remain, $off, $level) = 7483a3c9242SWarner Losh ctx_statement_block($linenr, $remain, $off); 7493a3c9242SWarner Losh #print "C: c<$condition> s<$statement> remain<$remain>\n"; 7503a3c9242SWarner Losh last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); 7513a3c9242SWarner Losh #print "C: push\n"; 7523a3c9242SWarner Losh push(@chunks, [ $condition, $statement ]); 7533a3c9242SWarner Losh } 7543a3c9242SWarner Losh 7553a3c9242SWarner Losh return ($level, $linenr, @chunks); 7563a3c9242SWarner Losh} 7573a3c9242SWarner Losh 7583a3c9242SWarner Loshsub ctx_block_get { 7593a3c9242SWarner Losh my ($linenr, $remain, $outer, $open, $close, $off) = @_; 7603a3c9242SWarner Losh my $line; 7613a3c9242SWarner Losh my $start = $linenr - 1; 7623a3c9242SWarner Losh my $blk = ''; 7633a3c9242SWarner Losh my @o; 7643a3c9242SWarner Losh my @c; 7653a3c9242SWarner Losh my @res = (); 7663a3c9242SWarner Losh 7673a3c9242SWarner Losh my $level = 0; 7683a3c9242SWarner Losh my @stack = ($level); 7693a3c9242SWarner Losh for ($line = $start; $remain > 0; $line++) { 7703a3c9242SWarner Losh next if ($rawlines[$line] =~ /^-/); 7713a3c9242SWarner Losh $remain--; 7723a3c9242SWarner Losh 7733a3c9242SWarner Losh $blk .= $rawlines[$line]; 7743a3c9242SWarner Losh 7753a3c9242SWarner Losh # Handle nested #if/#else. 7763a3c9242SWarner Losh if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { 7773a3c9242SWarner Losh push(@stack, $level); 7783a3c9242SWarner Losh } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { 7793a3c9242SWarner Losh $level = $stack[$#stack - 1]; 7803a3c9242SWarner Losh } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { 7813a3c9242SWarner Losh $level = pop(@stack); 7823a3c9242SWarner Losh } 7833a3c9242SWarner Losh 7843a3c9242SWarner Losh foreach my $c (split(//, $lines[$line])) { 7853a3c9242SWarner Losh ##print "C<$c>L<$level><$open$close>O<$off>\n"; 7863a3c9242SWarner Losh if ($off > 0) { 7873a3c9242SWarner Losh $off--; 7883a3c9242SWarner Losh next; 7893a3c9242SWarner Losh } 7903a3c9242SWarner Losh 7913a3c9242SWarner Losh if ($c eq $close && $level > 0) { 7923a3c9242SWarner Losh $level--; 7933a3c9242SWarner Losh last if ($level == 0); 7943a3c9242SWarner Losh } elsif ($c eq $open) { 7953a3c9242SWarner Losh $level++; 7963a3c9242SWarner Losh } 7973a3c9242SWarner Losh } 7983a3c9242SWarner Losh 7993a3c9242SWarner Losh if (!$outer || $level <= 1) { 8003a3c9242SWarner Losh push(@res, $rawlines[$line]); 8013a3c9242SWarner Losh } 8023a3c9242SWarner Losh 8033a3c9242SWarner Losh last if ($level == 0); 8043a3c9242SWarner Losh } 8053a3c9242SWarner Losh 8063a3c9242SWarner Losh return ($level, @res); 8073a3c9242SWarner Losh} 8083a3c9242SWarner Loshsub ctx_block_outer { 8093a3c9242SWarner Losh my ($linenr, $remain) = @_; 8103a3c9242SWarner Losh 8113a3c9242SWarner Losh my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); 8123a3c9242SWarner Losh return @r; 8133a3c9242SWarner Losh} 8143a3c9242SWarner Loshsub ctx_block { 8153a3c9242SWarner Losh my ($linenr, $remain) = @_; 8163a3c9242SWarner Losh 8173a3c9242SWarner Losh my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); 8183a3c9242SWarner Losh return @r; 8193a3c9242SWarner Losh} 8203a3c9242SWarner Loshsub ctx_statement { 8213a3c9242SWarner Losh my ($linenr, $remain, $off) = @_; 8223a3c9242SWarner Losh 8233a3c9242SWarner Losh my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); 8243a3c9242SWarner Losh return @r; 8253a3c9242SWarner Losh} 8263a3c9242SWarner Loshsub ctx_block_level { 8273a3c9242SWarner Losh my ($linenr, $remain) = @_; 8283a3c9242SWarner Losh 8293a3c9242SWarner Losh return ctx_block_get($linenr, $remain, 0, '{', '}', 0); 8303a3c9242SWarner Losh} 8313a3c9242SWarner Loshsub ctx_statement_level { 8323a3c9242SWarner Losh my ($linenr, $remain, $off) = @_; 8333a3c9242SWarner Losh 8343a3c9242SWarner Losh return ctx_block_get($linenr, $remain, 0, '(', ')', $off); 8353a3c9242SWarner Losh} 8363a3c9242SWarner Losh 8373a3c9242SWarner Loshsub ctx_locate_comment { 8383a3c9242SWarner Losh my ($first_line, $end_line) = @_; 8393a3c9242SWarner Losh 8403a3c9242SWarner Losh # Catch a comment on the end of the line itself. 8413a3c9242SWarner Losh my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); 8423a3c9242SWarner Losh return $current_comment if (defined $current_comment); 8433a3c9242SWarner Losh 8443a3c9242SWarner Losh # Look through the context and try and figure out if there is a 8453a3c9242SWarner Losh # comment. 8463a3c9242SWarner Losh my $in_comment = 0; 8473a3c9242SWarner Losh $current_comment = ''; 8483a3c9242SWarner Losh for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { 8493a3c9242SWarner Losh my $line = $rawlines[$linenr - 1]; 8503a3c9242SWarner Losh #warn " $line\n"; 8513a3c9242SWarner Losh if ($linenr == $first_line and $line =~ m@^.\s*\*@) { 8523a3c9242SWarner Losh $in_comment = 1; 8533a3c9242SWarner Losh } 8543a3c9242SWarner Losh if ($line =~ m@/\*@) { 8553a3c9242SWarner Losh $in_comment = 1; 8563a3c9242SWarner Losh } 8573a3c9242SWarner Losh if (!$in_comment && $current_comment ne '') { 8583a3c9242SWarner Losh $current_comment = ''; 8593a3c9242SWarner Losh } 8603a3c9242SWarner Losh $current_comment .= $line . "\n" if ($in_comment); 8613a3c9242SWarner Losh if ($line =~ m@\*/@) { 8623a3c9242SWarner Losh $in_comment = 0; 8633a3c9242SWarner Losh } 8643a3c9242SWarner Losh } 8653a3c9242SWarner Losh 8663a3c9242SWarner Losh chomp($current_comment); 8673a3c9242SWarner Losh return($current_comment); 8683a3c9242SWarner Losh} 8693a3c9242SWarner Loshsub ctx_has_comment { 8703a3c9242SWarner Losh my ($first_line, $end_line) = @_; 8713a3c9242SWarner Losh my $cmt = ctx_locate_comment($first_line, $end_line); 8723a3c9242SWarner Losh 8733a3c9242SWarner Losh ##print "LINE: $rawlines[$end_line - 1 ]\n"; 8743a3c9242SWarner Losh ##print "CMMT: $cmt\n"; 8753a3c9242SWarner Losh 8763a3c9242SWarner Losh return ($cmt ne ''); 8773a3c9242SWarner Losh} 8783a3c9242SWarner Losh 8793a3c9242SWarner Loshsub raw_line { 8803a3c9242SWarner Losh my ($linenr, $cnt) = @_; 8813a3c9242SWarner Losh 8823a3c9242SWarner Losh my $offset = $linenr - 1; 8833a3c9242SWarner Losh $cnt++; 8843a3c9242SWarner Losh 8853a3c9242SWarner Losh my $line; 8863a3c9242SWarner Losh while ($cnt) { 8873a3c9242SWarner Losh $line = $rawlines[$offset++]; 8883a3c9242SWarner Losh next if (defined($line) && $line =~ /^-/); 8893a3c9242SWarner Losh $cnt--; 8903a3c9242SWarner Losh } 8913a3c9242SWarner Losh 8923a3c9242SWarner Losh return $line; 8933a3c9242SWarner Losh} 8943a3c9242SWarner Losh 8953a3c9242SWarner Loshsub cat_vet { 8963a3c9242SWarner Losh my ($vet) = @_; 8973a3c9242SWarner Losh my ($res, $coded); 8983a3c9242SWarner Losh 8993a3c9242SWarner Losh $res = ''; 9003a3c9242SWarner Losh while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { 9013a3c9242SWarner Losh $res .= $1; 9023a3c9242SWarner Losh if ($2 ne '') { 9033a3c9242SWarner Losh $coded = sprintf("^%c", unpack('C', $2) + 64); 9043a3c9242SWarner Losh $res .= $coded; 9053a3c9242SWarner Losh } 9063a3c9242SWarner Losh } 9073a3c9242SWarner Losh $res =~ s/$/\$/; 9083a3c9242SWarner Losh 9093a3c9242SWarner Losh return $res; 9103a3c9242SWarner Losh} 9113a3c9242SWarner Losh 9123a3c9242SWarner Loshmy $av_preprocessor = 0; 9133a3c9242SWarner Loshmy $av_pending; 9143a3c9242SWarner Loshmy @av_paren_type; 9153a3c9242SWarner Loshmy $av_pend_colon; 9163a3c9242SWarner Losh 9173a3c9242SWarner Loshsub annotate_reset { 9183a3c9242SWarner Losh $av_preprocessor = 0; 9193a3c9242SWarner Losh $av_pending = '_'; 9203a3c9242SWarner Losh @av_paren_type = ('E'); 9213a3c9242SWarner Losh $av_pend_colon = 'O'; 9223a3c9242SWarner Losh} 9233a3c9242SWarner Losh 9243a3c9242SWarner Loshsub annotate_values { 9253a3c9242SWarner Losh my ($stream, $type) = @_; 9263a3c9242SWarner Losh 9273a3c9242SWarner Losh my $res; 9283a3c9242SWarner Losh my $var = '_' x length($stream); 9293a3c9242SWarner Losh my $cur = $stream; 9303a3c9242SWarner Losh 9313a3c9242SWarner Losh print "$stream\n" if ($dbg_values > 1); 9323a3c9242SWarner Losh 9333a3c9242SWarner Losh while (length($cur)) { 9343a3c9242SWarner Losh @av_paren_type = ('E') if ($#av_paren_type < 0); 9353a3c9242SWarner Losh print " <" . join('', @av_paren_type) . 9363a3c9242SWarner Losh "> <$type> <$av_pending>" if ($dbg_values > 1); 9373a3c9242SWarner Losh if ($cur =~ /^(\s+)/o) { 9383a3c9242SWarner Losh print "WS($1)\n" if ($dbg_values > 1); 9393a3c9242SWarner Losh if ($1 =~ /\n/ && $av_preprocessor) { 9403a3c9242SWarner Losh $type = pop(@av_paren_type); 9413a3c9242SWarner Losh $av_preprocessor = 0; 9423a3c9242SWarner Losh } 9433a3c9242SWarner Losh 9443a3c9242SWarner Losh } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { 9453a3c9242SWarner Losh print "CAST($1)\n" if ($dbg_values > 1); 9463a3c9242SWarner Losh push(@av_paren_type, $type); 9473a3c9242SWarner Losh $type = 'C'; 9483a3c9242SWarner Losh 9493a3c9242SWarner Losh } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { 9503a3c9242SWarner Losh print "DECLARE($1)\n" if ($dbg_values > 1); 9513a3c9242SWarner Losh $type = 'T'; 9523a3c9242SWarner Losh 9533a3c9242SWarner Losh } elsif ($cur =~ /^($Modifier)\s*/) { 9543a3c9242SWarner Losh print "MODIFIER($1)\n" if ($dbg_values > 1); 9553a3c9242SWarner Losh $type = 'T'; 9563a3c9242SWarner Losh 9573a3c9242SWarner Losh } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { 9583a3c9242SWarner Losh print "DEFINE($1,$2)\n" if ($dbg_values > 1); 9593a3c9242SWarner Losh $av_preprocessor = 1; 9603a3c9242SWarner Losh push(@av_paren_type, $type); 9613a3c9242SWarner Losh if ($2 ne '') { 9623a3c9242SWarner Losh $av_pending = 'N'; 9633a3c9242SWarner Losh } 9643a3c9242SWarner Losh $type = 'E'; 9653a3c9242SWarner Losh 9663a3c9242SWarner Losh } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { 9673a3c9242SWarner Losh print "UNDEF($1)\n" if ($dbg_values > 1); 9683a3c9242SWarner Losh $av_preprocessor = 1; 9693a3c9242SWarner Losh push(@av_paren_type, $type); 9703a3c9242SWarner Losh 9713a3c9242SWarner Losh } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { 9723a3c9242SWarner Losh print "PRE_START($1)\n" if ($dbg_values > 1); 9733a3c9242SWarner Losh $av_preprocessor = 1; 9743a3c9242SWarner Losh 9753a3c9242SWarner Losh push(@av_paren_type, $type); 9763a3c9242SWarner Losh push(@av_paren_type, $type); 9773a3c9242SWarner Losh $type = 'E'; 9783a3c9242SWarner Losh 9793a3c9242SWarner Losh } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { 9803a3c9242SWarner Losh print "PRE_RESTART($1)\n" if ($dbg_values > 1); 9813a3c9242SWarner Losh $av_preprocessor = 1; 9823a3c9242SWarner Losh 9833a3c9242SWarner Losh push(@av_paren_type, $av_paren_type[$#av_paren_type]); 9843a3c9242SWarner Losh 9853a3c9242SWarner Losh $type = 'E'; 9863a3c9242SWarner Losh 9873a3c9242SWarner Losh } elsif ($cur =~ /^(\#\s*(?:endif))/o) { 9883a3c9242SWarner Losh print "PRE_END($1)\n" if ($dbg_values > 1); 9893a3c9242SWarner Losh 9903a3c9242SWarner Losh $av_preprocessor = 1; 9913a3c9242SWarner Losh 9923a3c9242SWarner Losh # Assume all arms of the conditional end as this 9933a3c9242SWarner Losh # one does, and continue as if the #endif was not here. 9943a3c9242SWarner Losh pop(@av_paren_type); 9953a3c9242SWarner Losh push(@av_paren_type, $type); 9963a3c9242SWarner Losh $type = 'E'; 9973a3c9242SWarner Losh 9983a3c9242SWarner Losh } elsif ($cur =~ /^(\\\n)/o) { 9993a3c9242SWarner Losh print "PRECONT($1)\n" if ($dbg_values > 1); 10003a3c9242SWarner Losh 10013a3c9242SWarner Losh } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { 10023a3c9242SWarner Losh print "ATTR($1)\n" if ($dbg_values > 1); 10033a3c9242SWarner Losh $av_pending = $type; 10043a3c9242SWarner Losh $type = 'N'; 10053a3c9242SWarner Losh 10063a3c9242SWarner Losh } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { 10073a3c9242SWarner Losh print "SIZEOF($1)\n" if ($dbg_values > 1); 10083a3c9242SWarner Losh if (defined $2) { 10093a3c9242SWarner Losh $av_pending = 'V'; 10103a3c9242SWarner Losh } 10113a3c9242SWarner Losh $type = 'N'; 10123a3c9242SWarner Losh 10133a3c9242SWarner Losh } elsif ($cur =~ /^(if|while|for)\b/o) { 10143a3c9242SWarner Losh print "COND($1)\n" if ($dbg_values > 1); 10153a3c9242SWarner Losh $av_pending = 'E'; 10163a3c9242SWarner Losh $type = 'N'; 10173a3c9242SWarner Losh 10183a3c9242SWarner Losh } elsif ($cur =~/^(case)/o) { 10193a3c9242SWarner Losh print "CASE($1)\n" if ($dbg_values > 1); 10203a3c9242SWarner Losh $av_pend_colon = 'C'; 10213a3c9242SWarner Losh $type = 'N'; 10223a3c9242SWarner Losh 10233a3c9242SWarner Losh } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { 10243a3c9242SWarner Losh print "KEYWORD($1)\n" if ($dbg_values > 1); 10253a3c9242SWarner Losh $type = 'N'; 10263a3c9242SWarner Losh 10273a3c9242SWarner Losh } elsif ($cur =~ /^(\()/o) { 10283a3c9242SWarner Losh print "PAREN('$1')\n" if ($dbg_values > 1); 10293a3c9242SWarner Losh push(@av_paren_type, $av_pending); 10303a3c9242SWarner Losh $av_pending = '_'; 10313a3c9242SWarner Losh $type = 'N'; 10323a3c9242SWarner Losh 10333a3c9242SWarner Losh } elsif ($cur =~ /^(\))/o) { 10343a3c9242SWarner Losh my $new_type = pop(@av_paren_type); 10353a3c9242SWarner Losh if ($new_type ne '_') { 10363a3c9242SWarner Losh $type = $new_type; 10373a3c9242SWarner Losh print "PAREN('$1') -> $type\n" 10383a3c9242SWarner Losh if ($dbg_values > 1); 10393a3c9242SWarner Losh } else { 10403a3c9242SWarner Losh print "PAREN('$1')\n" if ($dbg_values > 1); 10413a3c9242SWarner Losh } 10423a3c9242SWarner Losh 10433a3c9242SWarner Losh } elsif ($cur =~ /^($Ident)\s*\(/o) { 10443a3c9242SWarner Losh print "FUNC($1)\n" if ($dbg_values > 1); 10453a3c9242SWarner Losh $type = 'V'; 10463a3c9242SWarner Losh $av_pending = 'V'; 10473a3c9242SWarner Losh 10483a3c9242SWarner Losh } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { 10493a3c9242SWarner Losh if (defined $2 && $type eq 'C' || $type eq 'T') { 10503a3c9242SWarner Losh $av_pend_colon = 'B'; 10513a3c9242SWarner Losh } elsif ($type eq 'E') { 10523a3c9242SWarner Losh $av_pend_colon = 'L'; 10533a3c9242SWarner Losh } 10543a3c9242SWarner Losh print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); 10553a3c9242SWarner Losh $type = 'V'; 10563a3c9242SWarner Losh 10573a3c9242SWarner Losh } elsif ($cur =~ /^($Ident|$Constant)/o) { 10583a3c9242SWarner Losh print "IDENT($1)\n" if ($dbg_values > 1); 10593a3c9242SWarner Losh $type = 'V'; 10603a3c9242SWarner Losh 10613a3c9242SWarner Losh } elsif ($cur =~ /^($Assignment)/o) { 10623a3c9242SWarner Losh print "ASSIGN($1)\n" if ($dbg_values > 1); 10633a3c9242SWarner Losh $type = 'N'; 10643a3c9242SWarner Losh 10653a3c9242SWarner Losh } elsif ($cur =~/^(;|{|})/) { 10663a3c9242SWarner Losh print "END($1)\n" if ($dbg_values > 1); 10673a3c9242SWarner Losh $type = 'E'; 10683a3c9242SWarner Losh $av_pend_colon = 'O'; 10693a3c9242SWarner Losh 10703a3c9242SWarner Losh } elsif ($cur =~/^(,)/) { 10713a3c9242SWarner Losh print "COMMA($1)\n" if ($dbg_values > 1); 10723a3c9242SWarner Losh $type = 'C'; 10733a3c9242SWarner Losh 10743a3c9242SWarner Losh } elsif ($cur =~ /^(\?)/o) { 10753a3c9242SWarner Losh print "QUESTION($1)\n" if ($dbg_values > 1); 10763a3c9242SWarner Losh $type = 'N'; 10773a3c9242SWarner Losh 10783a3c9242SWarner Losh } elsif ($cur =~ /^(:)/o) { 10793a3c9242SWarner Losh print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); 10803a3c9242SWarner Losh 10813a3c9242SWarner Losh substr($var, length($res), 1, $av_pend_colon); 10823a3c9242SWarner Losh if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { 10833a3c9242SWarner Losh $type = 'E'; 10843a3c9242SWarner Losh } else { 10853a3c9242SWarner Losh $type = 'N'; 10863a3c9242SWarner Losh } 10873a3c9242SWarner Losh $av_pend_colon = 'O'; 10883a3c9242SWarner Losh 10893a3c9242SWarner Losh } elsif ($cur =~ /^(\[)/o) { 10903a3c9242SWarner Losh print "CLOSE($1)\n" if ($dbg_values > 1); 10913a3c9242SWarner Losh $type = 'N'; 10923a3c9242SWarner Losh 10933a3c9242SWarner Losh } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { 10943a3c9242SWarner Losh my $variant; 10953a3c9242SWarner Losh 10963a3c9242SWarner Losh print "OPV($1)\n" if ($dbg_values > 1); 10973a3c9242SWarner Losh if ($type eq 'V') { 10983a3c9242SWarner Losh $variant = 'B'; 10993a3c9242SWarner Losh } else { 11003a3c9242SWarner Losh $variant = 'U'; 11013a3c9242SWarner Losh } 11023a3c9242SWarner Losh 11033a3c9242SWarner Losh substr($var, length($res), 1, $variant); 11043a3c9242SWarner Losh $type = 'N'; 11053a3c9242SWarner Losh 11063a3c9242SWarner Losh } elsif ($cur =~ /^($Operators)/o) { 11073a3c9242SWarner Losh print "OP($1)\n" if ($dbg_values > 1); 11083a3c9242SWarner Losh if ($1 ne '++' && $1 ne '--') { 11093a3c9242SWarner Losh $type = 'N'; 11103a3c9242SWarner Losh } 11113a3c9242SWarner Losh 11123a3c9242SWarner Losh } elsif ($cur =~ /(^.)/o) { 11133a3c9242SWarner Losh print "C($1)\n" if ($dbg_values > 1); 11143a3c9242SWarner Losh } 11153a3c9242SWarner Losh if (defined $1) { 11163a3c9242SWarner Losh $cur = substr($cur, length($1)); 11173a3c9242SWarner Losh $res .= $type x length($1); 11183a3c9242SWarner Losh } 11193a3c9242SWarner Losh } 11203a3c9242SWarner Losh 11213a3c9242SWarner Losh return ($res, $var); 11223a3c9242SWarner Losh} 11233a3c9242SWarner Losh 11243a3c9242SWarner Loshsub possible { 11253a3c9242SWarner Losh my ($possible, $line) = @_; 11263a3c9242SWarner Losh my $notPermitted = qr{(?: 11273a3c9242SWarner Losh ^(?: 11283a3c9242SWarner Losh $Modifier| 11293a3c9242SWarner Losh $Storage| 11303a3c9242SWarner Losh $Type| 11313a3c9242SWarner Losh DEFINE_\S+ 11323a3c9242SWarner Losh )$| 11333a3c9242SWarner Losh ^(?: 11343a3c9242SWarner Losh goto| 11353a3c9242SWarner Losh return| 11363a3c9242SWarner Losh case| 11373a3c9242SWarner Losh else| 11383a3c9242SWarner Losh asm|__asm__| 11393a3c9242SWarner Losh do 11403a3c9242SWarner Losh )(?:\s|$)| 11413a3c9242SWarner Losh ^(?:typedef|struct|enum)\b| 11423a3c9242SWarner Losh ^\# 11433a3c9242SWarner Losh )}x; 11443a3c9242SWarner Losh warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); 11453a3c9242SWarner Losh if ($possible !~ $notPermitted) { 11463a3c9242SWarner Losh # Check for modifiers. 11473a3c9242SWarner Losh $possible =~ s/\s*$Storage\s*//g; 11483a3c9242SWarner Losh $possible =~ s/\s*$Sparse\s*//g; 11493a3c9242SWarner Losh if ($possible =~ /^\s*$/) { 11503a3c9242SWarner Losh 11513a3c9242SWarner Losh } elsif ($possible =~ /\s/) { 11523a3c9242SWarner Losh $possible =~ s/\s*(?:$Type|\#\#)\s*//g; 11533a3c9242SWarner Losh for my $modifier (split(' ', $possible)) { 11543a3c9242SWarner Losh if ($modifier !~ $notPermitted) { 11553a3c9242SWarner Losh warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); 11563a3c9242SWarner Losh push(@modifierList, $modifier); 11573a3c9242SWarner Losh } 11583a3c9242SWarner Losh } 11593a3c9242SWarner Losh 11603a3c9242SWarner Losh } else { 11613a3c9242SWarner Losh warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); 11623a3c9242SWarner Losh push(@typeList, $possible); 11633a3c9242SWarner Losh } 11643a3c9242SWarner Losh build_types(); 11653a3c9242SWarner Losh } else { 11663a3c9242SWarner Losh warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); 11673a3c9242SWarner Losh } 11683a3c9242SWarner Losh} 11693a3c9242SWarner Losh 11703a3c9242SWarner Loshmy $prefix = ''; 11713a3c9242SWarner Losh 11723a3c9242SWarner Loshsub report { 11733a3c9242SWarner Losh my ($level, $msg) = @_; 11743a3c9242SWarner Losh if (defined $tst_only && $msg !~ /\Q$tst_only\E/) { 11753a3c9242SWarner Losh return 0; 11763a3c9242SWarner Losh } 11773a3c9242SWarner Losh 11783a3c9242SWarner Losh my $output = ''; 1179c2f5306cSWarner Losh my $do_color = $color && !$github; 1180c2f5306cSWarner Losh $output .= BOLD if $do_color; 118122d12caaSWarner Losh $output .= "::error " if $github && $level eq 'ERROR'; 118222d12caaSWarner Losh $output .= "::warning " if $github && $level eq 'WARNING'; 11833a3c9242SWarner Losh $output .= $prefix; 1184c2f5306cSWarner Losh $output .= RED if $do_color && $level eq 'ERROR'; 1185c2f5306cSWarner Losh $output .= MAGENTA if $do_color && $level eq 'WARNING'; 1186c2f5306cSWarner Losh $output .= $level . ':' if !$github; 1187c2f5306cSWarner Losh $output .= RESET if $do_color; 1188ac9abe93SWarner Losh $output .= ' ' if (!$github); 1189ac9abe93SWarner Losh $output .= $msg . "\n"; 11903a3c9242SWarner Losh 11913a3c9242SWarner Losh $output = (split('\n', $output))[0] . "\n" if ($terse); 11923a3c9242SWarner Losh 11933a3c9242SWarner Losh push(our @report, $output); 11943a3c9242SWarner Losh 11953a3c9242SWarner Losh return 1; 11963a3c9242SWarner Losh} 11973a3c9242SWarner Loshsub report_dump { 11983a3c9242SWarner Losh our @report; 11993a3c9242SWarner Losh} 12003a3c9242SWarner Loshsub ERROR { 12013a3c9242SWarner Losh if (report("ERROR", $_[0])) { 12023a3c9242SWarner Losh our $clean = 0; 12033a3c9242SWarner Losh our $cnt_error++; 12043a3c9242SWarner Losh } 12053a3c9242SWarner Losh} 12063a3c9242SWarner Loshsub WARN { 12073a3c9242SWarner Losh if (report("WARNING", $_[0])) { 12083a3c9242SWarner Losh our $clean = 0; 12093a3c9242SWarner Losh our $cnt_warn++; 12103a3c9242SWarner Losh } 12113a3c9242SWarner Losh} 12123a3c9242SWarner Losh 12133a3c9242SWarner Losh# According to tests/qtest/bios-tables-test.c: do not 12143a3c9242SWarner Losh# change expected file in the same commit with adding test 12153a3c9242SWarner Loshsub checkfilename { 12163a3c9242SWarner Losh my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_; 12173a3c9242SWarner Losh 12183a3c9242SWarner Losh # Note: shell script that rebuilds the expected files is in the same 12193a3c9242SWarner Losh # directory as files themselves. 12203a3c9242SWarner Losh # Note: allowed diff list can be changed both when changing expected 12213a3c9242SWarner Losh # files and when changing tests. 12223a3c9242SWarner Losh if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) { 12233a3c9242SWarner Losh $$acpi_testexpected = $name; 12243a3c9242SWarner Losh } elsif ($name !~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { 12253a3c9242SWarner Losh $$acpi_nontestexpected = $name; 12263a3c9242SWarner Losh } 12273a3c9242SWarner Losh if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) { 12283a3c9242SWarner Losh ERROR("Do not add expected files together with tests, " . 12293a3c9242SWarner Losh "follow instructions in " . 12303a3c9242SWarner Losh "tests/qtest/bios-tables-test.c: both " . 12313a3c9242SWarner Losh $$acpi_testexpected . " and " . 12323a3c9242SWarner Losh $$acpi_nontestexpected . " found\n"); 12333a3c9242SWarner Losh } 12343a3c9242SWarner Losh} 12353a3c9242SWarner Losh 12363a3c9242SWarner Loshsub process { 12373a3c9242SWarner Losh my $filename = shift; 12383a3c9242SWarner Losh 12393a3c9242SWarner Losh my $linenr=0; 12403a3c9242SWarner Losh my $prevline=""; 12413a3c9242SWarner Losh my $prevrawline=""; 12423a3c9242SWarner Losh my $stashline=""; 12433a3c9242SWarner Losh my $stashrawline=""; 12443a3c9242SWarner Losh 12453a3c9242SWarner Losh my $length; 12463a3c9242SWarner Losh my $indent; 12473a3c9242SWarner Losh my $previndent=0; 12483a3c9242SWarner Losh my $stashindent=0; 12493a3c9242SWarner Losh 12503a3c9242SWarner Losh our $clean = 1; 12513a3c9242SWarner Losh my $signoff = 0; 12523a3c9242SWarner Losh my $is_patch = 0; 12533a3c9242SWarner Losh 12543a3c9242SWarner Losh my $in_header_lines = $file ? 0 : 1; 12553a3c9242SWarner Losh my $in_commit_log = 0; #Scanning lines before patch 12563a3c9242SWarner Losh my $non_utf8_charset = 0; 12573a3c9242SWarner Losh 12583a3c9242SWarner Losh our @report = (); 12593a3c9242SWarner Losh our $cnt_lines = 0; 12603a3c9242SWarner Losh our $cnt_error = 0; 12613a3c9242SWarner Losh our $cnt_warn = 0; 12623a3c9242SWarner Losh our $cnt_chk = 0; 12633a3c9242SWarner Losh 12643a3c9242SWarner Losh # Trace the real file/line as we go. 12653a3c9242SWarner Losh my $realfile = ''; 12663a3c9242SWarner Losh my $realline = 0; 12673a3c9242SWarner Losh my $realcnt = 0; 12683a3c9242SWarner Losh my $here = ''; 12693a3c9242SWarner Losh my $in_comment = 0; 12703a3c9242SWarner Losh my $comment_edge = 0; 12713a3c9242SWarner Losh my $first_line = 0; 12723a3c9242SWarner Losh my $p1_prefix = ''; 12733a3c9242SWarner Losh 12743a3c9242SWarner Losh my $prev_values = 'E'; 12753a3c9242SWarner Losh 12763a3c9242SWarner Losh # suppression flags 12773a3c9242SWarner Losh my %suppress_ifbraces; 12783a3c9242SWarner Losh my %suppress_whiletrailers; 12793a3c9242SWarner Losh my %suppress_export; 12803a3c9242SWarner Losh 12813a3c9242SWarner Losh my $acpi_testexpected; 12823a3c9242SWarner Losh my $acpi_nontestexpected; 12833a3c9242SWarner Losh 12843a3c9242SWarner Losh # Pre-scan the patch sanitizing the lines. 12853a3c9242SWarner Losh 12863a3c9242SWarner Losh sanitise_line_reset(); 12873a3c9242SWarner Losh my $line; 12883a3c9242SWarner Losh foreach my $rawline (@rawlines) { 12893a3c9242SWarner Losh $linenr++; 12903a3c9242SWarner Losh $line = $rawline; 12913a3c9242SWarner Losh 12923a3c9242SWarner Losh if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { 12933a3c9242SWarner Losh $realline=$1-1; 12943a3c9242SWarner Losh if (defined $2) { 12953a3c9242SWarner Losh $realcnt=$3+1; 12963a3c9242SWarner Losh } else { 12973a3c9242SWarner Losh $realcnt=1+1; 12983a3c9242SWarner Losh } 12993a3c9242SWarner Losh $in_comment = 0; 13003a3c9242SWarner Losh 13013a3c9242SWarner Losh # Guestimate if this is a continuing comment. Run 13023a3c9242SWarner Losh # the context looking for a comment "edge". If this 13033a3c9242SWarner Losh # edge is a close comment then we must be in a comment 13043a3c9242SWarner Losh # at context start. 13053a3c9242SWarner Losh my $edge; 13063a3c9242SWarner Losh my $cnt = $realcnt; 13073a3c9242SWarner Losh for (my $ln = $linenr + 1; $cnt > 0; $ln++) { 13083a3c9242SWarner Losh next if (defined $rawlines[$ln - 1] && 13093a3c9242SWarner Losh $rawlines[$ln - 1] =~ /^-/); 13103a3c9242SWarner Losh $cnt--; 13113a3c9242SWarner Losh #print "RAW<$rawlines[$ln - 1]>\n"; 13123a3c9242SWarner Losh last if (!defined $rawlines[$ln - 1]); 13133a3c9242SWarner Losh if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && 13143a3c9242SWarner Losh $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { 13153a3c9242SWarner Losh ($edge) = $1; 13163a3c9242SWarner Losh last; 13173a3c9242SWarner Losh } 13183a3c9242SWarner Losh } 13193a3c9242SWarner Losh if (defined $edge && $edge eq '*/') { 13203a3c9242SWarner Losh $in_comment = 1; 13213a3c9242SWarner Losh } 13223a3c9242SWarner Losh 13233a3c9242SWarner Losh # Guestimate if this is a continuing comment. If this 13243a3c9242SWarner Losh # is the start of a diff block and this line starts 13253a3c9242SWarner Losh # ' *' then it is very likely a comment. 13263a3c9242SWarner Losh if (!defined $edge && 13273a3c9242SWarner Losh $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) 13283a3c9242SWarner Losh { 13293a3c9242SWarner Losh $in_comment = 1; 13303a3c9242SWarner Losh } 13313a3c9242SWarner Losh 13323a3c9242SWarner Losh ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; 13333a3c9242SWarner Losh sanitise_line_reset($in_comment); 13343a3c9242SWarner Losh 13353a3c9242SWarner Losh } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { 13363a3c9242SWarner Losh # Standardise the strings and chars within the input to 13373a3c9242SWarner Losh # simplify matching -- only bother with positive lines. 13383a3c9242SWarner Losh $line = sanitise_line($rawline); 13393a3c9242SWarner Losh } 13403a3c9242SWarner Losh push(@lines, $line); 13413a3c9242SWarner Losh 13423a3c9242SWarner Losh if ($realcnt > 1) { 13433a3c9242SWarner Losh $realcnt-- if ($line =~ /^(?:\+| |$)/); 13443a3c9242SWarner Losh } else { 13453a3c9242SWarner Losh $realcnt = 0; 13463a3c9242SWarner Losh } 13473a3c9242SWarner Losh 13483a3c9242SWarner Losh #print "==>$rawline\n"; 13493a3c9242SWarner Losh #print "-->$line\n"; 13503a3c9242SWarner Losh } 13513a3c9242SWarner Losh 13523a3c9242SWarner Losh $prefix = ''; 13533a3c9242SWarner Losh 13543a3c9242SWarner Losh $realcnt = 0; 13553a3c9242SWarner Losh $linenr = 0; 13563a3c9242SWarner Losh foreach my $line (@lines) { 13573a3c9242SWarner Losh $linenr++; 13583a3c9242SWarner Losh 13593a3c9242SWarner Losh my $rawline = $rawlines[$linenr - 1]; 13603a3c9242SWarner Losh 13613a3c9242SWarner Losh#extract the line range in the file after the patch is applied 13623a3c9242SWarner Losh if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { 13633a3c9242SWarner Losh $is_patch = 1; 13643a3c9242SWarner Losh $first_line = $linenr + 1; 13653a3c9242SWarner Losh $realline=$1-1; 13663a3c9242SWarner Losh if (defined $2) { 13673a3c9242SWarner Losh $realcnt=$3+1; 13683a3c9242SWarner Losh } else { 13693a3c9242SWarner Losh $realcnt=1+1; 13703a3c9242SWarner Losh } 13713a3c9242SWarner Losh annotate_reset(); 13723a3c9242SWarner Losh $prev_values = 'E'; 13733a3c9242SWarner Losh 13743a3c9242SWarner Losh %suppress_ifbraces = (); 13753a3c9242SWarner Losh %suppress_whiletrailers = (); 13763a3c9242SWarner Losh %suppress_export = (); 13773a3c9242SWarner Losh next; 13783a3c9242SWarner Losh 13793a3c9242SWarner Losh# track the line number as we move through the hunk, note that 13803a3c9242SWarner Losh# new versions of GNU diff omit the leading space on completely 13813a3c9242SWarner Losh# blank context lines so we need to count that too. 13823a3c9242SWarner Losh } elsif ($line =~ /^( |\+|$)/) { 13833a3c9242SWarner Losh $realline++; 13843a3c9242SWarner Losh $realcnt-- if ($realcnt != 0); 13853a3c9242SWarner Losh 13863a3c9242SWarner Losh # Measure the line length and indent. 13873a3c9242SWarner Losh ($length, $indent) = line_stats($rawline); 13883a3c9242SWarner Losh 13893a3c9242SWarner Losh # Track the previous line. 13903a3c9242SWarner Losh ($prevline, $stashline) = ($stashline, $line); 13913a3c9242SWarner Losh ($previndent, $stashindent) = ($stashindent, $indent); 13923a3c9242SWarner Losh ($prevrawline, $stashrawline) = ($stashrawline, $rawline); 13933a3c9242SWarner Losh 13943a3c9242SWarner Losh #warn "line<$line>\n"; 13953a3c9242SWarner Losh 13963a3c9242SWarner Losh } elsif ($realcnt == 1) { 13973a3c9242SWarner Losh $realcnt--; 13983a3c9242SWarner Losh } 13993a3c9242SWarner Losh 14003a3c9242SWarner Losh my $hunk_line = ($realcnt != 0); 14013a3c9242SWarner Losh 14023a3c9242SWarner Losh#make up the handle for any error we report on this line 14033a3c9242SWarner Losh $prefix = "$filename:$realline: " if ($emacs && $file); 14043a3c9242SWarner Losh $prefix = "$filename:$linenr: " if ($emacs && !$file); 140522d12caaSWarner Losh $prefix = "file=$filename,line=$realline:\:" if ($github && $file); 140622d12caaSWarner Losh $prefix = "file=$realfile,line=$realline:\:" if ($github && !$file); 14073a3c9242SWarner Losh 14083a3c9242SWarner Losh $here = "#$linenr: " if (!$file); 14093a3c9242SWarner Losh $here = "#$realline: " if ($file); 14103a3c9242SWarner Losh 14113a3c9242SWarner Losh # extract the filename as it passes 14123a3c9242SWarner Losh if ($line =~ /^diff --git.*?(\S+)$/) { 14133a3c9242SWarner Losh $realfile = $1; 14143a3c9242SWarner Losh $realfile =~ s@^([^/]*)/@@ if (!$file); 14153a3c9242SWarner Losh checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); 14163a3c9242SWarner Losh } elsif ($line =~ /^\+\+\+\s+(\S+)/) { 14173a3c9242SWarner Losh $realfile = $1; 14183a3c9242SWarner Losh $realfile =~ s@^([^/]*)/@@ if (!$file); 14193a3c9242SWarner Losh checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); 14203a3c9242SWarner Losh 14213a3c9242SWarner Losh $p1_prefix = $1; 14224748db6fSWarner Losh if (!$file && $tree && $p1_prefix ne '' && defined $root && 14233a3c9242SWarner Losh -e "$root/$p1_prefix") { 14243a3c9242SWarner Losh WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); 14253a3c9242SWarner Losh } 14263a3c9242SWarner Losh 14273a3c9242SWarner Losh next; 14283a3c9242SWarner Losh } 14293a3c9242SWarner Losh 14303a3c9242SWarner Losh $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); 14313a3c9242SWarner Losh 14323a3c9242SWarner Losh my $hereline = "$here\n$rawline\n"; 14333a3c9242SWarner Losh my $herecurr = "$here\n$rawline\n"; 14343a3c9242SWarner Losh my $hereprev = "$here\n$prevrawline\n$rawline\n"; 14353a3c9242SWarner Losh 14363a3c9242SWarner Losh $cnt_lines++ if ($realcnt != 0); 14373a3c9242SWarner Losh 14383a3c9242SWarner Losh# Check for incorrect file permissions 14393a3c9242SWarner Losh if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { 14403a3c9242SWarner Losh my $permhere = $here . "FILE: $realfile\n"; 1441*0207010fSWarner Losh if ($realfile =~ /(\bMakefile(?:\.objs)?|\.c|\.cc|\.cpp|\.h|\.hpp|\.mak|\.[sS])$/) { 14423a3c9242SWarner Losh ERROR("do not set execute permissions for source files\n" . $permhere); 14433a3c9242SWarner Losh } 14443a3c9242SWarner Losh } 14453a3c9242SWarner Losh 14463a3c9242SWarner Losh# Accept git diff extended headers as valid patches 14473a3c9242SWarner Losh if ($line =~ /^(?:rename|copy) (?:from|to) [\w\/\.\-]+\s*$/) { 14483a3c9242SWarner Losh $is_patch = 1; 14493a3c9242SWarner Losh } 14503a3c9242SWarner Losh 14513a3c9242SWarner Losh# Check for wrappage within a valid hunk of the file 14523a3c9242SWarner Losh if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { 14533a3c9242SWarner Losh ERROR("patch seems to be corrupt (line wrapped?)\n" . 14543a3c9242SWarner Losh $herecurr) if (!$emitted_corrupt++); 14553a3c9242SWarner Losh } 14563a3c9242SWarner Losh 14573a3c9242SWarner Losh# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php 14583a3c9242SWarner Losh if (($realfile =~ /^$/ || $line =~ /^\+/) && 14593a3c9242SWarner Losh $rawline !~ m/^$UTF8*$/) { 14603a3c9242SWarner Losh my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); 14613a3c9242SWarner Losh 14623a3c9242SWarner Losh my $blank = copy_spacing($rawline); 14633a3c9242SWarner Losh my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; 14643a3c9242SWarner Losh my $hereptr = "$hereline$ptr\n"; 14653a3c9242SWarner Losh 14663a3c9242SWarner Losh ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); 14673a3c9242SWarner Losh } 14683a3c9242SWarner Losh 14693a3c9242SWarner Losh if ($rawline =~ m/$UTF8_MOJIBAKE/) { 14703a3c9242SWarner Losh ERROR("Doubly-encoded UTF-8\n" . $herecurr); 14713a3c9242SWarner Losh } 14723a3c9242SWarner Losh# Check if it's the start of a commit log 14733a3c9242SWarner Losh# (not a header line and we haven't seen the patch filename) 14743a3c9242SWarner Losh if ($in_header_lines && $realfile =~ /^$/ && 14753a3c9242SWarner Losh !($rawline =~ /^\s+\S/ || 14763a3c9242SWarner Losh $rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) { 14773a3c9242SWarner Losh $in_header_lines = 0; 14783a3c9242SWarner Losh $in_commit_log = 1; 14793a3c9242SWarner Losh } 14803a3c9242SWarner Losh 14813a3c9242SWarner Losh# Check if there is UTF-8 in a commit log when a mail header has explicitly 14823a3c9242SWarner Losh# declined it, i.e defined some charset where it is missing. 14833a3c9242SWarner Losh if ($in_header_lines && 14843a3c9242SWarner Losh $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && 14853a3c9242SWarner Losh $1 !~ /utf-8/i) { 14863a3c9242SWarner Losh $non_utf8_charset = 1; 14873a3c9242SWarner Losh } 14883a3c9242SWarner Losh 14893a3c9242SWarner Losh if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && 14903a3c9242SWarner Losh $rawline =~ /$NON_ASCII_UTF8/) { 14913a3c9242SWarner Losh WARN("8-bit UTF-8 used in possible commit log\n" . $herecurr); 14923a3c9242SWarner Losh } 14933a3c9242SWarner Losh 14943a3c9242SWarner Losh# ignore non-hunk lines and lines being removed 14953a3c9242SWarner Losh next if (!$hunk_line || $line =~ /^-/); 14963a3c9242SWarner Losh 14973a3c9242SWarner Losh#trailing whitespace 14983a3c9242SWarner Losh if ($line =~ /^\+.*\015/) { 14993a3c9242SWarner Losh my $herevet = "$here\n" . cat_vet($rawline) . "\n"; 15003a3c9242SWarner Losh ERROR("DOS line endings\n" . $herevet); 15013a3c9242SWarner Losh 15023a3c9242SWarner Losh } elsif ($realfile =~ /^docs\/.+\.txt/ || 15033a3c9242SWarner Losh $realfile =~ /^docs\/.+\.md/) { 15043a3c9242SWarner Losh if ($rawline =~ /^\+\s+$/ && $rawline !~ /^\+ {4}$/) { 15053a3c9242SWarner Losh # TODO: properly check we're in a code block 15063a3c9242SWarner Losh # (surrounding text is 4-column aligned) 15073a3c9242SWarner Losh my $herevet = "$here\n" . cat_vet($rawline) . "\n"; 15083a3c9242SWarner Losh ERROR("code blocks in documentation should have " . 15093a3c9242SWarner Losh "empty lines with exactly 4 columns of " . 15103a3c9242SWarner Losh "whitespace\n" . $herevet); 15113a3c9242SWarner Losh } 15123a3c9242SWarner Losh } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { 15133a3c9242SWarner Losh my $herevet = "$here\n" . cat_vet($rawline) . "\n"; 15143a3c9242SWarner Losh ERROR("trailing whitespace\n" . $herevet); 15153a3c9242SWarner Losh $rpt_cleaners = 1; 15163a3c9242SWarner Losh } 15173a3c9242SWarner Losh 15183a3c9242SWarner Losh# check we are in a valid source file if not then ignore this hunk 15193a3c9242SWarner Losh next if ($realfile !~ /$SrcFile/); 15203a3c9242SWarner Losh 15213a3c9242SWarner Losh#120 column limit; exempt URLs, if no other words on line 15223a3c9242SWarner Losh if ($line =~ /^\+/ && 15233a3c9242SWarner Losh !($line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && 15243a3c9242SWarner Losh !($rawline =~ /^[^[:alnum:]]*https?:\S*$/) && 15253a3c9242SWarner Losh $length > 80 && 15263a3c9242SWarner Losh $realfile !~ /\/tests\//) 15273a3c9242SWarner Losh { 15283a3c9242SWarner Losh if ($length > 120) { 15293a3c9242SWarner Losh ERROR("line over 120 characters\n" . $herecurr); 15303a3c9242SWarner Losh } else { 15313a3c9242SWarner Losh WARN("line over 80 characters\n" . $herecurr); 15323a3c9242SWarner Losh } 15333a3c9242SWarner Losh } 15343a3c9242SWarner Losh 15353a3c9242SWarner Losh# check for spaces before a quoted newline 15363a3c9242SWarner Losh if ($rawline =~ /^.*\".*\s\\n/) { 15373a3c9242SWarner Losh ERROR("unnecessary whitespace before a quoted newline\n" . $herecurr); 15383a3c9242SWarner Losh } 15393a3c9242SWarner Losh 15403a3c9242SWarner Losh# check for adding lines without a newline. 15413a3c9242SWarner Losh if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { 15423a3c9242SWarner Losh ERROR("adding a line without newline at end of file\n" . $herecurr); 15433a3c9242SWarner Losh } 15443a3c9242SWarner Losh 15453a3c9242SWarner Losh# check for RCS/CVS revision markers 15461e817245SWarner Losh if ($rawline =~ /^\+.*\$(FreeBSD|Revision|Log|Id)(?:\$|\b)/) { 15473a3c9242SWarner Losh ERROR("CVS style keyword markers, these will _not_ be updated\n". $herecurr); 15483a3c9242SWarner Losh } 15493a3c9242SWarner Losh 15503a3c9242SWarner Losh# check we are in a valid C source file if not then ignore this hunk 1551*0207010fSWarner Losh next if ($realfile !~ /\.(h|hpp|c|cpp|cc|hh)$/); 15523a3c9242SWarner Losh 15533a3c9242SWarner Losh# Block comment styles 15543a3c9242SWarner Losh 15553a3c9242SWarner Losh # Block comments use /* on a line of its own 15563a3c9242SWarner Losh if ($rawline !~ m@^\+.*/\*.*\*/[ \t)}]*$@ && #inline /*...*/ 15573a3c9242SWarner Losh $rawline =~ m@^\+.*/\*[*-]?+[ \t]*[^ \t]@) { # /* or /** or /*- non-blank 15583a3c9242SWarner Losh WARN("Block comments use a leading /* on a separate line\n" . $herecurr); 15593a3c9242SWarner Losh } 15603a3c9242SWarner Losh 15613a3c9242SWarner Losh# Block comments use * on subsequent lines 15623a3c9242SWarner Losh if ($prevline =~ /$;[ \t]*$/ && #ends in comment 15633a3c9242SWarner Losh $prevrawline =~ /^\+.*?\/\*/ && #starting /* 15643a3c9242SWarner Losh $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ 15653a3c9242SWarner Losh $rawline =~ /^\+/ && #line is new 15663a3c9242SWarner Losh $rawline !~ /^\+[ \t]*\*/) { #no leading * 15673a3c9242SWarner Losh WARN("Block comments use * on subsequent lines\n" . $hereprev); 15683a3c9242SWarner Losh } 15693a3c9242SWarner Losh 15703a3c9242SWarner Losh# Block comments use */ on trailing lines 15713a3c9242SWarner Losh if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ 15723a3c9242SWarner Losh $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ 15733a3c9242SWarner Losh $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ 15743a3c9242SWarner Losh $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ 15753a3c9242SWarner Losh WARN("Block comments use a trailing */ on a separate line\n" . $herecurr); 15763a3c9242SWarner Losh } 15773a3c9242SWarner Losh 15783a3c9242SWarner Losh# Block comment * alignment 15793a3c9242SWarner Losh if ($prevline =~ /$;[ \t]*$/ && #ends in comment 15803a3c9242SWarner Losh $line =~ /^\+[ \t]*$;/ && #leading comment 15813a3c9242SWarner Losh $rawline =~ /^\+[ \t]*\*/ && #leading * 15823a3c9242SWarner Losh (($prevrawline =~ /^\+.*?\/\*/ && #leading /* 15833a3c9242SWarner Losh $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ 15843a3c9242SWarner Losh $prevrawline =~ /^\+[ \t]*\*/)) { #leading * 15853a3c9242SWarner Losh my $oldindent; 15863a3c9242SWarner Losh $prevrawline =~ m@^\+([ \t]*/?)\*@; 15873a3c9242SWarner Losh if (defined($1)) { 15883a3c9242SWarner Losh $oldindent = expand_tabs($1); 15893a3c9242SWarner Losh } else { 15903a3c9242SWarner Losh $prevrawline =~ m@^\+(.*/?)\*@; 15913a3c9242SWarner Losh $oldindent = expand_tabs($1); 15923a3c9242SWarner Losh } 15933a3c9242SWarner Losh $rawline =~ m@^\+([ \t]*)\*@; 15943a3c9242SWarner Losh my $newindent = $1; 15953a3c9242SWarner Losh $newindent = expand_tabs($newindent); 15963a3c9242SWarner Losh if (length($oldindent) ne length($newindent)) { 15973a3c9242SWarner Losh WARN("Block comments should align the * on each line\n" . $hereprev); 15983a3c9242SWarner Losh } 15993a3c9242SWarner Losh } 16003a3c9242SWarner Losh 16013a3c9242SWarner Losh# Check for potential 'bare' types 16023a3c9242SWarner Losh my ($stat, $cond, $line_nr_next, $remain_next, $off_next, 16033a3c9242SWarner Losh $realline_next); 16043a3c9242SWarner Losh if ($realcnt && $line =~ /.\s*\S/) { 16053a3c9242SWarner Losh ($stat, $cond, $line_nr_next, $remain_next, $off_next) = 16063a3c9242SWarner Losh ctx_statement_block($linenr, $realcnt, 0); 16073a3c9242SWarner Losh $stat =~ s/\n./\n /g; 16083a3c9242SWarner Losh $cond =~ s/\n./\n /g; 16093a3c9242SWarner Losh 16103a3c9242SWarner Losh # Find the real next line. 16113a3c9242SWarner Losh $realline_next = $line_nr_next; 16123a3c9242SWarner Losh if (defined $realline_next && 16133a3c9242SWarner Losh (!defined $lines[$realline_next - 1] || 16143a3c9242SWarner Losh substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { 16153a3c9242SWarner Losh $realline_next++; 16163a3c9242SWarner Losh } 16173a3c9242SWarner Losh 16183a3c9242SWarner Losh my $s = $stat; 16193a3c9242SWarner Losh $s =~ s/{.*$//s; 16203a3c9242SWarner Losh 16213a3c9242SWarner Losh # Ignore goto labels. 16223a3c9242SWarner Losh if ($s =~ /$Ident:\*$/s) { 16233a3c9242SWarner Losh 16243a3c9242SWarner Losh # Ignore functions being called 16253a3c9242SWarner Losh } elsif ($s =~ /^.\s*$Ident\s*\(/s) { 16263a3c9242SWarner Losh 16273a3c9242SWarner Losh } elsif ($s =~ /^.\s*else\b/s) { 16283a3c9242SWarner Losh 16293a3c9242SWarner Losh # declarations always start with types 16303a3c9242SWarner Losh } 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) { 16313a3c9242SWarner Losh my $type = $1; 16323a3c9242SWarner Losh $type =~ s/\s+/ /g; 16333a3c9242SWarner Losh possible($type, "A:" . $s); 16343a3c9242SWarner Losh 16353a3c9242SWarner Losh # definitions in global scope can only start with types 16363a3c9242SWarner Losh } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { 16373a3c9242SWarner Losh possible($1, "B:" . $s); 16383a3c9242SWarner Losh } 16393a3c9242SWarner Losh 16403a3c9242SWarner Losh # any (foo ... *) is a pointer cast, and foo is a type 16413a3c9242SWarner Losh while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { 16423a3c9242SWarner Losh possible($1, "C:" . $s); 16433a3c9242SWarner Losh } 16443a3c9242SWarner Losh 16453a3c9242SWarner Losh # Check for any sort of function declaration. 16463a3c9242SWarner Losh # int foo(something bar, other baz); 16473a3c9242SWarner Losh # void (*store_gdt)(x86_descr_ptr *); 16483a3c9242SWarner Losh if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { 16493a3c9242SWarner Losh my ($name_len) = length($1); 16503a3c9242SWarner Losh 16513a3c9242SWarner Losh my $ctx = $s; 16523a3c9242SWarner Losh substr($ctx, 0, $name_len + 1, ''); 16533a3c9242SWarner Losh $ctx =~ s/\)[^\)]*$//; 16543a3c9242SWarner Losh 16553a3c9242SWarner Losh for my $arg (split(/\s*,\s*/, $ctx)) { 16563a3c9242SWarner Losh if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { 16573a3c9242SWarner Losh 16583a3c9242SWarner Losh possible($1, "D:" . $s); 16593a3c9242SWarner Losh } 16603a3c9242SWarner Losh } 16613a3c9242SWarner Losh } 16623a3c9242SWarner Losh 16633a3c9242SWarner Losh } 16643a3c9242SWarner Losh 16653a3c9242SWarner Losh# 16663a3c9242SWarner Losh# Checks which may be anchored in the context. 16673a3c9242SWarner Losh# 16683a3c9242SWarner Losh 16693a3c9242SWarner Losh# Check for switch () and associated case and default 16703a3c9242SWarner Losh# statements should be at the same indent. 16713a3c9242SWarner Losh if ($line=~/\bswitch\s*\(.*\)/) { 16723a3c9242SWarner Losh my $err = ''; 16733a3c9242SWarner Losh my $sep = ''; 16743a3c9242SWarner Losh my @ctx = ctx_block_outer($linenr, $realcnt); 16753a3c9242SWarner Losh shift(@ctx); 16763a3c9242SWarner Losh for my $ctx (@ctx) { 16773a3c9242SWarner Losh my ($clen, $cindent) = line_stats($ctx); 16783a3c9242SWarner Losh if ($ctx =~ /^\+\s*(case\s+|default:)/ && 16793a3c9242SWarner Losh $indent != $cindent) { 16803a3c9242SWarner Losh $err .= "$sep$ctx\n"; 16813a3c9242SWarner Losh $sep = ''; 16823a3c9242SWarner Losh } else { 16833a3c9242SWarner Losh $sep = "[...]\n"; 16843a3c9242SWarner Losh } 16853a3c9242SWarner Losh } 16863a3c9242SWarner Losh if ($err ne '') { 16873a3c9242SWarner Losh ERROR("switch and case should be at the same indent\n$hereline$err"); 16883a3c9242SWarner Losh } 16893a3c9242SWarner Losh } 16903a3c9242SWarner Losh 16913a3c9242SWarner Losh# if/while/etc brace do not go on next line, unless defining a do while loop, 16923a3c9242SWarner Losh# or if that brace on the next line is for something else 16933a3c9242SWarner Losh if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { 16943a3c9242SWarner Losh my $pre_ctx = "$1$2"; 16953a3c9242SWarner Losh 16963a3c9242SWarner Losh my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); 16973a3c9242SWarner Losh my $ctx_cnt = $realcnt - $#ctx - 1; 16983a3c9242SWarner Losh my $ctx = join("\n", @ctx); 16993a3c9242SWarner Losh 17003a3c9242SWarner Losh my $ctx_ln = $linenr; 17013a3c9242SWarner Losh my $ctx_skip = $realcnt; 17023a3c9242SWarner Losh 17033a3c9242SWarner Losh while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && 17043a3c9242SWarner Losh defined $lines[$ctx_ln - 1] && 17053a3c9242SWarner Losh $lines[$ctx_ln - 1] =~ /^-/)) { 17063a3c9242SWarner Losh ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; 17073a3c9242SWarner Losh $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); 17083a3c9242SWarner Losh $ctx_ln++; 17093a3c9242SWarner Losh } 17103a3c9242SWarner Losh 17113a3c9242SWarner Losh #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; 17123a3c9242SWarner Losh #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; 17133a3c9242SWarner Losh 17143a3c9242SWarner Losh # The length of the "previous line" is checked against 80 because it 17153a3c9242SWarner Losh # includes the + at the beginning of the line (if the actual line has 17163a3c9242SWarner Losh # 79 or 80 characters, it is no longer possible to add a space and an 17173a3c9242SWarner Losh # opening brace there) 17183a3c9242SWarner Losh if ($#ctx == 0 && $ctx !~ /{\s*/ && 17193a3c9242SWarner Losh defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*\{/ && 17203a3c9242SWarner Losh defined($lines[$ctx_ln - 2]) && length($lines[$ctx_ln - 2]) < 80) { 17213a3c9242SWarner Losh ERROR("that open brace { should be on the previous line\n" . 17223a3c9242SWarner Losh "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); 17233a3c9242SWarner Losh } 17243a3c9242SWarner Losh if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && 17253a3c9242SWarner Losh $ctx =~ /\)\s*\;\s*$/ && 17263a3c9242SWarner Losh defined $lines[$ctx_ln - 1]) 17273a3c9242SWarner Losh { 17283a3c9242SWarner Losh my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); 17293a3c9242SWarner Losh if ($nindent > $indent) { 17303a3c9242SWarner Losh ERROR("trailing semicolon indicates no statements, indent implies otherwise\n" . 17313a3c9242SWarner Losh "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); 17323a3c9242SWarner Losh } 17333a3c9242SWarner Losh } 17343a3c9242SWarner Losh } 17353a3c9242SWarner Losh 17363a3c9242SWarner Losh# 'do ... while (0/false)' only makes sense in macros, without trailing ';' 17373a3c9242SWarner Losh if ($line =~ /while\s*\((0|false)\);/) { 17383a3c9242SWarner Losh ERROR("suspicious ; after while (0)\n" . $herecurr); 17393a3c9242SWarner Losh } 17403a3c9242SWarner Losh 17413a3c9242SWarner Losh# Check superfluous trailing ';' 17423a3c9242SWarner Losh if ($line =~ /;;$/) { 17433a3c9242SWarner Losh ERROR("superfluous trailing semicolon\n" . $herecurr); 17443a3c9242SWarner Losh } 17453a3c9242SWarner Losh 17463a3c9242SWarner Losh# Check relative indent for conditionals and blocks. 17473a3c9242SWarner Losh if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { 17483a3c9242SWarner Losh my ($s, $c) = ($stat, $cond); 17493a3c9242SWarner Losh 17503a3c9242SWarner Losh substr($s, 0, length($c), ''); 17513a3c9242SWarner Losh 17523a3c9242SWarner Losh # Make sure we remove the line prefixes as we have 17533a3c9242SWarner Losh # none on the first line, and are going to re-add them 17543a3c9242SWarner Losh # where necessary. 17553a3c9242SWarner Losh $s =~ s/\n./\n/gs; 17563a3c9242SWarner Losh 17573a3c9242SWarner Losh # Find out how long the conditional actually is. 17583a3c9242SWarner Losh my @newlines = ($c =~ /\n/gs); 17593a3c9242SWarner Losh my $cond_lines = 1 + $#newlines; 17603a3c9242SWarner Losh 17613a3c9242SWarner Losh # We want to check the first line inside the block 17623a3c9242SWarner Losh # starting at the end of the conditional, so remove: 17633a3c9242SWarner Losh # 1) any blank line termination 17643a3c9242SWarner Losh # 2) any opening brace { on end of the line 17653a3c9242SWarner Losh # 3) any do (...) { 17663a3c9242SWarner Losh my $continuation = 0; 17673a3c9242SWarner Losh my $check = 0; 17683a3c9242SWarner Losh $s =~ s/^.*\bdo\b//; 17693a3c9242SWarner Losh $s =~ s/^\s*\{//; 17703a3c9242SWarner Losh if ($s =~ s/^\s*\\//) { 17713a3c9242SWarner Losh $continuation = 1; 17723a3c9242SWarner Losh } 17733a3c9242SWarner Losh if ($s =~ s/^\s*?\n//) { 17743a3c9242SWarner Losh $check = 1; 17753a3c9242SWarner Losh $cond_lines++; 17763a3c9242SWarner Losh } 17773a3c9242SWarner Losh 17783a3c9242SWarner Losh # Also ignore a loop construct at the end of a 17793a3c9242SWarner Losh # preprocessor statement. 17803a3c9242SWarner Losh if (($prevline =~ /^.\s*#\s*define\s/ || 17813a3c9242SWarner Losh $prevline =~ /\\\s*$/) && $continuation == 0) { 17823a3c9242SWarner Losh $check = 0; 17833a3c9242SWarner Losh } 17843a3c9242SWarner Losh 17853a3c9242SWarner Losh my $cond_ptr = -1; 17863a3c9242SWarner Losh $continuation = 0; 17873a3c9242SWarner Losh while ($cond_ptr != $cond_lines) { 17883a3c9242SWarner Losh $cond_ptr = $cond_lines; 17893a3c9242SWarner Losh 17903a3c9242SWarner Losh # If we see an #else/#elif then the code 17913a3c9242SWarner Losh # is not linear. 17923a3c9242SWarner Losh if ($s =~ /^\s*\#\s*(?:else|elif)/) { 17933a3c9242SWarner Losh $check = 0; 17943a3c9242SWarner Losh } 17953a3c9242SWarner Losh 17963a3c9242SWarner Losh # Ignore: 17973a3c9242SWarner Losh # 1) blank lines, they should be at 0, 17983a3c9242SWarner Losh # 2) preprocessor lines, and 17993a3c9242SWarner Losh # 3) labels. 18003a3c9242SWarner Losh if ($continuation || 18013a3c9242SWarner Losh $s =~ /^\s*?\n/ || 18023a3c9242SWarner Losh $s =~ /^\s*#\s*?/ || 18033a3c9242SWarner Losh $s =~ /^\s*$Ident\s*:/) { 18043a3c9242SWarner Losh $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; 18053a3c9242SWarner Losh if ($s =~ s/^.*?\n//) { 18063a3c9242SWarner Losh $cond_lines++; 18073a3c9242SWarner Losh } 18083a3c9242SWarner Losh } 18093a3c9242SWarner Losh } 18103a3c9242SWarner Losh 18113a3c9242SWarner Losh my (undef, $sindent) = line_stats("+" . $s); 18123a3c9242SWarner Losh my $stat_real = raw_line($linenr, $cond_lines); 18133a3c9242SWarner Losh 18143a3c9242SWarner Losh # Check if either of these lines are modified, else 18153a3c9242SWarner Losh # this is not this patch's fault. 18163a3c9242SWarner Losh if (!defined($stat_real) || 18173a3c9242SWarner Losh $stat !~ /^\+/ && $stat_real !~ /^\+/) { 18183a3c9242SWarner Losh $check = 0; 18193a3c9242SWarner Losh } 18203a3c9242SWarner Losh if (defined($stat_real) && $cond_lines > 1) { 18213a3c9242SWarner Losh $stat_real = "[...]\n$stat_real"; 18223a3c9242SWarner Losh } 18233a3c9242SWarner Losh 18243a3c9242SWarner Losh #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"; 18253a3c9242SWarner Losh 18263a3c9242SWarner Losh if ($check && (($sindent % 4) != 0 || 18273a3c9242SWarner Losh ($sindent <= $indent && $s ne ''))) { 18283a3c9242SWarner Losh ERROR("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); 18293a3c9242SWarner Losh } 18303a3c9242SWarner Losh } 18313a3c9242SWarner Losh 18323a3c9242SWarner Losh # Track the 'values' across context and added lines. 18333a3c9242SWarner Losh my $opline = $line; $opline =~ s/^./ /; 18343a3c9242SWarner Losh my ($curr_values, $curr_vars) = 18353a3c9242SWarner Losh annotate_values($opline . "\n", $prev_values); 18363a3c9242SWarner Losh $curr_values = $prev_values . $curr_values; 18373a3c9242SWarner Losh if ($dbg_values) { 18383a3c9242SWarner Losh my $outline = $opline; $outline =~ s/\t/ /g; 18393a3c9242SWarner Losh print "$linenr > .$outline\n"; 18403a3c9242SWarner Losh print "$linenr > $curr_values\n"; 18413a3c9242SWarner Losh print "$linenr > $curr_vars\n"; 18423a3c9242SWarner Losh } 18433a3c9242SWarner Losh $prev_values = substr($curr_values, -1); 18443a3c9242SWarner Losh 18453a3c9242SWarner Losh#ignore lines not being added 18463a3c9242SWarner Losh if ($line=~/^[^\+]/) {next;} 18473a3c9242SWarner Losh 18483a3c9242SWarner Losh# check for initialisation to aggregates open brace on the next line 18493a3c9242SWarner Losh if ($line =~ /^.\s*\{/ && 18503a3c9242SWarner Losh $prevline =~ /(?:^|[^=])=\s*$/) { 18513a3c9242SWarner Losh ERROR("that open brace { should be on the previous line\n" . $hereprev); 18523a3c9242SWarner Losh } 18533a3c9242SWarner Losh 18543a3c9242SWarner Losh# 18553a3c9242SWarner Losh# Checks which are anchored on the added line. 18563a3c9242SWarner Losh# 18573a3c9242SWarner Losh 18583a3c9242SWarner Losh# check for malformed paths in #include statements (uses RAW line) 18593a3c9242SWarner Losh if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { 18603a3c9242SWarner Losh my $path = $1; 18613a3c9242SWarner Losh if ($path =~ m{//}) { 18623a3c9242SWarner Losh ERROR("malformed #include filename\n" . 18633a3c9242SWarner Losh $herecurr); 18643a3c9242SWarner Losh } 18653a3c9242SWarner Losh } 18663a3c9242SWarner Losh 18673a3c9242SWarner Losh# Remove C99 comments. 18683a3c9242SWarner Losh $line =~ s@//.*@@; 18693a3c9242SWarner Losh $opline =~ s@//.*@@; 18703a3c9242SWarner Losh 18713a3c9242SWarner Losh# * goes on variable not on type 18723a3c9242SWarner Losh # (char*[ const]) 18733a3c9242SWarner Losh if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { 18743a3c9242SWarner Losh my ($from, $to) = ($1, $1); 18753a3c9242SWarner Losh 18763a3c9242SWarner Losh # Should start with a space. 18773a3c9242SWarner Losh $to =~ s/^(\S)/ $1/; 18783a3c9242SWarner Losh # Should not end with a space. 18793a3c9242SWarner Losh $to =~ s/\s+$//; 18803a3c9242SWarner Losh # '*'s should not have spaces between. 18813a3c9242SWarner Losh while ($to =~ s/\*\s+\*/\*\*/) { 18823a3c9242SWarner Losh } 18833a3c9242SWarner Losh 18843a3c9242SWarner Losh #print "from<$from> to<$to>\n"; 18853a3c9242SWarner Losh if ($from ne $to) { 18863a3c9242SWarner Losh ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); 18873a3c9242SWarner Losh } 18883a3c9242SWarner Losh } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { 18893a3c9242SWarner Losh my ($from, $to, $ident) = ($1, $1, $2); 18903a3c9242SWarner Losh 18913a3c9242SWarner Losh # Should start with a space. 18923a3c9242SWarner Losh $to =~ s/^(\S)/ $1/; 18933a3c9242SWarner Losh # Should not end with a space. 18943a3c9242SWarner Losh $to =~ s/\s+$//; 18953a3c9242SWarner Losh # '*'s should not have spaces between. 18963a3c9242SWarner Losh while ($to =~ s/\*\s+\*/\*\*/) { 18973a3c9242SWarner Losh } 18983a3c9242SWarner Losh # Modifiers should have spaces. 18993a3c9242SWarner Losh $to =~ s/(\b$Modifier$)/$1 /; 19003a3c9242SWarner Losh 19013a3c9242SWarner Losh #print "from<$from> to<$to> ident<$ident>\n"; 19023a3c9242SWarner Losh if ($from ne $to && $ident !~ /^$Modifier$/) { 19033a3c9242SWarner Losh ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); 19043a3c9242SWarner Losh } 19053a3c9242SWarner Losh } 19063a3c9242SWarner Losh 19073a3c9242SWarner Losh# function brace can't be on same line, except for #defines of do while, 19083a3c9242SWarner Losh# or if closed on same line 19093a3c9242SWarner Losh if (($line=~/$Type\s*$Ident\(.*\).*\s\{/) and 19103a3c9242SWarner Losh !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { 19113a3c9242SWarner Losh ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); 19123a3c9242SWarner Losh } 19133a3c9242SWarner Losh 19143a3c9242SWarner Losh# missing space after union, struct or enum definition 19153a3c9242SWarner Losh if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { 19163a3c9242SWarner Losh ERROR("missing space after $1 definition\n" . $herecurr); 19173a3c9242SWarner Losh } 19183a3c9242SWarner Losh 19193a3c9242SWarner Losh# check for spacing round square brackets; allowed: 19203a3c9242SWarner Losh# 1. with a type on the left -- int [] a; 19213a3c9242SWarner Losh# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, 19223a3c9242SWarner Losh# 3. inside a curly brace -- = { [0...10] = 5 } 19233a3c9242SWarner Losh# 4. after a comma -- [1] = 5, [2] = 6 19243a3c9242SWarner Losh# 5. in a macro definition -- #define abc(x) [x] = y 19253a3c9242SWarner Losh while ($line =~ /(.*?\s)\[/g) { 19263a3c9242SWarner Losh my ($where, $prefix) = ($-[1], $1); 19273a3c9242SWarner Losh if ($prefix !~ /$Type\s+$/ && 19283a3c9242SWarner Losh ($where != 0 || $prefix !~ /^.\s+$/) && 19293a3c9242SWarner Losh $prefix !~ /\#\s*define[^(]*\([^)]*\)\s+$/ && 19303a3c9242SWarner Losh $prefix !~ /[,{:]\s+$/) { 19313a3c9242SWarner Losh ERROR("space prohibited before open square bracket '['\n" . $herecurr); 19323a3c9242SWarner Losh } 19333a3c9242SWarner Losh } 19343a3c9242SWarner Losh 19353a3c9242SWarner Losh# check for spaces between functions and their parentheses. 19363a3c9242SWarner Losh while ($line =~ /($Ident)\s+\(/g) { 19373a3c9242SWarner Losh my $name = $1; 19383a3c9242SWarner Losh my $ctx_before = substr($line, 0, $-[1]); 19393a3c9242SWarner Losh my $ctx = "$ctx_before$name"; 19403a3c9242SWarner Losh 19413a3c9242SWarner Losh # Ignore those directives where spaces _are_ permitted. 19423a3c9242SWarner Losh if ($name =~ /^(?: 19433a3c9242SWarner Losh if|for|while|switch|return|case| 19443a3c9242SWarner Losh volatile|__volatile__|coroutine_fn| 19453a3c9242SWarner Losh __attribute__|format|__extension__| 19463a3c9242SWarner Losh asm|__asm__)$/x) 19473a3c9242SWarner Losh { 19483a3c9242SWarner Losh 19493a3c9242SWarner Losh # Ignore 'catch (...)' in C++ 1950*0207010fSWarner Losh } elsif ($name =~ /^catch$/ && $realfile =~ /\.(cpp|h|hpp|hh|cc)$/) { 19513a3c9242SWarner Losh 19523a3c9242SWarner Losh # cpp #define statements have non-optional spaces, ie 19533a3c9242SWarner Losh # if there is a space between the name and the open 19543a3c9242SWarner Losh # parenthesis it is simply not a parameter group. 19553a3c9242SWarner Losh } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { 19563a3c9242SWarner Losh 19573a3c9242SWarner Losh # cpp #elif statement condition may start with a ( 19583a3c9242SWarner Losh } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { 19593a3c9242SWarner Losh 19603a3c9242SWarner Losh # If this whole things ends with a type its most 19613a3c9242SWarner Losh # likely a typedef for a function. 19623a3c9242SWarner Losh } elsif ($ctx =~ /$Type$/) { 19633a3c9242SWarner Losh 19643a3c9242SWarner Losh } else { 19653a3c9242SWarner Losh ERROR("space prohibited between function name and open parenthesis '('\n" . $herecurr); 19663a3c9242SWarner Losh } 19673a3c9242SWarner Losh } 19683a3c9242SWarner Losh# Check operator spacing. 19693a3c9242SWarner Losh if (!($line=~/\#\s*include/)) { 19703a3c9242SWarner Losh my $ops = qr{ 19713a3c9242SWarner Losh <<=|>>=|<=|>=|==|!=| 19723a3c9242SWarner Losh \+=|-=|\*=|\/=|%=|\^=|\|=|&=| 19733a3c9242SWarner Losh =>|->|<<|>>|<|>|=|!|~| 19743a3c9242SWarner Losh &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| 19753a3c9242SWarner Losh \?|::|: 19763a3c9242SWarner Losh }x; 19773a3c9242SWarner Losh my @elements = split(/($ops|;)/, $opline); 19783a3c9242SWarner Losh my $off = 0; 19793a3c9242SWarner Losh 19803a3c9242SWarner Losh my $blank = copy_spacing($opline); 19813a3c9242SWarner Losh 19823a3c9242SWarner Losh for (my $n = 0; $n < $#elements; $n += 2) { 19833a3c9242SWarner Losh $off += length($elements[$n]); 19843a3c9242SWarner Losh 19853a3c9242SWarner Losh # Pick up the preceding and succeeding characters. 19863a3c9242SWarner Losh my $ca = substr($opline, 0, $off); 19873a3c9242SWarner Losh my $cc = ''; 19883a3c9242SWarner Losh if (length($opline) >= ($off + length($elements[$n + 1]))) { 19893a3c9242SWarner Losh $cc = substr($opline, $off + length($elements[$n + 1])); 19903a3c9242SWarner Losh } 19913a3c9242SWarner Losh my $cb = "$ca$;$cc"; 19923a3c9242SWarner Losh 19933a3c9242SWarner Losh my $a = ''; 19943a3c9242SWarner Losh $a = 'V' if ($elements[$n] ne ''); 19953a3c9242SWarner Losh $a = 'W' if ($elements[$n] =~ /\s$/); 19963a3c9242SWarner Losh $a = 'C' if ($elements[$n] =~ /$;$/); 19973a3c9242SWarner Losh $a = 'B' if ($elements[$n] =~ /(\[|\()$/); 19983a3c9242SWarner Losh $a = 'O' if ($elements[$n] eq ''); 19993a3c9242SWarner Losh $a = 'E' if ($ca =~ /^\s*$/); 20003a3c9242SWarner Losh 20013a3c9242SWarner Losh my $op = $elements[$n + 1]; 20023a3c9242SWarner Losh 20033a3c9242SWarner Losh my $c = ''; 20043a3c9242SWarner Losh if (defined $elements[$n + 2]) { 20053a3c9242SWarner Losh $c = 'V' if ($elements[$n + 2] ne ''); 20063a3c9242SWarner Losh $c = 'W' if ($elements[$n + 2] =~ /^\s/); 20073a3c9242SWarner Losh $c = 'C' if ($elements[$n + 2] =~ /^$;/); 20083a3c9242SWarner Losh $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); 20093a3c9242SWarner Losh $c = 'O' if ($elements[$n + 2] eq ''); 20103a3c9242SWarner Losh $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); 20113a3c9242SWarner Losh } else { 20123a3c9242SWarner Losh $c = 'E'; 20133a3c9242SWarner Losh } 20143a3c9242SWarner Losh 20153a3c9242SWarner Losh my $ctx = "${a}x${c}"; 20163a3c9242SWarner Losh 20173a3c9242SWarner Losh my $at = "(ctx:$ctx)"; 20183a3c9242SWarner Losh 20193a3c9242SWarner Losh my $ptr = substr($blank, 0, $off) . "^"; 20203a3c9242SWarner Losh my $hereptr = "$hereline$ptr\n"; 20213a3c9242SWarner Losh 20223a3c9242SWarner Losh # Pull out the value of this operator. 20233a3c9242SWarner Losh my $op_type = substr($curr_values, $off + 1, 1); 20243a3c9242SWarner Losh 20253a3c9242SWarner Losh # Get the full operator variant. 20263a3c9242SWarner Losh my $opv = $op . substr($curr_vars, $off, 1); 20273a3c9242SWarner Losh 20283a3c9242SWarner Losh # Ignore operators passed as parameters. 20293a3c9242SWarner Losh if ($op_type ne 'V' && 20303a3c9242SWarner Losh $ca =~ /\s$/ && $cc =~ /^\s*,/) { 20313a3c9242SWarner Losh 20323a3c9242SWarner Losh# # Ignore comments 20333a3c9242SWarner Losh# } elsif ($op =~ /^$;+$/) { 20343a3c9242SWarner Losh 20353a3c9242SWarner Losh # ; should have either the end of line or a space or \ after it 20363a3c9242SWarner Losh } elsif ($op eq ';') { 20373a3c9242SWarner Losh if ($ctx !~ /.x[WEBC]/ && 20383a3c9242SWarner Losh $cc !~ /^\\/ && $cc !~ /^;/) { 20393a3c9242SWarner Losh ERROR("space required after that '$op' $at\n" . $hereptr); 20403a3c9242SWarner Losh } 20413a3c9242SWarner Losh 20423a3c9242SWarner Losh # // is a comment 20433a3c9242SWarner Losh } elsif ($op eq '//') { 20443a3c9242SWarner Losh 20453a3c9242SWarner Losh # Ignore : used in class declaration in C++ 20463a3c9242SWarner Losh } elsif ($opv eq ':B' && $ctx =~ /Wx[WE]/ && 2047*0207010fSWarner Losh $line =~ /class/ && $realfile =~ /\.(cpp|h|hpp|hh|cc)$/) { 20483a3c9242SWarner Losh 20493a3c9242SWarner Losh # No spaces for: 20503a3c9242SWarner Losh # -> 20513a3c9242SWarner Losh # : when part of a bitfield 20523a3c9242SWarner Losh } elsif ($op eq '->' || $opv eq ':B') { 20533a3c9242SWarner Losh if ($ctx =~ /Wx.|.xW/) { 20543a3c9242SWarner Losh ERROR("spaces prohibited around that '$op' $at\n" . $hereptr); 20553a3c9242SWarner Losh } 20563a3c9242SWarner Losh 20573a3c9242SWarner Losh # , must have a space on the right. 20583a3c9242SWarner Losh # not required when having a single },{ on one line 20593a3c9242SWarner Losh } elsif ($op eq ',') { 20603a3c9242SWarner Losh if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ && 20613a3c9242SWarner Losh ($elements[$n] . $elements[$n + 2]) !~ " *}\\{") { 20623a3c9242SWarner Losh ERROR("space required after that '$op' $at\n" . $hereptr); 20633a3c9242SWarner Losh } 20643a3c9242SWarner Losh 20653a3c9242SWarner Losh # '*' as part of a type definition -- reported already. 20663a3c9242SWarner Losh } elsif ($opv eq '*_') { 20673a3c9242SWarner Losh #warn "'*' is part of type\n"; 20683a3c9242SWarner Losh 20693a3c9242SWarner Losh # unary operators should have a space before and 20703a3c9242SWarner Losh # none after. May be left adjacent to another 20713a3c9242SWarner Losh # unary operator, or a cast 20723a3c9242SWarner Losh } elsif ($op eq '!' || $op eq '~' || 20733a3c9242SWarner Losh $opv eq '*U' || $opv eq '-U' || 20743a3c9242SWarner Losh $opv eq '&U' || $opv eq '&&U') { 2075*0207010fSWarner Losh if ($op eq '~' && $ca =~ /::$/ && $realfile =~ /\.(cpp|h|hpp|cc|hh)$/) { 20763a3c9242SWarner Losh # '~' used as a name of Destructor 20773a3c9242SWarner Losh 20783a3c9242SWarner Losh } elsif ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { 20793a3c9242SWarner Losh ERROR("space required before that '$op' $at\n" . $hereptr); 20803a3c9242SWarner Losh } 20813a3c9242SWarner Losh if ($op eq '*' && $cc =~/\s*$Modifier\b/) { 20823a3c9242SWarner Losh # A unary '*' may be const 20833a3c9242SWarner Losh 20843a3c9242SWarner Losh } elsif ($ctx =~ /.xW/) { 20853a3c9242SWarner Losh ERROR("space prohibited after that '$op' $at\n" . $hereptr); 20863a3c9242SWarner Losh } 20873a3c9242SWarner Losh 20883a3c9242SWarner Losh # unary ++ and unary -- are allowed no space on one side. 20893a3c9242SWarner Losh } elsif ($op eq '++' or $op eq '--') { 20903a3c9242SWarner Losh if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { 20913a3c9242SWarner Losh ERROR("space required one side of that '$op' $at\n" . $hereptr); 20923a3c9242SWarner Losh } 20933a3c9242SWarner Losh if ($ctx =~ /Wx[BE]/ || 20943a3c9242SWarner Losh ($ctx =~ /Wx./ && $cc =~ /^;/)) { 20953a3c9242SWarner Losh ERROR("space prohibited before that '$op' $at\n" . $hereptr); 20963a3c9242SWarner Losh } 20973a3c9242SWarner Losh if ($ctx =~ /ExW/) { 20983a3c9242SWarner Losh ERROR("space prohibited after that '$op' $at\n" . $hereptr); 20993a3c9242SWarner Losh } 21003a3c9242SWarner Losh 21013a3c9242SWarner Losh # A colon needs no spaces before when it is 21023a3c9242SWarner Losh # terminating a case value or a label. 21033a3c9242SWarner Losh } elsif ($opv eq ':C' || $opv eq ':L') { 21043a3c9242SWarner Losh if ($ctx =~ /Wx./) { 21053a3c9242SWarner Losh ERROR("space prohibited before that '$op' $at\n" . $hereptr); 21063a3c9242SWarner Losh } 21073a3c9242SWarner Losh 21083a3c9242SWarner Losh # All the others need spaces both sides. 21093a3c9242SWarner Losh } elsif ($ctx !~ /[EWC]x[CWE]/) { 21103a3c9242SWarner Losh my $ok = 0; 21113a3c9242SWarner Losh 2112*0207010fSWarner Losh if ($realfile =~ /\.(cpp|h|hpp|cc|hh)$/) { 21133a3c9242SWarner Losh # Ignore template arguments <...> in C++ 21143a3c9242SWarner Losh if (($op eq '<' || $op eq '>') && $line =~ /<.*>/) { 21153a3c9242SWarner Losh $ok = 1; 21163a3c9242SWarner Losh } 21173a3c9242SWarner Losh 21183a3c9242SWarner Losh # Ignore :: in C++ 21193a3c9242SWarner Losh if ($op eq '::') { 21203a3c9242SWarner Losh $ok = 1; 21213a3c9242SWarner Losh } 21223a3c9242SWarner Losh } 21233a3c9242SWarner Losh 21243a3c9242SWarner Losh # Ignore email addresses <foo@bar> 21253a3c9242SWarner Losh if (($op eq '<' && 21263a3c9242SWarner Losh $cc =~ /^\S+\@\S+>/) || 21273a3c9242SWarner Losh ($op eq '>' && 21283a3c9242SWarner Losh $ca =~ /<\S+\@\S+$/)) 21293a3c9242SWarner Losh { 21303a3c9242SWarner Losh $ok = 1; 21313a3c9242SWarner Losh } 21323a3c9242SWarner Losh 21333a3c9242SWarner Losh # Ignore ?: 21343a3c9242SWarner Losh if (($opv eq ':O' && $ca =~ /\?$/) || 21353a3c9242SWarner Losh ($op eq '?' && $cc =~ /^:/)) { 21363a3c9242SWarner Losh $ok = 1; 21373a3c9242SWarner Losh } 21383a3c9242SWarner Losh 21393a3c9242SWarner Losh if ($ok == 0) { 21403a3c9242SWarner Losh ERROR("spaces required around that '$op' $at\n" . $hereptr); 21413a3c9242SWarner Losh } 21423a3c9242SWarner Losh } 21433a3c9242SWarner Losh $off += length($elements[$n + 1]); 21443a3c9242SWarner Losh } 21453a3c9242SWarner Losh } 21463a3c9242SWarner Losh 21473a3c9242SWarner Losh#need space before brace following if, while, etc 21483a3c9242SWarner Losh if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || 21493a3c9242SWarner Losh $line =~ /do\{/) { 21503a3c9242SWarner Losh ERROR("space required before the open brace '{'\n" . $herecurr); 21513a3c9242SWarner Losh } 21523a3c9242SWarner Losh 21533a3c9242SWarner Losh# closing brace should have a space following it when it has anything 21543a3c9242SWarner Losh# on the line 21553a3c9242SWarner Losh if ($line =~ /}(?!(?:,|;|\)))\S/) { 21563a3c9242SWarner Losh ERROR("space required after that close brace '}'\n" . $herecurr); 21573a3c9242SWarner Losh } 21583a3c9242SWarner Losh 21593a3c9242SWarner Losh# check spacing on square brackets 21603a3c9242SWarner Losh if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { 21613a3c9242SWarner Losh ERROR("space prohibited after that open square bracket '['\n" . $herecurr); 21623a3c9242SWarner Losh } 21633a3c9242SWarner Losh if ($line =~ /\s\]/) { 21643a3c9242SWarner Losh ERROR("space prohibited before that close square bracket ']'\n" . $herecurr); 21653a3c9242SWarner Losh } 21663a3c9242SWarner Losh 21673a3c9242SWarner Losh# check spacing on parentheses 21683a3c9242SWarner Losh if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && 21693a3c9242SWarner Losh $line !~ /for\s*\(\s+;/) { 21703a3c9242SWarner Losh ERROR("space prohibited after that open parenthesis '('\n" . $herecurr); 21713a3c9242SWarner Losh } 21723a3c9242SWarner Losh if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && 21733a3c9242SWarner Losh $line !~ /for\s*\(.*;\s+\)/ && 21743a3c9242SWarner Losh $line !~ /:\s+\)/) { 21753a3c9242SWarner Losh ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr); 21763a3c9242SWarner Losh } 21773a3c9242SWarner Losh 21783a3c9242SWarner Losh if ($line =~ /^.\s*(Q(?:S?LIST|SIMPLEQ|TAILQ)_HEAD)\s*\(\s*[^,]/ && 21793a3c9242SWarner Losh $line !~ /^.typedef/) { 21803a3c9242SWarner Losh ERROR("named $1 should be typedefed separately\n" . $herecurr); 21813a3c9242SWarner Losh } 21823a3c9242SWarner Losh 21833a3c9242SWarner Losh# Return needs parens 21843a3c9242SWarner Losh if ($line =~ /^.\s*return [^(]/) { 21853a3c9242SWarner Losh ERROR("parentheses required on return\n" . $herecurr); 21863a3c9242SWarner Losh } 21873a3c9242SWarner Losh 21883a3c9242SWarner Losh# Need a space before open parenthesis after if, while etc 21893a3c9242SWarner Losh if ($line=~/\b(if|while|for|switch|return)\(/) { 21903a3c9242SWarner Losh ERROR("space required before the open parenthesis '('\n" . $herecurr); 21913a3c9242SWarner Losh } 21923a3c9242SWarner Losh 21933a3c9242SWarner Losh# Check for illegal assignment in if conditional -- and check for trailing 21943a3c9242SWarner Losh# statements after the conditional. 21953a3c9242SWarner Losh if ($line =~ /do\s*(?!{)/) { 21963a3c9242SWarner Losh my ($stat_next) = ctx_statement_block($line_nr_next, 21973a3c9242SWarner Losh $remain_next, $off_next); 21983a3c9242SWarner Losh $stat_next =~ s/\n./\n /g; 21993a3c9242SWarner Losh ##print "stat<$stat> stat_next<$stat_next>\n"; 22003a3c9242SWarner Losh 22013a3c9242SWarner Losh if ($stat_next =~ /^\s*while\b/) { 22023a3c9242SWarner Losh # If the statement carries leading newlines, 22033a3c9242SWarner Losh # then count those as offsets. 22043a3c9242SWarner Losh my ($whitespace) = 22053a3c9242SWarner Losh ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); 22063a3c9242SWarner Losh my $offset = 22073a3c9242SWarner Losh statement_rawlines($whitespace) - 1; 22083a3c9242SWarner Losh 22093a3c9242SWarner Losh $suppress_whiletrailers{$line_nr_next + 22103a3c9242SWarner Losh $offset} = 1; 22113a3c9242SWarner Losh } 22123a3c9242SWarner Losh } 22133a3c9242SWarner Losh if (!defined $suppress_whiletrailers{$linenr} && 22143a3c9242SWarner Losh $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { 22153a3c9242SWarner Losh my ($s, $c) = ($stat, $cond); 22163a3c9242SWarner Losh 22173a3c9242SWarner Losh# if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { 22183a3c9242SWarner Losh# ERROR("do not use assignment in if condition\n" . $herecurr); 22193a3c9242SWarner Losh# } 22203a3c9242SWarner Losh 22213a3c9242SWarner Losh # Find out what is on the end of the line after the 22223a3c9242SWarner Losh # conditional. 22233a3c9242SWarner Losh substr($s, 0, length($c), ''); 22243a3c9242SWarner Losh $s =~ s/\n.*//g; 22253a3c9242SWarner Losh $s =~ s/$;//g; # Remove any comments 22263a3c9242SWarner Losh if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && 22273a3c9242SWarner Losh $c !~ /}\s*while\s*/) 22283a3c9242SWarner Losh { 22293a3c9242SWarner Losh # Find out how long the conditional actually is. 22303a3c9242SWarner Losh my @newlines = ($c =~ /\n/gs); 22313a3c9242SWarner Losh my $cond_lines = 1 + $#newlines; 22323a3c9242SWarner Losh my $stat_real = ''; 22333a3c9242SWarner Losh 22343a3c9242SWarner Losh $stat_real = raw_line($linenr, $cond_lines) 22353a3c9242SWarner Losh . "\n" if ($cond_lines); 22363a3c9242SWarner Losh if (defined($stat_real) && $cond_lines > 1) { 22373a3c9242SWarner Losh $stat_real = "[...]\n$stat_real"; 22383a3c9242SWarner Losh } 22393a3c9242SWarner Losh 22403a3c9242SWarner Losh ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real); 22413a3c9242SWarner Losh } 22423a3c9242SWarner Losh } 22433a3c9242SWarner Losh 22443a3c9242SWarner Losh# Check for bitwise tests written as boolean 22453a3c9242SWarner Losh if ($line =~ / 22463a3c9242SWarner Losh (?: 22473a3c9242SWarner Losh (?:\[|\(|\&\&|\|\|) 22483a3c9242SWarner Losh \s*0[xX][0-9]+\s* 22493a3c9242SWarner Losh (?:\&\&|\|\|) 22503a3c9242SWarner Losh | 22513a3c9242SWarner Losh (?:\&\&|\|\|) 22523a3c9242SWarner Losh \s*0[xX][0-9]+\s* 22533a3c9242SWarner Losh (?:\&\&|\|\||\)|\]) 22543a3c9242SWarner Losh )/x) 22553a3c9242SWarner Losh { 22563a3c9242SWarner Losh ERROR("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); 22573a3c9242SWarner Losh } 22583a3c9242SWarner Losh 22593a3c9242SWarner Losh# if and else should not have general statements after it 22603a3c9242SWarner Losh if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { 22613a3c9242SWarner Losh my $s = $1; 22623a3c9242SWarner Losh $s =~ s/$;//g; # Remove any comments 22633a3c9242SWarner Losh if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { 22643a3c9242SWarner Losh ERROR("trailing statements should be on next line\n" . $herecurr); 22653a3c9242SWarner Losh } 22663a3c9242SWarner Losh } 22673a3c9242SWarner Losh# if should not continue a brace 22683a3c9242SWarner Losh if ($line =~ /}\s*if\b/) { 22693a3c9242SWarner Losh ERROR("trailing statements should be on next line\n" . 22703a3c9242SWarner Losh $herecurr); 22713a3c9242SWarner Losh } 22723a3c9242SWarner Losh# case and default should not have general statements after them 22733a3c9242SWarner Losh if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && 22743a3c9242SWarner Losh $line !~ /\G(?: 22753a3c9242SWarner Losh (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| 22763a3c9242SWarner Losh \s*return\s+ 22773a3c9242SWarner Losh )/xg) 22783a3c9242SWarner Losh { 22793a3c9242SWarner Losh ERROR("trailing statements should be on next line\n" . $herecurr); 22803a3c9242SWarner Losh } 22813a3c9242SWarner Losh 22823a3c9242SWarner Losh # Check for }<nl>else {, these must be at the same 22833a3c9242SWarner Losh # indent level to be relevant to each other. 22843a3c9242SWarner Losh if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and 22853a3c9242SWarner Losh $previndent == $indent) { 22863a3c9242SWarner Losh ERROR("else should follow close brace '}'\n" . $hereprev); 22873a3c9242SWarner Losh } 22883a3c9242SWarner Losh 22893a3c9242SWarner Losh if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and 22903a3c9242SWarner Losh $previndent == $indent) { 22913a3c9242SWarner Losh my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); 22923a3c9242SWarner Losh 22933a3c9242SWarner Losh # Find out what is on the end of the line after the 22943a3c9242SWarner Losh # conditional. 22953a3c9242SWarner Losh substr($s, 0, length($c), ''); 22963a3c9242SWarner Losh $s =~ s/\n.*//g; 22973a3c9242SWarner Losh 22983a3c9242SWarner Losh if ($s =~ /^\s*;/) { 22993a3c9242SWarner Losh ERROR("while should follow close brace '}'\n" . $hereprev); 23003a3c9242SWarner Losh } 23013a3c9242SWarner Losh } 23023a3c9242SWarner Losh 23033a3c9242SWarner Losh#no spaces allowed after \ in define 23043a3c9242SWarner Losh if ($line=~/\#\s*define.*\\\s$/) { 23053a3c9242SWarner Losh ERROR("Whitespace after \\ makes next lines useless\n" . $herecurr); 23063a3c9242SWarner Losh } 23073a3c9242SWarner Losh 23083a3c9242SWarner Losh# multi-statement macros should be enclosed in a do while loop, grab the 23093a3c9242SWarner Losh# first statement and ensure its the whole macro if its not enclosed 23103a3c9242SWarner Losh# in a known good container 23113a3c9242SWarner Losh if ($realfile !~ m@/vmlinux.lds.h$@ && 23123a3c9242SWarner Losh $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { 23133a3c9242SWarner Losh my $ln = $linenr; 23143a3c9242SWarner Losh my $cnt = $realcnt; 23153a3c9242SWarner Losh my ($off, $dstat, $dcond, $rest); 23163a3c9242SWarner Losh my $ctx = ''; 23173a3c9242SWarner Losh 23183a3c9242SWarner Losh my $args = defined($1); 23193a3c9242SWarner Losh 23203a3c9242SWarner Losh # Find the end of the macro and limit our statement 23213a3c9242SWarner Losh # search to that. 23223a3c9242SWarner Losh while ($cnt > 0 && defined $lines[$ln - 1] && 23233a3c9242SWarner Losh $lines[$ln - 1] =~ /^(?:-|..*\\$)/) 23243a3c9242SWarner Losh { 23253a3c9242SWarner Losh $ctx .= $rawlines[$ln - 1] . "\n"; 23263a3c9242SWarner Losh $cnt-- if ($lines[$ln - 1] !~ /^-/); 23273a3c9242SWarner Losh $ln++; 23283a3c9242SWarner Losh } 23293a3c9242SWarner Losh $ctx .= $rawlines[$ln - 1]; 23303a3c9242SWarner Losh 23313a3c9242SWarner Losh ($dstat, $dcond, $ln, $cnt, $off) = 23323a3c9242SWarner Losh ctx_statement_block($linenr, $ln - $linenr + 1, 0); 23333a3c9242SWarner Losh #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; 23343a3c9242SWarner Losh #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; 23353a3c9242SWarner Losh 23363a3c9242SWarner Losh # Extract the remainder of the define (if any) and 23373a3c9242SWarner Losh # rip off surrounding spaces, and trailing \'s. 23383a3c9242SWarner Losh $rest = ''; 23393a3c9242SWarner Losh while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { 23403a3c9242SWarner Losh #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; 23413a3c9242SWarner Losh if ($off != 0 || $lines[$ln - 1] !~ /^-/) { 23423a3c9242SWarner Losh $rest .= substr($lines[$ln - 1], $off) . "\n"; 23433a3c9242SWarner Losh $cnt--; 23443a3c9242SWarner Losh } 23453a3c9242SWarner Losh $ln++; 23463a3c9242SWarner Losh $off = 0; 23473a3c9242SWarner Losh } 23483a3c9242SWarner Losh $rest =~ s/\\\n.//g; 23493a3c9242SWarner Losh $rest =~ s/^\s*//s; 23503a3c9242SWarner Losh $rest =~ s/\s*$//s; 23513a3c9242SWarner Losh 23523a3c9242SWarner Losh # Clean up the original statement. 23533a3c9242SWarner Losh if ($args) { 23543a3c9242SWarner Losh substr($dstat, 0, length($dcond), ''); 23553a3c9242SWarner Losh } else { 23563a3c9242SWarner Losh $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; 23573a3c9242SWarner Losh } 23583a3c9242SWarner Losh $dstat =~ s/$;//g; 23593a3c9242SWarner Losh $dstat =~ s/\\\n.//g; 23603a3c9242SWarner Losh $dstat =~ s/^\s*//s; 23613a3c9242SWarner Losh $dstat =~ s/\s*$//s; 23623a3c9242SWarner Losh 23633a3c9242SWarner Losh # Flatten any parentheses and braces 23643a3c9242SWarner Losh while ($dstat =~ s/\([^\(\)]*\)/1/ || 23653a3c9242SWarner Losh $dstat =~ s/\{[^\{\}]*\}/1/ || 23663a3c9242SWarner Losh $dstat =~ s/\[[^\{\}]*\]/1/) 23673a3c9242SWarner Losh { 23683a3c9242SWarner Losh } 23693a3c9242SWarner Losh 23703a3c9242SWarner Losh my $exceptions = qr{ 23713a3c9242SWarner Losh $Declare| 23723a3c9242SWarner Losh module_param_named| 23733a3c9242SWarner Losh MODULE_PARAM_DESC| 23743a3c9242SWarner Losh DECLARE_PER_CPU| 23753a3c9242SWarner Losh DEFINE_PER_CPU| 23763a3c9242SWarner Losh __typeof__\(| 23773a3c9242SWarner Losh union| 23783a3c9242SWarner Losh struct| 23793a3c9242SWarner Losh \.$Ident\s*=\s*| 23803a3c9242SWarner Losh ^\"|\"$ 23813a3c9242SWarner Losh }x; 23823a3c9242SWarner Losh #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; 23833a3c9242SWarner Losh if ($rest ne '' && $rest ne ',') { 23843a3c9242SWarner Losh if ($rest !~ /while\s*\(/ && 23853a3c9242SWarner Losh $dstat !~ /$exceptions/) 23863a3c9242SWarner Losh { 23873a3c9242SWarner Losh ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); 23883a3c9242SWarner Losh } 23893a3c9242SWarner Losh 23903a3c9242SWarner Losh } elsif ($ctx !~ /;/) { 23913a3c9242SWarner Losh if ($dstat ne '' && 23923a3c9242SWarner Losh $dstat !~ /^(?:$Ident|-?$Constant)$/ && 23933a3c9242SWarner Losh $dstat !~ /$exceptions/ && 23943a3c9242SWarner Losh $dstat !~ /^\.$Ident\s*=/ && 23953a3c9242SWarner Losh $dstat =~ /$Operators/) 23963a3c9242SWarner Losh { 23973a3c9242SWarner Losh ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); 23983a3c9242SWarner Losh } 23993a3c9242SWarner Losh } 24003a3c9242SWarner Losh } 24013a3c9242SWarner Losh 24023a3c9242SWarner Losh# check for missing bracing around if etc 24033a3c9242SWarner Losh if ($line =~ /(^.*)\b(?:if|while|for)\b/ && 24043a3c9242SWarner Losh $line !~ /\#\s*if/) { 24053a3c9242SWarner Losh my $allowed = 0; 24063a3c9242SWarner Losh 24073a3c9242SWarner Losh # Check the pre-context. 24083a3c9242SWarner Losh if ($line =~ /(\}.*?)$/) { 24093a3c9242SWarner Losh my $pre = $1; 24103a3c9242SWarner Losh 24113a3c9242SWarner Losh if ($line !~ /else/) { 24123a3c9242SWarner Losh print "APW: ALLOWED: pre<$pre> line<$line>\n" 24133a3c9242SWarner Losh if $dbg_adv_apw; 24143a3c9242SWarner Losh $allowed = 1; 24153a3c9242SWarner Losh } 24163a3c9242SWarner Losh } 24173a3c9242SWarner Losh my ($level, $endln, @chunks) = 24183a3c9242SWarner Losh ctx_statement_full($linenr, $realcnt, 1); 24193a3c9242SWarner Losh if ($dbg_adv_apw) { 24203a3c9242SWarner Losh print "APW: chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; 24213a3c9242SWarner Losh print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n" 24223a3c9242SWarner Losh if $#chunks >= 1; 24233a3c9242SWarner Losh } 24243a3c9242SWarner Losh if ($#chunks >= 0 && $level == 0) { 24253a3c9242SWarner Losh my $seen = 0; 24263a3c9242SWarner Losh my $herectx = $here . "\n"; 24273a3c9242SWarner Losh my $ln = $linenr - 1; 24283a3c9242SWarner Losh for my $chunk (@chunks) { 24293a3c9242SWarner Losh my ($cond, $block) = @{$chunk}; 24303a3c9242SWarner Losh 24313a3c9242SWarner Losh # If the condition carries leading newlines, then count those as offsets. 24323a3c9242SWarner Losh my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); 24333a3c9242SWarner Losh my $offset = statement_rawlines($whitespace) - 1; 24343a3c9242SWarner Losh 24353a3c9242SWarner Losh #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; 24363a3c9242SWarner Losh 24373a3c9242SWarner Losh # We have looked at and allowed this specific line. 24383a3c9242SWarner Losh $suppress_ifbraces{$ln + $offset} = 1; 24393a3c9242SWarner Losh 24403a3c9242SWarner Losh $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; 24413a3c9242SWarner Losh $ln += statement_rawlines($block) - 1; 24423a3c9242SWarner Losh 24433a3c9242SWarner Losh substr($block, 0, length($cond), ''); 24443a3c9242SWarner Losh 24453a3c9242SWarner Losh my $spaced_block = $block; 24463a3c9242SWarner Losh $spaced_block =~ s/\n\+/ /g; 24473a3c9242SWarner Losh 24483a3c9242SWarner Losh $seen++ if ($spaced_block =~ /^\s*\{/); 24493a3c9242SWarner Losh 24503a3c9242SWarner Losh print "APW: cond<$cond> block<$block> allowed<$allowed>\n" 24513a3c9242SWarner Losh if $dbg_adv_apw; 24523a3c9242SWarner Losh if (statement_lines($cond) > 1) { 24533a3c9242SWarner Losh print "APW: ALLOWED: cond<$cond>\n" 24543a3c9242SWarner Losh if $dbg_adv_apw; 24553a3c9242SWarner Losh $allowed = 1; 24563a3c9242SWarner Losh } 24573a3c9242SWarner Losh if ($block =~/\b(?:if|for|while)\b/) { 24583a3c9242SWarner Losh print "APW: ALLOWED: block<$block>\n" 24593a3c9242SWarner Losh if $dbg_adv_apw; 24603a3c9242SWarner Losh $allowed = 1; 24613a3c9242SWarner Losh } 24623a3c9242SWarner Losh if (statement_block_size($block) > 1) { 24633a3c9242SWarner Losh print "APW: ALLOWED: lines block<$block>\n" 24643a3c9242SWarner Losh if $dbg_adv_apw; 24653a3c9242SWarner Losh $allowed = 1; 24663a3c9242SWarner Losh } 24673a3c9242SWarner Losh } 24683a3c9242SWarner Losh $allowed=1; # disable for now. 24693a3c9242SWarner Losh if ($seen != ($#chunks + 1) && !$allowed) { 24703a3c9242SWarner Losh ERROR("braces {} are necessary for all arms of this statement\n" . $herectx); 24713a3c9242SWarner Losh } 24723a3c9242SWarner Losh } 24733a3c9242SWarner Losh } 24743a3c9242SWarner Losh if (!defined $suppress_ifbraces{$linenr - 1} && 24753a3c9242SWarner Losh $line =~ /\b(if|while|for|else)\b/ && 24763a3c9242SWarner Losh $line !~ /\#\s*if/ && 24773a3c9242SWarner Losh $line !~ /\#\s*else/) { 24783a3c9242SWarner Losh my $allowed = 0; 24793a3c9242SWarner Losh 24803a3c9242SWarner Losh # Check the pre-context. 24813a3c9242SWarner Losh if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { 24823a3c9242SWarner Losh my $pre = $1; 24833a3c9242SWarner Losh 24843a3c9242SWarner Losh if ($line !~ /else/) { 24853a3c9242SWarner Losh print "APW: ALLOWED: pre<$pre> line<$line>\n" 24863a3c9242SWarner Losh if $dbg_adv_apw; 24873a3c9242SWarner Losh $allowed = 1; 24883a3c9242SWarner Losh } 24893a3c9242SWarner Losh } 24903a3c9242SWarner Losh 24913a3c9242SWarner Losh my ($level, $endln, @chunks) = 24923a3c9242SWarner Losh ctx_statement_full($linenr, $realcnt, $-[0]); 24933a3c9242SWarner Losh 24943a3c9242SWarner Losh # Check the condition. 24953a3c9242SWarner Losh my ($cond, $block) = @{$chunks[0]}; 24963a3c9242SWarner Losh print "CHECKING<$linenr> cond<$cond> block<$block>\n" 24973a3c9242SWarner Losh if $dbg_adv_checking; 24983a3c9242SWarner Losh if (defined $cond) { 24993a3c9242SWarner Losh substr($block, 0, length($cond), ''); 25003a3c9242SWarner Losh } 25013a3c9242SWarner Losh if (statement_lines($cond) > 1) { 25023a3c9242SWarner Losh print "APW: ALLOWED: cond<$cond>\n" 25033a3c9242SWarner Losh if $dbg_adv_apw; 25043a3c9242SWarner Losh $allowed = 1; 25053a3c9242SWarner Losh } 25063a3c9242SWarner Losh if ($block =~/\b(?:if|for|while)\b/) { 25073a3c9242SWarner Losh print "APW: ALLOWED: block<$block>\n" 25083a3c9242SWarner Losh if $dbg_adv_apw; 25093a3c9242SWarner Losh $allowed = 1; 25103a3c9242SWarner Losh } 25113a3c9242SWarner Losh if (statement_block_size($block) > 1) { 25123a3c9242SWarner Losh print "APW: ALLOWED: lines block<$block>\n" 25133a3c9242SWarner Losh if $dbg_adv_apw; 25143a3c9242SWarner Losh $allowed = 1; 25153a3c9242SWarner Losh } 25163a3c9242SWarner Losh # Check the post-context. 25173a3c9242SWarner Losh if (defined $chunks[1]) { 25183a3c9242SWarner Losh my ($cond, $block) = @{$chunks[1]}; 25193a3c9242SWarner Losh if (defined $cond) { 25203a3c9242SWarner Losh substr($block, 0, length($cond), ''); 25213a3c9242SWarner Losh } 25223a3c9242SWarner Losh if ($block =~ /^\s*\{/) { 25233a3c9242SWarner Losh print "APW: ALLOWED: chunk-1 block<$block>\n" 25243a3c9242SWarner Losh if $dbg_adv_apw; 25253a3c9242SWarner Losh $allowed = 1; 25263a3c9242SWarner Losh } 25273a3c9242SWarner Losh } 25283a3c9242SWarner Losh print "DCS: level=$level block<$block> allowed=$allowed\n" 25293a3c9242SWarner Losh if $dbg_adv_dcs; 25303a3c9242SWarner Losh if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) { 25313a3c9242SWarner Losh my $herectx = $here . "\n";; 25323a3c9242SWarner Losh my $cnt = statement_rawlines($block); 25333a3c9242SWarner Losh 25343a3c9242SWarner Losh for (my $n = 0; $n < $cnt; $n++) { 25353a3c9242SWarner Losh $herectx .= raw_line($linenr, $n) . "\n";; 25363a3c9242SWarner Losh } 25373a3c9242SWarner Losh 253857623b3bSWarner Losh WARN("braces {} are encouraged even for single statement blocks\n" . $herectx); 25393a3c9242SWarner Losh } 25403a3c9242SWarner Losh } 25413a3c9242SWarner Losh 25423a3c9242SWarner Losh# warn about #if 0 25433a3c9242SWarner Losh if ($line =~ /^.\s*\#\s*if\s+0\b/) { 25443a3c9242SWarner Losh ERROR("if this code is redundant consider removing it\n" . 25453a3c9242SWarner Losh $herecurr); 25463a3c9242SWarner Losh } 25473a3c9242SWarner Losh 25483a3c9242SWarner Losh# Check that the storage class is at the beginning of a declaration 25493a3c9242SWarner Losh if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { 25503a3c9242SWarner Losh ERROR("storage class should be at the beginning of the declaration\n" . $herecurr) 25513a3c9242SWarner Losh } 25523a3c9242SWarner Losh 25533a3c9242SWarner Losh# check the location of the inline attribute, that it is between 25543a3c9242SWarner Losh# storage class and type. 25553a3c9242SWarner Losh if ($line =~ /\b$Type\s+$Inline\b/ || 25563a3c9242SWarner Losh $line =~ /\b$Inline\s+$Storage\b/) { 25573a3c9242SWarner Losh ERROR("inline keyword should sit between storage class and type\n" . $herecurr); 25583a3c9242SWarner Losh } 25593a3c9242SWarner Losh 25603a3c9242SWarner Losh# check for sizeof(&) 25613a3c9242SWarner Losh if ($line =~ /\bsizeof\s*\(\s*\&/) { 25623a3c9242SWarner Losh ERROR("sizeof(& should be avoided\n" . $herecurr); 25633a3c9242SWarner Losh } 25643a3c9242SWarner Losh 25653a3c9242SWarner Losh# check for new externs in .c files. 25663a3c9242SWarner Losh if ($realfile =~ /\.c$/ && defined $stat && 25673a3c9242SWarner Losh $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) 25683a3c9242SWarner Losh { 25693a3c9242SWarner Losh my $function_name = $1; 25703a3c9242SWarner Losh my $paren_space = $2; 25713a3c9242SWarner Losh 25723a3c9242SWarner Losh my $s = $stat; 25733a3c9242SWarner Losh if (defined $cond) { 25743a3c9242SWarner Losh substr($s, 0, length($cond), ''); 25753a3c9242SWarner Losh } 25763a3c9242SWarner Losh if ($s =~ /^\s*;/ && 25773a3c9242SWarner Losh $function_name ne 'uninitialized_var') 25783a3c9242SWarner Losh { 25793a3c9242SWarner Losh ERROR("externs should be avoided in .c files\n" . $herecurr); 25803a3c9242SWarner Losh } 25813a3c9242SWarner Losh 25823a3c9242SWarner Losh if ($paren_space =~ /\n/) { 25833a3c9242SWarner Losh ERROR("arguments for function declarations should follow identifier\n" . $herecurr); 25843a3c9242SWarner Losh } 25853a3c9242SWarner Losh 25863a3c9242SWarner Losh } elsif ($realfile =~ /\.c$/ && defined $stat && 25873a3c9242SWarner Losh $stat =~ /^.\s*extern\s+/) 25883a3c9242SWarner Losh { 25893a3c9242SWarner Losh ERROR("externs should be avoided in .c files\n" . $herecurr); 25903a3c9242SWarner Losh } 25913a3c9242SWarner Losh 25923a3c9242SWarner Losh# check for gcc specific __FUNCTION__ 25933a3c9242SWarner Losh if ($line =~ /__FUNCTION__/) { 25943a3c9242SWarner Losh ERROR("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); 25953a3c9242SWarner Losh } 25963a3c9242SWarner Losh 25973a3c9242SWarner Losh# recommend sigaction over signal for portability, when establishing a handler 25983a3c9242SWarner Losh if ($line =~ /\bsignal\s*\(/ && !($line =~ /SIG_(?:IGN|DFL)/)) { 25993a3c9242SWarner Losh ERROR("use sigaction to establish signal handlers; signal is not portable\n" . $herecurr); 26003a3c9242SWarner Losh } 26013a3c9242SWarner Losh 26023a3c9242SWarner Losh# format strings checks 26033a3c9242SWarner Losh my $string; 26043a3c9242SWarner Losh while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { 26053a3c9242SWarner Losh $string = substr($rawline, $-[1], $+[1] - $-[1]); 26063a3c9242SWarner Losh $string =~ s/%%/__/g; 26073a3c9242SWarner Losh # check for %L{u,d,i} in strings 26083a3c9242SWarner Losh if ($string =~ /(?<!%)%L[udi]/) { 26093a3c9242SWarner Losh ERROR("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); 26103a3c9242SWarner Losh } 26113a3c9242SWarner Losh } 26123a3c9242SWarner Losh 26133a3c9242SWarner Losh # Continue checking for error messages that contains newlines. This 26143a3c9242SWarner Losh # check handles cases where string literals are spread over multiple lines. 26153a3c9242SWarner Losh # Example: 26163a3c9242SWarner Losh # error_report("Error msg line #1" 26173a3c9242SWarner Losh # "Error msg line #2\n"); 26183a3c9242SWarner Losh my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"}; 26193a3c9242SWarner Losh my $continued_str_literal = qr{\+\s*\".*\"}; 26203a3c9242SWarner Losh 26213a3c9242SWarner Losh if ($rawline =~ /$quoted_newline_regex/) { 26223a3c9242SWarner Losh # Backtrack to first line that does not contain only a quoted literal 26233a3c9242SWarner Losh # and assume that it is the start of the statement. 26243a3c9242SWarner Losh my $i = $linenr - 2; 26253a3c9242SWarner Losh 26263a3c9242SWarner Losh while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) { 26273a3c9242SWarner Losh $i--; 26283a3c9242SWarner Losh } 26293a3c9242SWarner Losh } 26303a3c9242SWarner Losh 26313a3c9242SWarner Losh } 26323a3c9242SWarner Losh 26333a3c9242SWarner Losh # If we have no input at all, then there is nothing to report on 26343a3c9242SWarner Losh # so just keep quiet. 26353a3c9242SWarner Losh if ($#rawlines == -1) { 26363a3c9242SWarner Losh return 1; 26373a3c9242SWarner Losh } 26383a3c9242SWarner Losh 26393a3c9242SWarner Losh # In mailback mode only produce a report in the negative, for 26403a3c9242SWarner Losh # things that appear to be patches. 26413a3c9242SWarner Losh if ($mailback && ($clean == 1 || !$is_patch)) { 26423a3c9242SWarner Losh return 1; 26433a3c9242SWarner Losh } 26443a3c9242SWarner Losh 26453a3c9242SWarner Losh # This is not a patch, and we are are in 'no-patch' mode so 26463a3c9242SWarner Losh # just keep quiet. 26473a3c9242SWarner Losh if (!$chk_patch && !$is_patch) { 26483a3c9242SWarner Losh return 1; 26493a3c9242SWarner Losh } 26503a3c9242SWarner Losh 26513a3c9242SWarner Losh if (!$is_patch && $filename !~ /cover-letter\.patch$/) { 26523a3c9242SWarner Losh ERROR("Does not appear to be a unified-diff format patch\n"); 26533a3c9242SWarner Losh } 26543a3c9242SWarner Losh 26553a3c9242SWarner Losh print report_dump(); 26563a3c9242SWarner Losh if ($summary && !($clean == 1 && $quiet == 1)) { 26573a3c9242SWarner Losh print "$filename " if ($summary_file); 26583a3c9242SWarner Losh print "total: $cnt_error errors, $cnt_warn warnings, " . 26593a3c9242SWarner Losh "$cnt_lines lines checked\n"; 26603a3c9242SWarner Losh print "\n" if ($quiet == 0); 26613a3c9242SWarner Losh } 26623a3c9242SWarner Losh 26633a3c9242SWarner Losh if ($quiet == 0) { 26643a3c9242SWarner Losh # If there were whitespace errors which cleanpatch can fix 26653a3c9242SWarner Losh # then suggest that. 26663a3c9242SWarner Losh# if ($rpt_cleaners) { 26673a3c9242SWarner Losh# print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; 26683a3c9242SWarner Losh# print " scripts/cleanfile\n\n"; 26693a3c9242SWarner Losh# } 26703a3c9242SWarner Losh } 26713a3c9242SWarner Losh 26723a3c9242SWarner Losh if ($clean == 1 && $quiet == 0) { 26733a3c9242SWarner Losh print "$vname has no obvious style problems and is ready for submission.\n" 26743a3c9242SWarner Losh } 26753a3c9242SWarner Losh 26763a3c9242SWarner Losh return ($no_warnings ? $clean : $cnt_error == 0); 26773a3c9242SWarner Losh} 2678