xref: /freebsd-src/tools/build/checkstyle9.pl (revision ca363716fc492146978c8650b97862f94daab6bf)
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