mistress emilia9/dotfiles / cddl / cstyle
   1#!/usr/bin/perl -w
   2#
   3# CDDL HEADER START
   4#
   5# The contents of this file are subject to the terms of the
   6# Common Development and Distribution License (the "License").
   7# You may not use this file except in compliance with the License.
   8#
   9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10# or http://www.opensolaris.org/os/licensing.
  11# See the License for the specific language governing permissions
  12# and limitations under the License.
  13#
  14# When distributing Covered Code, include this CDDL HEADER in each
  15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16# If applicable, add the following below this CDDL HEADER, with the
  17# fields enclosed by brackets "[]" replaced with your own identifying
  18# information: Portions Copyright [yyyy] [name of copyright owner]
  19#
  20# CDDL HEADER END
  21#
  22# Copyright 2015 Toomas Soome <tsoome@me.com>
  23# Copyright 2016 Nexenta Systems, Inc.
  24# Copyright 2023 Oxide Computer Company
  25#
  26# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  27# Use is subject to license terms.
  28#
  29# Copyright (c) 2015 by Delphix. All rights reserved.
  30#
  31# @(#)cstyle 1.58 98/09/09 (from shannon)
  32#
  33# cstyle - check for some common stylistic errors.
  34#
  35#	cstyle is a sort of "lint" for C coding style.
  36#	It attempts to check for the style used in the
  37#	kernel, sometimes known as "Bill Joy Normal Form".
  38#
  39#	There's a lot this can't check for, like proper indentation
  40#	of code blocks.  There's also a lot more this could check for.
  41#
  42#	A note to the non perl literate:
  43#
  44#		perl regular expressions are pretty much like egrep
  45#		regular expressions, with the following special symbols
  46#
  47#		\s	any space character
  48#		\S	any non-space character
  49#		\w	any "word" character [a-zA-Z0-9_]
  50#		\W	any non-word character
  51#		\d	a digit [0-9]
  52#		\D	a non-digit
  53#		\b	word boundary (between \w and \W)
  54#		\B	non-word boundary
  55#
  56
  57require 5.0;
  58use IO::File;
  59use Getopt::Std;
  60use strict;
  61
  62my $usage =
  63"usage: cstyle [-chpvCP] [-o constructs] file ...
  64	-c	check continuation indentation inside functions
  65	-h	perform heuristic checks that are sometimes wrong
  66	-p	perform some of the more picky checks
  67	-v	verbose
  68	-C	don't check anything in header block comments
  69	-P	check for use of non-POSIX types
  70	-o constructs
  71		allow a comma-seperated list of optional constructs:
  72		    doxygen	allow doxygen-style block comments (/** /*!)
  73		    splint	allow splint-style lint comments (/*@ ... @*/)
  74";
  75
  76my %opts;
  77
  78if (!getopts("cho:pvCP", \%opts)) {
  79	print $usage;
  80	exit 2;
  81}
  82
  83my $check_continuation = $opts{'c'};
  84my $heuristic = $opts{'h'};
  85my $picky = $opts{'p'};
  86my $verbose = $opts{'v'};
  87my $ignore_hdr_comment = $opts{'C'};
  88my $check_posix_types = $opts{'P'};
  89
  90my $doxygen_comments = 0;
  91my $splint_comments = 0;
  92
  93if (defined($opts{'o'})) {
  94	for my $x (split /,/, $opts{'o'}) {
  95		if ($x eq "doxygen") {
  96			$doxygen_comments = 1;
  97		} elsif ($x eq "splint") {
  98			$splint_comments = 1;
  99		} else {
 100			print "cstyle: unrecognized construct \"$x\"\n";
 101			print $usage;
 102			exit 2;
 103		}
 104	}
 105}
 106
 107my ($filename, $line, $prev);		# shared globals
 108
 109my $fmt;
 110my $hdr_comment_start;
 111
 112if ($verbose) {
 113	$fmt = "%s: %d: %s\n%s\n";
 114} else {
 115	$fmt = "%s: %d: %s\n";
 116}
 117
 118if ($doxygen_comments) {
 119	# doxygen comments look like "/*!" or "/**"; allow them.
 120	$hdr_comment_start = qr/^\s*\/\*[\!\*]?$/;
 121} else {
 122	$hdr_comment_start = qr/^\s*\/\*$/;
 123}
 124
 125# FreeBSD uses comments styled as such for their license headers:
 126# /*-
 127#  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
 128#  *
 129#  ...
 130#
 131# In order to apply other cstyle checks to those files without stumbling over
 132# the license header, tolerate such comment openings as well.
 133my $fbsd_comment_start = qr/^\s*\/\*-$/;
 134
 135# Note, following must be in single quotes so that \s and \w work right.
 136my $typename = '(int|char|short|long|unsigned|float|double' .
 137    '|\w+_t|struct\s+\w+|union\s+\w+|FILE)';
 138
 139# mapping of old types to POSIX compatible types
 140my %old2posix = (
 141	'unchar' => 'uchar_t',
 142	'ushort' => 'ushort_t',
 143	'uint' => 'uint_t',
 144	'ulong' => 'ulong_t',
 145	'u_int' => 'uint_t',
 146	'u_short' => 'ushort_t',
 147	'u_long' => 'ulong_t',
 148	'u_char' => 'uchar_t',
 149	'u_int8_t' => 'uint8_t',
 150	'u_int16_t' => 'uint16_t',
 151	'u_int32_t' => 'uint32_t',
 152	'u_int64_t' => 'uint64_t',
 153	'u_quad_t' => 'uint64_t',
 154	'quad' => 'quad_t'
 155);
 156
 157my $lint_re = qr/\/\*(?:
 158	ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
 159	CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|
 160	FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*|
 161	PROTOLIB[0-9]*|SCANFLIKE[0-9]*|CSTYLED.*?
 162    )\*\//x;
 163
 164my $splint_re = qr/\/\*@.*?@\*\//x;
 165
 166my $warlock_re = qr/\/\*\s*(?:
 167	VARIABLES\ PROTECTED\ BY|
 168	MEMBERS\ PROTECTED\ BY|
 169	ALL\ MEMBERS\ PROTECTED\ BY|
 170	READ-ONLY\ VARIABLES:|
 171	READ-ONLY\ MEMBERS:|
 172	VARIABLES\ READABLE\ WITHOUT\ LOCK:|
 173	MEMBERS\ READABLE\ WITHOUT\ LOCK:|
 174	LOCKS\ COVERED\ BY|
 175	LOCK\ UNNEEDED\ BECAUSE|
 176	LOCK\ NEEDED:|
 177	LOCK\ HELD\ ON\ ENTRY:|
 178	READ\ LOCK\ HELD\ ON\ ENTRY:|
 179	WRITE\ LOCK\ HELD\ ON\ ENTRY:|
 180	LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
 181	READ\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
 182	WRITE\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
 183	LOCK\ RELEASED\ AS\ SIDE\ EFFECT:|
 184	LOCK\ UPGRADED\ AS\ SIDE\ EFFECT:|
 185	LOCK\ DOWNGRADED\ AS\ SIDE\ EFFECT:|
 186	FUNCTIONS\ CALLED\ THROUGH\ POINTER|
 187	FUNCTIONS\ CALLED\ THROUGH\ MEMBER|
 188	LOCK\ ORDER:
 189    )/x;
 190
 191my $err_stat = 0;		# exit status
 192
 193if ($#ARGV >= 0) {
 194	foreach my $arg (@ARGV) {
 195		my $fh = new IO::File $arg, "r";
 196		if (!defined($fh)) {
 197			printf "%s: can not open\n", $arg;
 198		} else {
 199			&cstyle($arg, $fh);
 200			close $fh;
 201		}
 202	}
 203} else {
 204	&cstyle("<stdin>", *STDIN);
 205}
 206exit $err_stat;
 207
 208my $no_errs = 0;		# set for CSTYLED-protected lines
 209
 210sub err($) {
 211	my ($error) = @_;
 212	unless ($no_errs) {
 213		if ($verbose) {
 214			printf $fmt, $filename, $., $error, $line;
 215		} else {
 216			printf $fmt, $filename, $., $error;
 217		}
 218		$err_stat = 1;
 219	}
 220}
 221
 222sub err_prefix($$) {
 223	my ($prevline, $error) = @_;
 224	my $out = $prevline."\n".$line;
 225	unless ($no_errs) {
 226		if ($verbose) {
 227			printf $fmt, $filename, $., $error, $out;
 228		} else {
 229			printf $fmt, $filename, $., $error;
 230		}
 231		$err_stat = 1;
 232	}
 233}
 234
 235sub err_prev($) {
 236	my ($error) = @_;
 237	unless ($no_errs) {
 238		if ($verbose) {
 239			printf $fmt, $filename, $. - 1, $error, $prev;
 240		} else {
 241			printf $fmt, $filename, $. - 1, $error;
 242		}
 243		$err_stat = 1;
 244	}
 245}
 246
 247sub cstyle($$) {
 248
 249my ($fn, $filehandle) = @_;
 250$filename = $fn;			# share it globally
 251
 252my $in_cpp = 0;
 253my $next_in_cpp = 0;
 254
 255my $in_comment = 0;
 256my $in_header_comment = 0;
 257my $comment_done = 0;
 258my $in_warlock_comment = 0;
 259my $in_function = 0;
 260my $in_function_header = 0;
 261my $function_header_full_indent = 0;
 262my $in_declaration = 0;
 263my $note_level = 0;
 264my $nextok = 0;
 265my $nocheck = 0;
 266
 267my $in_string = 0;
 268
 269my ($okmsg, $comment_prefix);
 270
 271$line = '';
 272$prev = '';
 273reset_indent();
 274
 275line: while (<$filehandle>) {
 276	s/\r?\n$//;	# strip return and newline
 277
 278	# save the original line, then remove all text from within
 279	# double or single quotes, we do not want to check such text.
 280
 281	$line = $_;
 282
 283	#
 284	# C allows strings to be continued with a backslash at the end of
 285	# the line.  We translate that into a quoted string on the previous
 286	# line followed by an initial quote on the next line.
 287	#
 288	# (we assume that no-one will use backslash-continuation with character
 289	# constants)
 290	#
 291	$_ = '"' . $_		if ($in_string && !$nocheck && !$in_comment);
 292
 293	#
 294	# normal strings and characters
 295	#
 296	s/'([^\\']|\\[^xX0]|\\0[0-9]*|\\[xX][0-9a-fA-F]*)'/''/g;
 297	s/"([^\\"]|\\.)*"/\"\"/g;
 298
 299	#
 300	# detect string continuation
 301	#
 302	if ($nocheck || $in_comment) {
 303		$in_string = 0;
 304	} else {
 305		#
 306		# Now that all full strings are replaced with "", we check
 307		# for unfinished strings continuing onto the next line.
 308		#
 309		$in_string =
 310		    (s/([^"](?:"")*)"([^\\"]|\\.)*\\$/$1""/ ||
 311		    s/^("")*"([^\\"]|\\.)*\\$/""/);
 312	}
 313
 314	#
 315	# figure out if we are in a cpp directive
 316	#
 317	$in_cpp = $next_in_cpp || /^\s*#/;	# continued or started
 318	$next_in_cpp = $in_cpp && /\\$/;	# only if continued
 319
 320	# strip off trailing backslashes, which appear in long macros
 321	s/\s*\\$//;
 322
 323	# an /* END CSTYLED */ comment ends a no-check block.
 324	if ($nocheck) {
 325		if (/\/\* *END *CSTYLED *\*\//) {
 326			$nocheck = 0;
 327		} else {
 328			reset_indent();
 329			next line;
 330		}
 331	}
 332
 333	# a /*CSTYLED*/ comment indicates that the next line is ok.
 334	if ($nextok) {
 335		if ($okmsg) {
 336			err($okmsg);
 337		}
 338		$nextok = 0;
 339		$okmsg = 0;
 340		if (/\/\* *CSTYLED.*\*\//) {
 341			/^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
 342			$okmsg = $1;
 343			$nextok = 1;
 344		}
 345		$no_errs = 1;
 346	} elsif ($no_errs) {
 347		$no_errs = 0;
 348	}
 349
 350	# check length of line.
 351	# first, a quick check to see if there is any chance of being too long.
 352	if (($line =~ tr/\t/\t/) * 7 + length($line) > 80) {
 353		# yes, there is a chance.
 354		# replace tabs with spaces and check again.
 355		my $eline = $line;
 356		1 while $eline =~
 357		    s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
 358		if (length($eline) > 80) {
 359			err("line > 80 characters");
 360		}
 361	}
 362
 363	# ignore NOTE(...) annotations (assumes NOTE is on lines by itself).
 364	if ($note_level || /\b_?NOTE\s*\(/) { # if in NOTE or this is NOTE
 365		s/[^()]//g;			  # eliminate all non-parens
 366		$note_level += s/\(//g - length;  # update paren nest level
 367		next;
 368	}
 369
 370	# a /* BEGIN CSTYLED */ comment starts a no-check block.
 371	if (/\/\* *BEGIN *CSTYLED *\*\//) {
 372		$nocheck = 1;
 373	}
 374
 375	# a /*CSTYLED*/ comment indicates that the next line is ok.
 376	if (/\/\* *CSTYLED.*\*\//) {
 377		/^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
 378		$okmsg = $1;
 379		$nextok = 1;
 380	}
 381	if (/\/\/ *CSTYLED/) {
 382		/^.*\/\/ *CSTYLED *(.*)$/;
 383		$okmsg = $1;
 384		$nextok = 1;
 385	}
 386
 387	# universal checks; apply to everything
 388	if (/\t +\t/) {
 389		err("spaces between tabs");
 390	}
 391	if (/ \t+ /) {
 392		err("tabs between spaces");
 393	}
 394	if (/\s$/) {
 395		err("space or tab at end of line");
 396	}
 397	if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
 398		err("comment preceded by non-blank");
 399	}
 400
 401	# is this the beginning or ending of a function?
 402	# (not if "struct foo\n{\n")
 403	if (/^\{$/ && $prev =~ /\)\s*(const\s*)?(\/\*.*\*\/\s*)?\\?$/) {
 404		$in_function = 1;
 405		$in_declaration = 1;
 406		$in_function_header = 0;
 407		$function_header_full_indent = 0;
 408		$prev = $line;
 409		next line;
 410	}
 411	if (/^\}\s*(\/\*.*\*\/\s*)*$/) {
 412		if ($prev =~ /^\s*return\s*;/) {
 413			err_prev("unneeded return at end of function");
 414		}
 415		$in_function = 0;
 416		reset_indent();		# we don't check between functions
 417		$prev = $line;
 418		next line;
 419	}
 420	if ($in_function_header && ! /^    (\w|\.)/ ) {
 421		if (/^\{\}$/) {
 422			$in_function_header = 0;
 423			$function_header_full_indent = 0;
 424		} elsif ($picky && ! (/^\t/ && $function_header_full_indent != 0)) {
 425			err("continuation line should be indented by 4 spaces");
 426		}
 427	}
 428
 429	#
 430	# If this matches something of form "foo(", it's probably a function
 431	# definition, unless it ends with ") bar;", in which case it's a declaration
 432	# that uses a macro to generate the type.
 433	#
 434	if (/^\w+\(/ && !/\) \w+;$/) {
 435		$in_function_header = 1;
 436		if (/\($/) {
 437			$function_header_full_indent = 1;
 438		}
 439	}
 440	if ($in_function_header && /^\{$/) {
 441		$in_function_header = 0;
 442		$function_header_full_indent = 0;
 443		$in_function = 1;
 444	}
 445	if ($in_function_header && /\);$/) {
 446		$in_function_header = 0;
 447		$function_header_full_indent = 0;
 448	}
 449	if ($in_function_header && /\{$/ ) {
 450		if ($picky) {
 451			err("opening brace on same line as function header");
 452		}
 453		$in_function_header = 0;
 454		$function_header_full_indent = 0;
 455		$in_function = 1;
 456		next line;
 457	}
 458
 459	if ($in_warlock_comment && /\*\//) {
 460		$in_warlock_comment = 0;
 461		$prev = $line;
 462		next line;
 463	}
 464
 465	# a blank line terminates the declarations within a function.
 466	# XXX - but still a problem in sub-blocks.
 467	if ($in_declaration && /^$/) {
 468		$in_declaration = 0;
 469	}
 470
 471	if ($comment_done) {
 472		$in_comment = 0;
 473		$in_header_comment = 0;
 474		$comment_done = 0;
 475	}
 476	# does this looks like the start of a block comment?
 477	if (/$hdr_comment_start/ || /$fbsd_comment_start/) {
 478		if (!/^\t*\/\*/) {
 479			err("block comment not indented by tabs");
 480		}
 481		$in_comment = 1;
 482		/^(\s*)\//;
 483		$comment_prefix = $1;
 484		if ($comment_prefix eq "") {
 485			$in_header_comment = 1;
 486		}
 487		$prev = $line;
 488		next line;
 489	}
 490	# are we still in the block comment?
 491	if ($in_comment) {
 492		if (/^$comment_prefix \*\/$/) {
 493			$comment_done = 1;
 494		} elsif (/\*\//) {
 495			$comment_done = 1;
 496			err("improper block comment close")
 497			    unless ($ignore_hdr_comment && $in_header_comment);
 498		} elsif (!/^$comment_prefix \*[ \t]/ &&
 499		    !/^$comment_prefix \*$/) {
 500			err("improper block comment")
 501			    unless ($ignore_hdr_comment && $in_header_comment);
 502		}
 503	}
 504
 505	if ($in_header_comment && $ignore_hdr_comment) {
 506		$prev = $line;
 507		next line;
 508	}
 509
 510	# check for errors that might occur in comments and in code.
 511
 512	# allow spaces to be used to draw pictures in header comments.
 513	if (/[^ ]     / && !/".*     .*"/ && !$in_header_comment) {
 514		err("spaces instead of tabs");
 515	}
 516	if (/^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
 517	    (!/^    (\w|\.)/ || $in_function != 0)) {
 518		err("indent by spaces instead of tabs");
 519	}
 520	if (/^\t+ [^ \t\*]/ || /^\t+  \S/ || /^\t+   \S/) {
 521		err("continuation line not indented by 4 spaces");
 522	}
 523	if (/$warlock_re/ && !/\*\//) {
 524		$in_warlock_comment = 1;
 525		$prev = $line;
 526		next line;
 527	}
 528	if (/^\s*\/\*./ && !/^\s*\/\*.*\*\// && !/$hdr_comment_start/) {
 529		err("improper first line of block comment");
 530	}
 531
 532	if ($in_comment) {	# still in comment, don't do further checks
 533		$prev = $line;
 534		next line;
 535	}
 536
 537	if ((/[^(]\/\*\S/ || /^\/\*\S/) &&
 538	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
 539		err("missing blank after open comment");
 540	}
 541	if (/\S\*\/[^)]|\S\*\/$/ &&
 542	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
 543		err("missing blank before close comment");
 544	}
 545	if (/\/\/\S/) {		# C++ comments
 546		err("missing blank after start comment");
 547	}
 548	# check for unterminated single line comments, but allow them when
 549	# they are used to comment out the argument list of a function
 550	# declaration.
 551	if (/\S.*\/\*/ && !/\S.*\/\*.*\*\// && !/\(\/\*/) {
 552		err("unterminated single line comment");
 553	}
 554
 555	if (/^(#else|#endif|#include)(.*)$/) {
 556		$prev = $line;
 557		if ($picky) {
 558			my $directive = $1;
 559			my $clause = $2;
 560			# Enforce ANSI rules for #else and #endif: no noncomment
 561			# identifiers are allowed after #endif or #else.  Allow
 562			# C++ comments since they seem to be a fact of life.
 563			if ((($1 eq "#endif") || ($1 eq "#else")) &&
 564			    ($clause ne "") &&
 565			    (!($clause =~ /^\s+\/\*.*\*\/$/)) &&
 566			    (!($clause =~ /^\s+\/\/.*$/))) {
 567				err("non-comment text following " .
 568				    "$directive (or malformed $directive " .
 569				    "directive)");
 570			}
 571		}
 572		next line;
 573	}
 574
 575	#
 576	# delete any comments and check everything else.  Note that
 577	# ".*?" is a non-greedy match, so that we don't get confused by
 578	# multiple comments on the same line.
 579	#
 580	s/\/\*.*?\*\///g;
 581	s/\/\/.*$//;		# C++ comments
 582
 583	# delete any trailing whitespace; we have already checked for that.
 584	s/\s*$//;
 585
 586	# following checks do not apply to text in comments.
 587
 588	if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=[^\s,]/ ||
 589	    (/[^->]>[^,=>\s]/ && !/[^->]>$/) ||
 590	    (/[^<]<[^,=<\s]/ && !/[^<]<$/) ||
 591	    /[^<\s]<[^<]/ || /[^->\s]>[^>]/) {
 592		err("missing space around relational operator");
 593	}
 594	if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ ||
 595	    (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) ||
 596	    (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) {
 597		# XXX - should only check this for C++ code
 598		# XXX - there are probably other forms that should be allowed
 599		if (!/\soperator=/) {
 600			err("missing space around assignment operator");
 601		}
 602	}
 603	if (/[,;]\S/ && !/\bfor \(;;\)/) {
 604		err("comma or semicolon followed by non-blank");
 605	}
 606	# allow "for" statements to have empty "while" clauses
 607	if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
 608		err("comma or semicolon preceded by blank");
 609	}
 610	if (/^\s*(&&|\|\|)/) {
 611		err("improper boolean continuation");
 612	}
 613	if (/\S   *(&&|\|\|)/ || /(&&|\|\|)   *\S/) {
 614		err("more than one space around boolean operator");
 615	}
 616	if (/\b(for|if|while|switch|sizeof|alignof|return|case)\(/) {
 617		err("missing space between keyword and paren");
 618	}
 619	if (/(\b(for|if|while|switch|return)\b.*){2,}/ && !/^#define/) {
 620		# multiple "case" and "sizeof" allowed
 621		err("more than one keyword on line");
 622	}
 623	if (/\b(for|if|while|switch|sizeof|alignof|return|case)\s\s+\(/ &&
 624	    !/^#if\s+\(/) {
 625		err("extra space between keyword and paren");
 626	}
 627	# try to detect "func (x)" but not "if (x)" or
 628	# "#define foo (x)" or "int (*func)();"
 629	if (/\w\s\(/) {
 630		my $s = $_;
 631		# strip off all keywords on the line
 632		s/\b(for|if|while|switch|return|case|alignof|sizeof)\s\(/XXX(/g;
 633		s/#elif\s\(/XXX(/g;
 634		s/^#define\s+\w+\s+\(/XXX(/;
 635		# do not match things like "void (*f)();"
 636		# or "typedef void (func_t)();"
 637		s/\w\s\(+\*/XXX(*/g;
 638		s/\b($typename|void)\s+\(+/XXX(/og;
 639		if (/\w\s\(/) {
 640			err("extra space between function name and left paren");
 641		}
 642		$_ = $s;
 643	}
 644	# try to detect "int foo(x)", but not "extern int foo(x);"
 645	# XXX - this still trips over too many legitimate things,
 646	# like "int foo(x,\n\ty);"
 647#		if (/^(\w+(\s|\*)+)+\w+\(/ && !/\)[;,](\s|)*$/ &&
 648#		    !/^(extern|static)\b/) {
 649#			err("return type of function not on separate line");
 650#		}
 651	# this is a close approximation
 652	if (/^(\w+(\s|\*)+)+\w+\(.*\)(\s|)*$/ &&
 653	    !/^(extern|static)\b/) {
 654		err("return type of function not on separate line");
 655	}
 656	if (/^#define /) {
 657		err("#define followed by space instead of tab");
 658	}
 659	if (/^\s*return\W[^;]*;/ && !/^\s*return\s*\(.*\);/) {
 660		err("unparenthesized return expression");
 661	}
 662	if (/\bsizeof\b/ && !/\bsizeof\s*\(.*\)/) {
 663		err("unparenthesized sizeof expression");
 664	}
 665	if (/\balignof\b/ && !/\balignof\s*\(.*\)/) {
 666		err("unparenthesized alignof expression");
 667	}
 668	if (/\(\s/) {
 669		err("whitespace after left paren");
 670	}
 671	# allow "for" statements to have empty "continue" clauses
 672	if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) {
 673		err("whitespace before right paren");
 674	}
 675	if (/^\s*\(void\)[^ ]/) {
 676		err("missing space after (void) cast");
 677	}
 678	if (/\S\{/ && !/\{\{/) {
 679		err("missing space before left brace");
 680	}
 681	if ($in_function && /^\s+\{/ &&
 682	    ($prev =~ /\)\s*$/ || $prev =~ /\bstruct\s+\w+$/)) {
 683		err("left brace starting a line");
 684	}
 685	if (/\}(else|while)/) {
 686		err("missing space after right brace");
 687	}
 688	if (/\}\s\s+(else|while)/) {
 689		err("extra space after right brace");
 690	}
 691	if (/\b_VOID\b|\bVOID\b|\bSTATIC\b/) {
 692		err("obsolete use of VOID or STATIC");
 693	}
 694	if (/\b$typename\*/o) {
 695		err("missing space between type name and *");
 696	}
 697	if (/^\s+#/) {
 698		err("preprocessor statement not in column 1");
 699	}
 700	if (/^#\s/) {
 701		err("blank after preprocessor #");
 702	}
 703	if (/!\s*(strcmp|strncmp|bcmp)\s*\(/) {
 704		err("don't use boolean ! with comparison functions");
 705	}
 706
 707	#
 708	# We completely ignore, for purposes of indentation:
 709	#  * lines outside of functions
 710	#  * preprocessor lines
 711	#
 712	if ($check_continuation && $in_function && !$in_cpp) {
 713		process_indent($_);
 714	}
 715	if ($picky) {
 716		# try to detect spaces after casts, but allow (e.g.)
 717		# "sizeof (int) + 1", "void (*funcptr)(int) = foo;", and
 718		# "int foo(int) __NORETURN;"
 719		if ((/^\($typename( \*+)?\)\s/o ||
 720		    /\W\($typename( \*+)?\)\s/o) &&
 721		    !/sizeof\s*\($typename( \*)?\)\s/o &&
 722		    !/\($typename( \*+)?\)\s+=[^=]/o) {
 723			err("space after cast");
 724		}
 725		if (/\b$typename\s*\*\s/o &&
 726		    !/\b$typename\s*\*\s+const\b/o) {
 727			err("unary * followed by space");
 728		}
 729	}
 730	if ($check_posix_types) {
 731		# try to detect old non-POSIX types.
 732		# POSIX requires all non-standard typedefs to end in _t,
 733		# but historically these have been used.
 734		my $types = join '|', keys %old2posix;
 735		if (/\b($types)\b/) {
 736			err("non-POSIX typedef $1 used: use $old2posix{$1} instead");
 737		}
 738	}
 739	if ($heuristic) {
 740		# cannot check this everywhere due to "struct {\n...\n} foo;"
 741		if ($in_function && !$in_declaration &&
 742		    /\}./ && !/\}\s+=/ && !/\{.*\}[;,]$/ && !/\}(\s|)*$/ &&
 743		    !/\} (else|while)/ && !/\}\}/) {
 744			err("possible bad text following right brace");
 745		}
 746		# cannot check this because sub-blocks in
 747		# the middle of code are ok
 748		if ($in_function && /^\s+\{/) {
 749			err("possible left brace starting a line");
 750		}
 751	}
 752	if (/^\s*else\W/) {
 753		if ($prev =~ /^\s*\}$/) {
 754			err_prefix($prev,
 755			    "else and right brace should be on same line");
 756		}
 757	}
 758	$prev = $line;
 759}
 760
 761if ($prev eq "") {
 762	err("last line in file is blank");
 763}
 764
 765}
 766
 767#
 768# Continuation-line checking
 769#
 770# The rest of this file contains the code for the continuation checking
 771# engine.  It's a pretty simple state machine which tracks the expression
 772# depth (unmatched '('s and '['s).
 773#
 774# Keep in mind that the argument to process_indent() has already been heavily
 775# processed; all comments have been replaced by control-A, and the contents of
 776# strings and character constants have been elided.
 777#
 778
 779my $cont_in;		# currently inside of a continuation
 780my $cont_off;		# skipping an initializer or definition
 781my $cont_noerr;		# suppress cascading errors
 782my $cont_start;		# the line being continued
 783my $cont_base;		# the base indentation
 784my $cont_first;		# this is the first line of a statement
 785my $cont_multiseg;	# this continuation has multiple segments
 786
 787my $cont_special;	# this is a C statement (if, for, etc.)
 788my $cont_macro;		# this is a macro
 789my $cont_case;		# this is a multi-line case
 790
 791my @cont_paren;		# the stack of unmatched ( and [s we've seen
 792
 793sub
 794reset_indent()
 795{
 796	$cont_in = 0;
 797	$cont_off = 0;
 798}
 799
 800sub
 801delabel($)
 802{
 803	#
 804	# replace labels with tabs.  Note that there may be multiple
 805	# labels on a line.
 806	#
 807	local $_ = $_[0];
 808
 809	while (/^(\t*)( *(?:(?:\w+\s*)|(?:case\b[^:]*)): *)(.*)$/) {
 810		my ($pre_tabs, $label, $rest) = ($1, $2, $3);
 811		$_ = $pre_tabs;
 812		while ($label =~ s/^([^\t]*)(\t+)//) {
 813			$_ .= "\t" x (length($2) + length($1) / 8);
 814		}
 815		$_ .= ("\t" x (length($label) / 8)).$rest;
 816	}
 817
 818	return ($_);
 819}
 820
 821sub
 822process_indent($)
 823{
 824	require strict;
 825	local $_ = $_[0];			# preserve the global $_
 826
 827	s///g;	# No comments
 828	s/\s+$//;	# Strip trailing whitespace
 829
 830	return			if (/^$/);	# skip empty lines
 831
 832	# regexps used below; keywords taking (), macros, and continued cases
 833	my $special = '(?:(?:\}\s*)?else\s+)?(?:if|for|while|switch)\b';
 834	my $macro = '[A-Z_][A-Z_0-9]*\(';
 835	my $case = 'case\b[^:]*$';
 836
 837	# skip over enumerations, array definitions, initializers, etc.
 838	if ($cont_off <= 0 && !/^\s*$special/ &&
 839	    (/(?:(?:\b(?:enum|struct|union)\s*[^\{]*)|(?:\s+=\s*))\{/ ||
 840	    (/^\s*\{/ && $prev =~ /=\s*(?:\/\*.*\*\/\s*)*$/))) {
 841		$cont_in = 0;
 842		$cont_off = tr/{/{/ - tr/}/}/;
 843		return;
 844	}
 845	if ($cont_off) {
 846		$cont_off += tr/{/{/ - tr/}/}/;
 847		return;
 848	}
 849
 850	if (!$cont_in) {
 851		$cont_start = $line;
 852
 853		if (/^\t* /) {
 854			err("non-continuation indented 4 spaces");
 855			$cont_noerr = 1;		# stop reporting
 856		}
 857		$_ = delabel($_);	# replace labels with tabs
 858
 859		# check if the statement is complete
 860		return		if (/^\s*\}?$/);
 861		return		if (/^\s*\}?\s*else\s*\{?$/);
 862		return		if (/^\s*do\s*\{?$/);
 863		return		if (/\{$/);
 864		return		if (/\}[,;]?$/);
 865
 866		# Allow macros on their own lines
 867		return		if (/^\s*[A-Z_][A-Z_0-9]*$/);
 868
 869		# cases we don't deal with, generally non-kosher
 870		if (/\{/) {
 871			err("stuff after {");
 872			return;
 873		}
 874
 875		# Get the base line, and set up the state machine
 876		/^(\t*)/;
 877		$cont_base = $1;
 878		$cont_in = 1;
 879		@cont_paren = ();
 880		$cont_first = 1;
 881		$cont_multiseg = 0;
 882
 883		# certain things need special processing
 884		$cont_special = /^\s*$special/? 1 : 0;
 885		$cont_macro = /^\s*$macro/? 1 : 0;
 886		$cont_case = /^\s*$case/? 1 : 0;
 887	} else {
 888		$cont_first = 0;
 889
 890		# Strings may be pulled back to an earlier (half-)tabstop
 891		unless ($cont_noerr || /^$cont_base    / ||
 892		    (/^\t*(?:    )?(?:gettext\()?\"/ && !/^$cont_base\t/)) {
 893			err_prefix($cont_start,
 894			    "continuation should be indented 4 spaces");
 895		}
 896	}
 897
 898	my $rest = $_;			# keeps the remainder of the line
 899
 900	#
 901	# The split matches 0 characters, so that each 'special' character
 902	# is processed separately.  Parens and brackets are pushed and
 903	# popped off the @cont_paren stack.  For normal processing, we wait
 904	# until a ; or { terminates the statement.  "special" processing
 905	# (if/for/while/switch) is allowed to stop when the stack empties,
 906	# as is macro processing.  Case statements are terminated with a :
 907	# and an empty paren stack.
 908	#
 909	foreach $_ (split /[^\(\)\[\]\{\}\;\:]*/) {
 910		next		if (length($_) == 0);
 911
 912		# rest contains the remainder of the line
 913		my $rxp = "[^\Q$_\E]*\Q$_\E";
 914		$rest =~ s/^$rxp//;
 915
 916		if (/\(/ || /\[/) {
 917			push @cont_paren, $_;
 918		} elsif (/\)/ || /\]/) {
 919			my $cur = $_;
 920			tr/\)\]/\(\[/;
 921
 922			my $old = (pop @cont_paren);
 923			if (!defined($old)) {
 924				err("unexpected '$cur'");
 925				$cont_in = 0;
 926				last;
 927			} elsif ($old ne $_) {
 928				err("'$cur' mismatched with '$old'");
 929				$cont_in = 0;
 930				last;
 931			}
 932
 933			#
 934			# If the stack is now empty, do special processing
 935			# for if/for/while/switch and macro statements.
 936			#
 937			next		if (@cont_paren != 0);
 938			if ($cont_special) {
 939				if ($rest =~ /^\s*\{?$/) {
 940					$cont_in = 0;
 941					last;
 942				}
 943				if ($rest =~ /^\s*;$/) {
 944					err("empty if/for/while body ".
 945					    "not on its own line");
 946					$cont_in = 0;
 947					last;
 948				}
 949				if (!$cont_first && $cont_multiseg == 1) {
 950					err_prefix($cont_start,
 951					    "multiple statements continued ".
 952					    "over multiple lines");
 953					$cont_multiseg = 2;
 954				} elsif ($cont_multiseg == 0) {
 955					$cont_multiseg = 1;
 956				}
 957				# We've finished this section, start
 958				# processing the next.
 959				goto section_ended;
 960			}
 961			if ($cont_macro) {
 962				if ($rest =~ /^$/) {
 963					$cont_in = 0;
 964					last;
 965				}
 966			}
 967		} elsif (/\;/) {
 968			if ($cont_case) {
 969				err("unexpected ;");
 970			} elsif (!$cont_special) {
 971				err("unexpected ;")	if (@cont_paren != 0);
 972				if (!$cont_first && $cont_multiseg == 1) {
 973					err_prefix($cont_start,
 974					    "multiple statements continued ".
 975					    "over multiple lines");
 976					$cont_multiseg = 2;
 977				} elsif ($cont_multiseg == 0) {
 978					$cont_multiseg = 1;
 979				}
 980				if ($rest =~ /^$/) {
 981					$cont_in = 0;
 982					last;
 983				}
 984				if ($rest =~ /^\s*special/) {
 985					err("if/for/while/switch not started ".
 986					    "on its own line");
 987				}
 988				goto section_ended;
 989			}
 990		} elsif (/\{/) {
 991			err("{ while in parens/brackets") if (@cont_paren != 0);
 992			err("stuff after {")		if ($rest =~ /[^\s}]/);
 993			$cont_in = 0;
 994			last;
 995		} elsif (/\}/) {
 996			err("} while in parens/brackets") if (@cont_paren != 0);
 997			if (!$cont_special && $rest !~ /^\s*(while|else)\b/) {
 998				if ($rest =~ /^$/) {
 999					err("unexpected }");
1000				} else {
1001					err("stuff after }");
1002				}
1003				$cont_in = 0;
1004				last;
1005			}
1006		} elsif (/\:/ && $cont_case && @cont_paren == 0) {
1007			err("stuff after multi-line case") if ($rest !~ /$^/);
1008			$cont_in = 0;
1009			last;
1010		}
1011		next;
1012section_ended:
1013		# End of a statement or if/while/for loop.  Reset
1014		# cont_special and cont_macro based on the rest of the
1015		# line.
1016		$cont_special = ($rest =~ /^\s*$special/)? 1 : 0;
1017		$cont_macro = ($rest =~ /^\s*$macro/)? 1 : 0;
1018		$cont_case = 0;
1019		next;
1020	}
1021	$cont_noerr = 0			if (!$cont_in);
1022}