17c478bd9Sstevel@tonic-gate#!/usr/bin/perl -w 27c478bd9Sstevel@tonic-gate# 37c478bd9Sstevel@tonic-gate# CDDL HEADER START 47c478bd9Sstevel@tonic-gate# 57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the 6cdf0c1d5Smjnelson# Common Development and Distribution License (the "License"). 7cdf0c1d5Smjnelson# You may not use this file except in compliance with the License. 87c478bd9Sstevel@tonic-gate# 97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate# and limitations under the License. 137c478bd9Sstevel@tonic-gate# 147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate# 207c478bd9Sstevel@tonic-gate# CDDL HEADER END 217c478bd9Sstevel@tonic-gate# 2294385aa4SToomas Soome# Copyright 2015 Toomas Soome <tsoome@me.com> 23c667d216SHans Rosenfeld# Copyright 2016 Nexenta Systems, Inc. 24*ed093b41SRobert Mustacchi# Copyright 2023 Oxide Computer Company 257c478bd9Sstevel@tonic-gate# 26cdf0c1d5Smjnelson# Copyright 2008 Sun Microsystems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate# Use is subject to license terms. 287c478bd9Sstevel@tonic-gate# 29c4567a61SPaul Dagnelie# Copyright (c) 2015 by Delphix. All rights reserved. 30c4567a61SPaul Dagnelie# 317c478bd9Sstevel@tonic-gate# @(#)cstyle 1.58 98/09/09 (from shannon) 327c478bd9Sstevel@tonic-gate# 337c478bd9Sstevel@tonic-gate# cstyle - check for some common stylistic errors. 347c478bd9Sstevel@tonic-gate# 357c478bd9Sstevel@tonic-gate# cstyle is a sort of "lint" for C coding style. 367c478bd9Sstevel@tonic-gate# It attempts to check for the style used in the 377c478bd9Sstevel@tonic-gate# kernel, sometimes known as "Bill Joy Normal Form". 387c478bd9Sstevel@tonic-gate# 397c478bd9Sstevel@tonic-gate# There's a lot this can't check for, like proper indentation 407c478bd9Sstevel@tonic-gate# of code blocks. There's also a lot more this could check for. 417c478bd9Sstevel@tonic-gate# 427c478bd9Sstevel@tonic-gate# A note to the non perl literate: 437c478bd9Sstevel@tonic-gate# 447c478bd9Sstevel@tonic-gate# perl regular expressions are pretty much like egrep 457c478bd9Sstevel@tonic-gate# regular expressions, with the following special symbols 467c478bd9Sstevel@tonic-gate# 477c478bd9Sstevel@tonic-gate# \s any space character 487c478bd9Sstevel@tonic-gate# \S any non-space character 497c478bd9Sstevel@tonic-gate# \w any "word" character [a-zA-Z0-9_] 507c478bd9Sstevel@tonic-gate# \W any non-word character 517c478bd9Sstevel@tonic-gate# \d a digit [0-9] 527c478bd9Sstevel@tonic-gate# \D a non-digit 537c478bd9Sstevel@tonic-gate# \b word boundary (between \w and \W) 547c478bd9Sstevel@tonic-gate# \B non-word boundary 557c478bd9Sstevel@tonic-gate# 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gaterequire 5.0; 587c478bd9Sstevel@tonic-gateuse IO::File; 597c478bd9Sstevel@tonic-gateuse Getopt::Std; 607c478bd9Sstevel@tonic-gateuse strict; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gatemy $usage = 633c2f5c48Sjwadams"usage: cstyle [-chpvCP] [-o constructs] file ... 647c478bd9Sstevel@tonic-gate -c check continuation indentation inside functions 657c478bd9Sstevel@tonic-gate -h perform heuristic checks that are sometimes wrong 667c478bd9Sstevel@tonic-gate -p perform some of the more picky checks 677c478bd9Sstevel@tonic-gate -v verbose 687c478bd9Sstevel@tonic-gate -C don't check anything in header block comments 697c478bd9Sstevel@tonic-gate -P check for use of non-POSIX types 703c2f5c48Sjwadams -o constructs 713c2f5c48Sjwadams allow a comma-seperated list of optional constructs: 723c2f5c48Sjwadams doxygen allow doxygen-style block comments (/** /*!) 733c2f5c48Sjwadams splint allow splint-style lint comments (/*@ ... @*/) 747c478bd9Sstevel@tonic-gate"; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gatemy %opts; 777c478bd9Sstevel@tonic-gate 783c2f5c48Sjwadamsif (!getopts("cho:pvCP", \%opts)) { 797c478bd9Sstevel@tonic-gate print $usage; 80cdf0c1d5Smjnelson exit 2; 817c478bd9Sstevel@tonic-gate} 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gatemy $check_continuation = $opts{'c'}; 847c478bd9Sstevel@tonic-gatemy $heuristic = $opts{'h'}; 857c478bd9Sstevel@tonic-gatemy $picky = $opts{'p'}; 867c478bd9Sstevel@tonic-gatemy $verbose = $opts{'v'}; 877c478bd9Sstevel@tonic-gatemy $ignore_hdr_comment = $opts{'C'}; 887c478bd9Sstevel@tonic-gatemy $check_posix_types = $opts{'P'}; 897c478bd9Sstevel@tonic-gate 903c2f5c48Sjwadamsmy $doxygen_comments = 0; 913c2f5c48Sjwadamsmy $splint_comments = 0; 923c2f5c48Sjwadams 933c2f5c48Sjwadamsif (defined($opts{'o'})) { 943c2f5c48Sjwadams for my $x (split /,/, $opts{'o'}) { 953c2f5c48Sjwadams if ($x eq "doxygen") { 963c2f5c48Sjwadams $doxygen_comments = 1; 973c2f5c48Sjwadams } elsif ($x eq "splint") { 983c2f5c48Sjwadams $splint_comments = 1; 993c2f5c48Sjwadams } else { 1003c2f5c48Sjwadams print "cstyle: unrecognized construct \"$x\"\n"; 1013c2f5c48Sjwadams print $usage; 102cdf0c1d5Smjnelson exit 2; 1033c2f5c48Sjwadams } 1043c2f5c48Sjwadams } 1053c2f5c48Sjwadams} 1063c2f5c48Sjwadams 107fcfad32eSPatrick Mooneymy ($filename, $line, $prev); # shared globals 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gatemy $fmt; 1103c2f5c48Sjwadamsmy $hdr_comment_start; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gateif ($verbose) { 1137c478bd9Sstevel@tonic-gate $fmt = "%s: %d: %s\n%s\n"; 1147c478bd9Sstevel@tonic-gate} else { 1157c478bd9Sstevel@tonic-gate $fmt = "%s: %d: %s\n"; 1167c478bd9Sstevel@tonic-gate} 1177c478bd9Sstevel@tonic-gate 1183c2f5c48Sjwadamsif ($doxygen_comments) { 1193c2f5c48Sjwadams # doxygen comments look like "/*!" or "/**"; allow them. 1203c2f5c48Sjwadams $hdr_comment_start = qr/^\s*\/\*[\!\*]?$/; 1213c2f5c48Sjwadams} else { 1223c2f5c48Sjwadams $hdr_comment_start = qr/^\s*\/\*$/; 1233c2f5c48Sjwadams} 1243c2f5c48Sjwadams 125dcbbe9e0SPatrick Mooney# FreeBSD uses comments styled as such for their license headers: 126dcbbe9e0SPatrick Mooney# /*- 127dcbbe9e0SPatrick Mooney# * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 128dcbbe9e0SPatrick Mooney# * 129dcbbe9e0SPatrick Mooney# ... 130dcbbe9e0SPatrick Mooney# 131dcbbe9e0SPatrick Mooney# In order to apply other cstyle checks to those files without stumbling over 132dcbbe9e0SPatrick Mooney# the license header, tolerate such comment openings as well. 133dcbbe9e0SPatrick Mooneymy $fbsd_comment_start = qr/^\s*\/\*-$/; 134dcbbe9e0SPatrick Mooney 1357c478bd9Sstevel@tonic-gate# Note, following must be in single quotes so that \s and \w work right. 1367c478bd9Sstevel@tonic-gatemy $typename = '(int|char|short|long|unsigned|float|double' . 1377c478bd9Sstevel@tonic-gate '|\w+_t|struct\s+\w+|union\s+\w+|FILE)'; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate# mapping of old types to POSIX compatible types 1407c478bd9Sstevel@tonic-gatemy %old2posix = ( 1417c478bd9Sstevel@tonic-gate 'unchar' => 'uchar_t', 1427c478bd9Sstevel@tonic-gate 'ushort' => 'ushort_t', 1437c478bd9Sstevel@tonic-gate 'uint' => 'uint_t', 1447c478bd9Sstevel@tonic-gate 'ulong' => 'ulong_t', 1457c478bd9Sstevel@tonic-gate 'u_int' => 'uint_t', 1467c478bd9Sstevel@tonic-gate 'u_short' => 'ushort_t', 1477c478bd9Sstevel@tonic-gate 'u_long' => 'ulong_t', 1487c478bd9Sstevel@tonic-gate 'u_char' => 'uchar_t', 14988853a59SToomas Soome 'u_int8_t' => 'uint8_t', 15088853a59SToomas Soome 'u_int16_t' => 'uint16_t', 15188853a59SToomas Soome 'u_int32_t' => 'uint32_t', 15288853a59SToomas Soome 'u_int64_t' => 'uint64_t', 15388853a59SToomas Soome 'u_quad_t' => 'uint64_t', 1547c478bd9Sstevel@tonic-gate 'quad' => 'quad_t' 1557c478bd9Sstevel@tonic-gate); 1567c478bd9Sstevel@tonic-gate 1573c2f5c48Sjwadamsmy $lint_re = qr/\/\*(?: 1583c2f5c48Sjwadams ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*| 1593c2f5c48Sjwadams CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY| 1603c2f5c48Sjwadams FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*| 1613c2f5c48Sjwadams PROTOLIB[0-9]*|SCANFLIKE[0-9]*|CSTYLED.*? 1623c2f5c48Sjwadams )\*\//x; 1633c2f5c48Sjwadams 1643c2f5c48Sjwadamsmy $splint_re = qr/\/\*@.*?@\*\//x; 1653c2f5c48Sjwadams 1663c2f5c48Sjwadamsmy $warlock_re = qr/\/\*\s*(?: 1673c2f5c48Sjwadams VARIABLES\ PROTECTED\ BY| 1683c2f5c48Sjwadams MEMBERS\ PROTECTED\ BY| 1693c2f5c48Sjwadams ALL\ MEMBERS\ PROTECTED\ BY| 1703c2f5c48Sjwadams READ-ONLY\ VARIABLES:| 1713c2f5c48Sjwadams READ-ONLY\ MEMBERS:| 1723c2f5c48Sjwadams VARIABLES\ READABLE\ WITHOUT\ LOCK:| 1733c2f5c48Sjwadams MEMBERS\ READABLE\ WITHOUT\ LOCK:| 1743c2f5c48Sjwadams LOCKS\ COVERED\ BY| 1753c2f5c48Sjwadams LOCK\ UNNEEDED\ BECAUSE| 1763c2f5c48Sjwadams LOCK\ NEEDED:| 1773c2f5c48Sjwadams LOCK\ HELD\ ON\ ENTRY:| 1783c2f5c48Sjwadams READ\ LOCK\ HELD\ ON\ ENTRY:| 1793c2f5c48Sjwadams WRITE\ LOCK\ HELD\ ON\ ENTRY:| 1803c2f5c48Sjwadams LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:| 1813c2f5c48Sjwadams READ\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:| 1823c2f5c48Sjwadams WRITE\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:| 1833c2f5c48Sjwadams LOCK\ RELEASED\ AS\ SIDE\ EFFECT:| 1843c2f5c48Sjwadams LOCK\ UPGRADED\ AS\ SIDE\ EFFECT:| 1853c2f5c48Sjwadams LOCK\ DOWNGRADED\ AS\ SIDE\ EFFECT:| 1863c2f5c48Sjwadams FUNCTIONS\ CALLED\ THROUGH\ POINTER| 1873c2f5c48Sjwadams FUNCTIONS\ CALLED\ THROUGH\ MEMBER| 1883c2f5c48Sjwadams LOCK\ ORDER: 1893c2f5c48Sjwadams )/x; 1907c478bd9Sstevel@tonic-gate 191cdf0c1d5Smjnelsonmy $err_stat = 0; # exit status 192cdf0c1d5Smjnelson 1937c478bd9Sstevel@tonic-gateif ($#ARGV >= 0) { 1947c478bd9Sstevel@tonic-gate foreach my $arg (@ARGV) { 1957c478bd9Sstevel@tonic-gate my $fh = new IO::File $arg, "r"; 1967c478bd9Sstevel@tonic-gate if (!defined($fh)) { 1977c478bd9Sstevel@tonic-gate printf "%s: can not open\n", $arg; 1987c478bd9Sstevel@tonic-gate } else { 1997c478bd9Sstevel@tonic-gate &cstyle($arg, $fh); 2007c478bd9Sstevel@tonic-gate close $fh; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate} else { 2047c478bd9Sstevel@tonic-gate &cstyle("<stdin>", *STDIN); 2057c478bd9Sstevel@tonic-gate} 206cdf0c1d5Smjnelsonexit $err_stat; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gatemy $no_errs = 0; # set for CSTYLED-protected lines 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gatesub err($) { 2117c478bd9Sstevel@tonic-gate my ($error) = @_; 212cdf0c1d5Smjnelson unless ($no_errs) { 21394385aa4SToomas Soome if ($verbose) { 21494385aa4SToomas Soome printf $fmt, $filename, $., $error, $line; 21594385aa4SToomas Soome } else { 21694385aa4SToomas Soome printf $fmt, $filename, $., $error; 21794385aa4SToomas Soome } 218cdf0c1d5Smjnelson $err_stat = 1; 219cdf0c1d5Smjnelson } 2207c478bd9Sstevel@tonic-gate} 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gatesub err_prefix($$) { 2237c478bd9Sstevel@tonic-gate my ($prevline, $error) = @_; 2247c478bd9Sstevel@tonic-gate my $out = $prevline."\n".$line; 225cdf0c1d5Smjnelson unless ($no_errs) { 22694385aa4SToomas Soome if ($verbose) { 22794385aa4SToomas Soome printf $fmt, $filename, $., $error, $out; 22894385aa4SToomas Soome } else { 22994385aa4SToomas Soome printf $fmt, $filename, $., $error; 23094385aa4SToomas Soome } 231cdf0c1d5Smjnelson $err_stat = 1; 232cdf0c1d5Smjnelson } 2337c478bd9Sstevel@tonic-gate} 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gatesub err_prev($) { 2367c478bd9Sstevel@tonic-gate my ($error) = @_; 237cdf0c1d5Smjnelson unless ($no_errs) { 23894385aa4SToomas Soome if ($verbose) { 23994385aa4SToomas Soome printf $fmt, $filename, $. - 1, $error, $prev; 24094385aa4SToomas Soome } else { 24194385aa4SToomas Soome printf $fmt, $filename, $. - 1, $error; 24294385aa4SToomas Soome } 243cdf0c1d5Smjnelson $err_stat = 1; 244cdf0c1d5Smjnelson } 2457c478bd9Sstevel@tonic-gate} 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gatesub cstyle($$) { 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gatemy ($fn, $filehandle) = @_; 2507c478bd9Sstevel@tonic-gate$filename = $fn; # share it globally 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gatemy $in_cpp = 0; 2537c478bd9Sstevel@tonic-gatemy $next_in_cpp = 0; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gatemy $in_comment = 0; 2567c478bd9Sstevel@tonic-gatemy $in_header_comment = 0; 2577c478bd9Sstevel@tonic-gatemy $comment_done = 0; 2587c478bd9Sstevel@tonic-gatemy $in_warlock_comment = 0; 2597c478bd9Sstevel@tonic-gatemy $in_function = 0; 2607c478bd9Sstevel@tonic-gatemy $in_function_header = 0; 261c4567a61SPaul Dagneliemy $function_header_full_indent = 0; 2627c478bd9Sstevel@tonic-gatemy $in_declaration = 0; 2637c478bd9Sstevel@tonic-gatemy $note_level = 0; 2647c478bd9Sstevel@tonic-gatemy $nextok = 0; 2657c478bd9Sstevel@tonic-gatemy $nocheck = 0; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gatemy $in_string = 0; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gatemy ($okmsg, $comment_prefix); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate$line = ''; 2727c478bd9Sstevel@tonic-gate$prev = ''; 2737c478bd9Sstevel@tonic-gatereset_indent(); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gateline: while (<$filehandle>) { 2767c478bd9Sstevel@tonic-gate s/\r?\n$//; # strip return and newline 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate # save the original line, then remove all text from within 2797c478bd9Sstevel@tonic-gate # double or single quotes, we do not want to check such text. 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate $line = $_; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate # 2847c478bd9Sstevel@tonic-gate # C allows strings to be continued with a backslash at the end of 2857c478bd9Sstevel@tonic-gate # the line. We translate that into a quoted string on the previous 2867c478bd9Sstevel@tonic-gate # line followed by an initial quote on the next line. 2877c478bd9Sstevel@tonic-gate # 2887c478bd9Sstevel@tonic-gate # (we assume that no-one will use backslash-continuation with character 2897c478bd9Sstevel@tonic-gate # constants) 2907c478bd9Sstevel@tonic-gate # 2917c478bd9Sstevel@tonic-gate $_ = '"' . $_ if ($in_string && !$nocheck && !$in_comment); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate # 2947c478bd9Sstevel@tonic-gate # normal strings and characters 2957c478bd9Sstevel@tonic-gate # 2967c478bd9Sstevel@tonic-gate s/'([^\\']|\\[^xX0]|\\0[0-9]*|\\[xX][0-9a-fA-F]*)'/''/g; 2977c478bd9Sstevel@tonic-gate s/"([^\\"]|\\.)*"/\"\"/g; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate # 3007c478bd9Sstevel@tonic-gate # detect string continuation 3017c478bd9Sstevel@tonic-gate # 3027c478bd9Sstevel@tonic-gate if ($nocheck || $in_comment) { 3037c478bd9Sstevel@tonic-gate $in_string = 0; 3047c478bd9Sstevel@tonic-gate } else { 3057c478bd9Sstevel@tonic-gate # 3067c478bd9Sstevel@tonic-gate # Now that all full strings are replaced with "", we check 3077c478bd9Sstevel@tonic-gate # for unfinished strings continuing onto the next line. 3087c478bd9Sstevel@tonic-gate # 3097c478bd9Sstevel@tonic-gate $in_string = 3107c478bd9Sstevel@tonic-gate (s/([^"](?:"")*)"([^\\"]|\\.)*\\$/$1""/ || 3117c478bd9Sstevel@tonic-gate s/^("")*"([^\\"]|\\.)*\\$/""/); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate # 3157c478bd9Sstevel@tonic-gate # figure out if we are in a cpp directive 3167c478bd9Sstevel@tonic-gate # 3177c478bd9Sstevel@tonic-gate $in_cpp = $next_in_cpp || /^\s*#/; # continued or started 3187c478bd9Sstevel@tonic-gate $next_in_cpp = $in_cpp && /\\$/; # only if continued 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate # strip off trailing backslashes, which appear in long macros 3217c478bd9Sstevel@tonic-gate s/\s*\\$//; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate # an /* END CSTYLED */ comment ends a no-check block. 3247c478bd9Sstevel@tonic-gate if ($nocheck) { 3257c478bd9Sstevel@tonic-gate if (/\/\* *END *CSTYLED *\*\//) { 3267c478bd9Sstevel@tonic-gate $nocheck = 0; 3277c478bd9Sstevel@tonic-gate } else { 3287c478bd9Sstevel@tonic-gate reset_indent(); 3297c478bd9Sstevel@tonic-gate next line; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate # a /*CSTYLED*/ comment indicates that the next line is ok. 3347c478bd9Sstevel@tonic-gate if ($nextok) { 3357c478bd9Sstevel@tonic-gate if ($okmsg) { 3367c478bd9Sstevel@tonic-gate err($okmsg); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate $nextok = 0; 3397c478bd9Sstevel@tonic-gate $okmsg = 0; 3407c478bd9Sstevel@tonic-gate if (/\/\* *CSTYLED.*\*\//) { 3417c478bd9Sstevel@tonic-gate /^.*\/\* *CSTYLED *(.*) *\*\/.*$/; 3427c478bd9Sstevel@tonic-gate $okmsg = $1; 3437c478bd9Sstevel@tonic-gate $nextok = 1; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate $no_errs = 1; 3467c478bd9Sstevel@tonic-gate } elsif ($no_errs) { 3477c478bd9Sstevel@tonic-gate $no_errs = 0; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate # check length of line. 3517c478bd9Sstevel@tonic-gate # first, a quick check to see if there is any chance of being too long. 3527c478bd9Sstevel@tonic-gate if (($line =~ tr/\t/\t/) * 7 + length($line) > 80) { 3537c478bd9Sstevel@tonic-gate # yes, there is a chance. 3547c478bd9Sstevel@tonic-gate # replace tabs with spaces and check again. 3557c478bd9Sstevel@tonic-gate my $eline = $line; 3567c478bd9Sstevel@tonic-gate 1 while $eline =~ 3577c478bd9Sstevel@tonic-gate s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; 3587c478bd9Sstevel@tonic-gate if (length($eline) > 80) { 3597c478bd9Sstevel@tonic-gate err("line > 80 characters"); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate # ignore NOTE(...) annotations (assumes NOTE is on lines by itself). 3647c478bd9Sstevel@tonic-gate if ($note_level || /\b_?NOTE\s*\(/) { # if in NOTE or this is NOTE 3657c478bd9Sstevel@tonic-gate s/[^()]//g; # eliminate all non-parens 3667c478bd9Sstevel@tonic-gate $note_level += s/\(//g - length; # update paren nest level 3677c478bd9Sstevel@tonic-gate next; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate # a /* BEGIN CSTYLED */ comment starts a no-check block. 3717c478bd9Sstevel@tonic-gate if (/\/\* *BEGIN *CSTYLED *\*\//) { 3727c478bd9Sstevel@tonic-gate $nocheck = 1; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate # a /*CSTYLED*/ comment indicates that the next line is ok. 3767c478bd9Sstevel@tonic-gate if (/\/\* *CSTYLED.*\*\//) { 3777c478bd9Sstevel@tonic-gate /^.*\/\* *CSTYLED *(.*) *\*\/.*$/; 3787c478bd9Sstevel@tonic-gate $okmsg = $1; 3797c478bd9Sstevel@tonic-gate $nextok = 1; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate if (/\/\/ *CSTYLED/) { 3827c478bd9Sstevel@tonic-gate /^.*\/\/ *CSTYLED *(.*)$/; 3837c478bd9Sstevel@tonic-gate $okmsg = $1; 3847c478bd9Sstevel@tonic-gate $nextok = 1; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate # universal checks; apply to everything 3887c478bd9Sstevel@tonic-gate if (/\t +\t/) { 3897c478bd9Sstevel@tonic-gate err("spaces between tabs"); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate if (/ \t+ /) { 3927c478bd9Sstevel@tonic-gate err("tabs between spaces"); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate if (/\s$/) { 3957c478bd9Sstevel@tonic-gate err("space or tab at end of line"); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) { 3987c478bd9Sstevel@tonic-gate err("comment preceded by non-blank"); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate # is this the beginning or ending of a function? 4027c478bd9Sstevel@tonic-gate # (not if "struct foo\n{\n") 403578f6736SDominik Hassler if (/^\{$/ && $prev =~ /\)\s*(const\s*)?(\/\*.*\*\/\s*)?\\?$/) { 4047c478bd9Sstevel@tonic-gate $in_function = 1; 4057c478bd9Sstevel@tonic-gate $in_declaration = 1; 4067c478bd9Sstevel@tonic-gate $in_function_header = 0; 407c4567a61SPaul Dagnelie $function_header_full_indent = 0; 4087c478bd9Sstevel@tonic-gate $prev = $line; 4097c478bd9Sstevel@tonic-gate next line; 4107c478bd9Sstevel@tonic-gate } 411578f6736SDominik Hassler if (/^\}\s*(\/\*.*\*\/\s*)*$/) { 4127c478bd9Sstevel@tonic-gate if ($prev =~ /^\s*return\s*;/) { 4137c478bd9Sstevel@tonic-gate err_prev("unneeded return at end of function"); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate $in_function = 0; 4167c478bd9Sstevel@tonic-gate reset_indent(); # we don't check between functions 4177c478bd9Sstevel@tonic-gate $prev = $line; 4187c478bd9Sstevel@tonic-gate next line; 4197c478bd9Sstevel@tonic-gate } 420c667d216SHans Rosenfeld if ($in_function_header && ! /^ (\w|\.)/ ) { 421578f6736SDominik Hassler if (/^\{\}$/) { 422c4567a61SPaul Dagnelie $in_function_header = 0; 423c4567a61SPaul Dagnelie $function_header_full_indent = 0; 424c4567a61SPaul Dagnelie } elsif ($picky && ! (/^\t/ && $function_header_full_indent != 0)) { 425c4567a61SPaul Dagnelie err("continuation line should be indented by 4 spaces"); 426c4567a61SPaul Dagnelie } 427c4567a61SPaul Dagnelie } 428c4567a61SPaul Dagnelie 429c4567a61SPaul Dagnelie # 430c4567a61SPaul Dagnelie # If this matches something of form "foo(", it's probably a function 431c4567a61SPaul Dagnelie # definition, unless it ends with ") bar;", in which case it's a declaration 432c4567a61SPaul Dagnelie # that uses a macro to generate the type. 433c4567a61SPaul Dagnelie # 434c4567a61SPaul Dagnelie if (/^\w+\(/ && !/\) \w+;$/) { 4357c478bd9Sstevel@tonic-gate $in_function_header = 1; 436c4567a61SPaul Dagnelie if (/\($/) { 437c4567a61SPaul Dagnelie $function_header_full_indent = 1; 438c4567a61SPaul Dagnelie } 439c4567a61SPaul Dagnelie } 440578f6736SDominik Hassler if ($in_function_header && /^\{$/) { 441c4567a61SPaul Dagnelie $in_function_header = 0; 442c4567a61SPaul Dagnelie $function_header_full_indent = 0; 443c4567a61SPaul Dagnelie $in_function = 1; 444c4567a61SPaul Dagnelie } 445c4567a61SPaul Dagnelie if ($in_function_header && /\);$/) { 446c4567a61SPaul Dagnelie $in_function_header = 0; 447c4567a61SPaul Dagnelie $function_header_full_indent = 0; 448c4567a61SPaul Dagnelie } 449578f6736SDominik Hassler if ($in_function_header && /\{$/ ) { 450002ec3e4SRichard PALO if ($picky) { 451c4567a61SPaul Dagnelie err("opening brace on same line as function header"); 452c4567a61SPaul Dagnelie } 453c4567a61SPaul Dagnelie $in_function_header = 0; 454c4567a61SPaul Dagnelie $function_header_full_indent = 0; 455c4567a61SPaul Dagnelie $in_function = 1; 456c4567a61SPaul Dagnelie next line; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if ($in_warlock_comment && /\*\//) { 4607c478bd9Sstevel@tonic-gate $in_warlock_comment = 0; 4617c478bd9Sstevel@tonic-gate $prev = $line; 4627c478bd9Sstevel@tonic-gate next line; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate # a blank line terminates the declarations within a function. 4667c478bd9Sstevel@tonic-gate # XXX - but still a problem in sub-blocks. 4677c478bd9Sstevel@tonic-gate if ($in_declaration && /^$/) { 4687c478bd9Sstevel@tonic-gate $in_declaration = 0; 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if ($comment_done) { 4727c478bd9Sstevel@tonic-gate $in_comment = 0; 4737c478bd9Sstevel@tonic-gate $in_header_comment = 0; 4747c478bd9Sstevel@tonic-gate $comment_done = 0; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate # does this looks like the start of a block comment? 477dcbbe9e0SPatrick Mooney if (/$hdr_comment_start/ || /$fbsd_comment_start/) { 4783c2f5c48Sjwadams if (!/^\t*\/\*/) { 4797c478bd9Sstevel@tonic-gate err("block comment not indented by tabs"); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate $in_comment = 1; 4823c2f5c48Sjwadams /^(\s*)\//; 4833c2f5c48Sjwadams $comment_prefix = $1; 4847c478bd9Sstevel@tonic-gate if ($comment_prefix eq "") { 4857c478bd9Sstevel@tonic-gate $in_header_comment = 1; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate $prev = $line; 4887c478bd9Sstevel@tonic-gate next line; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate # are we still in the block comment? 4917c478bd9Sstevel@tonic-gate if ($in_comment) { 4927c478bd9Sstevel@tonic-gate if (/^$comment_prefix \*\/$/) { 4937c478bd9Sstevel@tonic-gate $comment_done = 1; 4947c478bd9Sstevel@tonic-gate } elsif (/\*\//) { 4957c478bd9Sstevel@tonic-gate $comment_done = 1; 4967c478bd9Sstevel@tonic-gate err("improper block comment close") 4977c478bd9Sstevel@tonic-gate unless ($ignore_hdr_comment && $in_header_comment); 4987c478bd9Sstevel@tonic-gate } elsif (!/^$comment_prefix \*[ \t]/ && 4997c478bd9Sstevel@tonic-gate !/^$comment_prefix \*$/) { 5007c478bd9Sstevel@tonic-gate err("improper block comment") 5017c478bd9Sstevel@tonic-gate unless ($ignore_hdr_comment && $in_header_comment); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if ($in_header_comment && $ignore_hdr_comment) { 5067c478bd9Sstevel@tonic-gate $prev = $line; 5077c478bd9Sstevel@tonic-gate next line; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate # check for errors that might occur in comments and in code. 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate # allow spaces to be used to draw pictures in header comments. 5137c478bd9Sstevel@tonic-gate if (/[^ ] / && !/".* .*"/ && !$in_header_comment) { 5147c478bd9Sstevel@tonic-gate err("spaces instead of tabs"); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate if (/^ / && !/^ \*[ \t\/]/ && !/^ \*$/ && 517c667d216SHans Rosenfeld (!/^ (\w|\.)/ || $in_function != 0)) { 5187c478bd9Sstevel@tonic-gate err("indent by spaces instead of tabs"); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate if (/^\t+ [^ \t\*]/ || /^\t+ \S/ || /^\t+ \S/) { 5217c478bd9Sstevel@tonic-gate err("continuation line not indented by 4 spaces"); 5227c478bd9Sstevel@tonic-gate } 5233c2f5c48Sjwadams if (/$warlock_re/ && !/\*\//) { 5247c478bd9Sstevel@tonic-gate $in_warlock_comment = 1; 5257c478bd9Sstevel@tonic-gate $prev = $line; 5267c478bd9Sstevel@tonic-gate next line; 5277c478bd9Sstevel@tonic-gate } 5283c2f5c48Sjwadams if (/^\s*\/\*./ && !/^\s*\/\*.*\*\// && !/$hdr_comment_start/) { 5297c478bd9Sstevel@tonic-gate err("improper first line of block comment"); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate if ($in_comment) { # still in comment, don't do further checks 5337c478bd9Sstevel@tonic-gate $prev = $line; 5347c478bd9Sstevel@tonic-gate next line; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if ((/[^(]\/\*\S/ || /^\/\*\S/) && 5383c2f5c48Sjwadams !(/$lint_re/ || ($splint_comments && /$splint_re/))) { 5397c478bd9Sstevel@tonic-gate err("missing blank after open comment"); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate if (/\S\*\/[^)]|\S\*\/$/ && 5423c2f5c48Sjwadams !(/$lint_re/ || ($splint_comments && /$splint_re/))) { 5437c478bd9Sstevel@tonic-gate err("missing blank before close comment"); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate if (/\/\/\S/) { # C++ comments 5467c478bd9Sstevel@tonic-gate err("missing blank after start comment"); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate # check for unterminated single line comments, but allow them when 5497c478bd9Sstevel@tonic-gate # they are used to comment out the argument list of a function 5507c478bd9Sstevel@tonic-gate # declaration. 5517c478bd9Sstevel@tonic-gate if (/\S.*\/\*/ && !/\S.*\/\*.*\*\// && !/\(\/\*/) { 5527c478bd9Sstevel@tonic-gate err("unterminated single line comment"); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (/^(#else|#endif|#include)(.*)$/) { 5567c478bd9Sstevel@tonic-gate $prev = $line; 5577c478bd9Sstevel@tonic-gate if ($picky) { 5587c478bd9Sstevel@tonic-gate my $directive = $1; 5597c478bd9Sstevel@tonic-gate my $clause = $2; 5607c478bd9Sstevel@tonic-gate # Enforce ANSI rules for #else and #endif: no noncomment 5617c478bd9Sstevel@tonic-gate # identifiers are allowed after #endif or #else. Allow 5627c478bd9Sstevel@tonic-gate # C++ comments since they seem to be a fact of life. 5637c478bd9Sstevel@tonic-gate if ((($1 eq "#endif") || ($1 eq "#else")) && 5647c478bd9Sstevel@tonic-gate ($clause ne "") && 5657c478bd9Sstevel@tonic-gate (!($clause =~ /^\s+\/\*.*\*\/$/)) && 5667c478bd9Sstevel@tonic-gate (!($clause =~ /^\s+\/\/.*$/))) { 5677c478bd9Sstevel@tonic-gate err("non-comment text following " . 5687c478bd9Sstevel@tonic-gate "$directive (or malformed $directive " . 5697c478bd9Sstevel@tonic-gate "directive)"); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate next line; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate # 5767c478bd9Sstevel@tonic-gate # delete any comments and check everything else. Note that 5777c478bd9Sstevel@tonic-gate # ".*?" is a non-greedy match, so that we don't get confused by 5787c478bd9Sstevel@tonic-gate # multiple comments on the same line. 5797c478bd9Sstevel@tonic-gate # 5807c478bd9Sstevel@tonic-gate s/\/\*.*?\*\///g; 5817c478bd9Sstevel@tonic-gate s/\/\/.*$//; # C++ comments 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate # delete any trailing whitespace; we have already checked for that. 5847c478bd9Sstevel@tonic-gate s/\s*$//; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate # following checks do not apply to text in comments. 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=[^\s,]/ || 5897c478bd9Sstevel@tonic-gate (/[^->]>[^,=>\s]/ && !/[^->]>$/) || 5907c478bd9Sstevel@tonic-gate (/[^<]<[^,=<\s]/ && !/[^<]<$/) || 591fcfad32eSPatrick Mooney /[^<\s]<[^<]/ || /[^->\s]>[^>]/) { 5927c478bd9Sstevel@tonic-gate err("missing space around relational operator"); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ || 5957c478bd9Sstevel@tonic-gate (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) || 5967c478bd9Sstevel@tonic-gate (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) { 5977c478bd9Sstevel@tonic-gate # XXX - should only check this for C++ code 5987c478bd9Sstevel@tonic-gate # XXX - there are probably other forms that should be allowed 5997c478bd9Sstevel@tonic-gate if (!/\soperator=/) { 6007c478bd9Sstevel@tonic-gate err("missing space around assignment operator"); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate } 603fcfad32eSPatrick Mooney if (/[,;]\S/ && !/\bfor \(;;\)/) { 604fcfad32eSPatrick Mooney err("comma or semicolon followed by non-blank"); 6057c478bd9Sstevel@tonic-gate } 606fcfad32eSPatrick Mooney # allow "for" statements to have empty "while" clauses 607fcfad32eSPatrick Mooney if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) { 6087c478bd9Sstevel@tonic-gate err("comma or semicolon preceded by blank"); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate if (/^\s*(&&|\|\|)/) { 6117c478bd9Sstevel@tonic-gate err("improper boolean continuation"); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate if (/\S *(&&|\|\|)/ || /(&&|\|\|) *\S/) { 6147c478bd9Sstevel@tonic-gate err("more than one space around boolean operator"); 6157c478bd9Sstevel@tonic-gate } 616*ed093b41SRobert Mustacchi if (/\b(for|if|while|switch|sizeof|alignof|return|case)\(/) { 6177c478bd9Sstevel@tonic-gate err("missing space between keyword and paren"); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate if (/(\b(for|if|while|switch|return)\b.*){2,}/ && !/^#define/) { 6207c478bd9Sstevel@tonic-gate # multiple "case" and "sizeof" allowed 6217c478bd9Sstevel@tonic-gate err("more than one keyword on line"); 6227c478bd9Sstevel@tonic-gate } 623*ed093b41SRobert Mustacchi if (/\b(for|if|while|switch|sizeof|alignof|return|case)\s\s+\(/ && 6247c478bd9Sstevel@tonic-gate !/^#if\s+\(/) { 6257c478bd9Sstevel@tonic-gate err("extra space between keyword and paren"); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate # try to detect "func (x)" but not "if (x)" or 6287c478bd9Sstevel@tonic-gate # "#define foo (x)" or "int (*func)();" 6297c478bd9Sstevel@tonic-gate if (/\w\s\(/) { 6307c478bd9Sstevel@tonic-gate my $s = $_; 6317c478bd9Sstevel@tonic-gate # strip off all keywords on the line 632*ed093b41SRobert Mustacchi s/\b(for|if|while|switch|return|case|alignof|sizeof)\s\(/XXX(/g; 6337c478bd9Sstevel@tonic-gate s/#elif\s\(/XXX(/g; 6347c478bd9Sstevel@tonic-gate s/^#define\s+\w+\s+\(/XXX(/; 6357c478bd9Sstevel@tonic-gate # do not match things like "void (*f)();" 6367c478bd9Sstevel@tonic-gate # or "typedef void (func_t)();" 6377c478bd9Sstevel@tonic-gate s/\w\s\(+\*/XXX(*/g; 6387c478bd9Sstevel@tonic-gate s/\b($typename|void)\s+\(+/XXX(/og; 6397c478bd9Sstevel@tonic-gate if (/\w\s\(/) { 6407c478bd9Sstevel@tonic-gate err("extra space between function name and left paren"); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate $_ = $s; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate # try to detect "int foo(x)", but not "extern int foo(x);" 6457c478bd9Sstevel@tonic-gate # XXX - this still trips over too many legitimate things, 6467c478bd9Sstevel@tonic-gate # like "int foo(x,\n\ty);" 6477c478bd9Sstevel@tonic-gate# if (/^(\w+(\s|\*)+)+\w+\(/ && !/\)[;,](\s|)*$/ && 6487c478bd9Sstevel@tonic-gate# !/^(extern|static)\b/) { 6497c478bd9Sstevel@tonic-gate# err("return type of function not on separate line"); 6507c478bd9Sstevel@tonic-gate# } 6517c478bd9Sstevel@tonic-gate # this is a close approximation 6527c478bd9Sstevel@tonic-gate if (/^(\w+(\s|\*)+)+\w+\(.*\)(\s|)*$/ && 6537c478bd9Sstevel@tonic-gate !/^(extern|static)\b/) { 6547c478bd9Sstevel@tonic-gate err("return type of function not on separate line"); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate if (/^#define /) { 6577c478bd9Sstevel@tonic-gate err("#define followed by space instead of tab"); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate if (/^\s*return\W[^;]*;/ && !/^\s*return\s*\(.*\);/) { 6607c478bd9Sstevel@tonic-gate err("unparenthesized return expression"); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate if (/\bsizeof\b/ && !/\bsizeof\s*\(.*\)/) { 6637c478bd9Sstevel@tonic-gate err("unparenthesized sizeof expression"); 6647c478bd9Sstevel@tonic-gate } 665*ed093b41SRobert Mustacchi if (/\balignof\b/ && !/\balignof\s*\(.*\)/) { 666*ed093b41SRobert Mustacchi err("unparenthesized alignof expression"); 667*ed093b41SRobert Mustacchi } 6687c478bd9Sstevel@tonic-gate if (/\(\s/) { 6697c478bd9Sstevel@tonic-gate err("whitespace after left paren"); 6707c478bd9Sstevel@tonic-gate } 671fcfad32eSPatrick Mooney # allow "for" statements to have empty "continue" clauses 672fcfad32eSPatrick Mooney if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) { 6737c478bd9Sstevel@tonic-gate err("whitespace before right paren"); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate if (/^\s*\(void\)[^ ]/) { 6767c478bd9Sstevel@tonic-gate err("missing space after (void) cast"); 6777c478bd9Sstevel@tonic-gate } 67894385aa4SToomas Soome if (/\S\{/ && !/\{\{/) { 6797c478bd9Sstevel@tonic-gate err("missing space before left brace"); 6807c478bd9Sstevel@tonic-gate } 681578f6736SDominik Hassler if ($in_function && /^\s+\{/ && 6827c478bd9Sstevel@tonic-gate ($prev =~ /\)\s*$/ || $prev =~ /\bstruct\s+\w+$/)) { 6837c478bd9Sstevel@tonic-gate err("left brace starting a line"); 6847c478bd9Sstevel@tonic-gate } 685578f6736SDominik Hassler if (/\}(else|while)/) { 6867c478bd9Sstevel@tonic-gate err("missing space after right brace"); 6877c478bd9Sstevel@tonic-gate } 688578f6736SDominik Hassler if (/\}\s\s+(else|while)/) { 6897c478bd9Sstevel@tonic-gate err("extra space after right brace"); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate if (/\b_VOID\b|\bVOID\b|\bSTATIC\b/) { 6927c478bd9Sstevel@tonic-gate err("obsolete use of VOID or STATIC"); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate if (/\b$typename\*/o) { 6957c478bd9Sstevel@tonic-gate err("missing space between type name and *"); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate if (/^\s+#/) { 6987c478bd9Sstevel@tonic-gate err("preprocessor statement not in column 1"); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate if (/^#\s/) { 7017c478bd9Sstevel@tonic-gate err("blank after preprocessor #"); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate if (/!\s*(strcmp|strncmp|bcmp)\s*\(/) { 7047c478bd9Sstevel@tonic-gate err("don't use boolean ! with comparison functions"); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate # 7087c478bd9Sstevel@tonic-gate # We completely ignore, for purposes of indentation: 7097c478bd9Sstevel@tonic-gate # * lines outside of functions 7107c478bd9Sstevel@tonic-gate # * preprocessor lines 7117c478bd9Sstevel@tonic-gate # 7127c478bd9Sstevel@tonic-gate if ($check_continuation && $in_function && !$in_cpp) { 7137c478bd9Sstevel@tonic-gate process_indent($_); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate if ($picky) { 7167c478bd9Sstevel@tonic-gate # try to detect spaces after casts, but allow (e.g.) 7173c2f5c48Sjwadams # "sizeof (int) + 1", "void (*funcptr)(int) = foo;", and 7183c2f5c48Sjwadams # "int foo(int) __NORETURN;" 7193c2f5c48Sjwadams if ((/^\($typename( \*+)?\)\s/o || 7203c2f5c48Sjwadams /\W\($typename( \*+)?\)\s/o) && 7217c478bd9Sstevel@tonic-gate !/sizeof\s*\($typename( \*)?\)\s/o && 7227c478bd9Sstevel@tonic-gate !/\($typename( \*+)?\)\s+=[^=]/o) { 7237c478bd9Sstevel@tonic-gate err("space after cast"); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate if (/\b$typename\s*\*\s/o && 7267c478bd9Sstevel@tonic-gate !/\b$typename\s*\*\s+const\b/o) { 7277c478bd9Sstevel@tonic-gate err("unary * followed by space"); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate if ($check_posix_types) { 7317c478bd9Sstevel@tonic-gate # try to detect old non-POSIX types. 7327c478bd9Sstevel@tonic-gate # POSIX requires all non-standard typedefs to end in _t, 7337c478bd9Sstevel@tonic-gate # but historically these have been used. 73488853a59SToomas Soome my $types = join '|', keys %old2posix; 73588853a59SToomas Soome if (/\b($types)\b/) { 7367c478bd9Sstevel@tonic-gate err("non-POSIX typedef $1 used: use $old2posix{$1} instead"); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate if ($heuristic) { 7407c478bd9Sstevel@tonic-gate # cannot check this everywhere due to "struct {\n...\n} foo;" 7417c478bd9Sstevel@tonic-gate if ($in_function && !$in_declaration && 742578f6736SDominik Hassler /\}./ && !/\}\s+=/ && !/\{.*\}[;,]$/ && !/\}(\s|)*$/ && 743578f6736SDominik Hassler !/\} (else|while)/ && !/\}\}/) { 7447c478bd9Sstevel@tonic-gate err("possible bad text following right brace"); 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate # cannot check this because sub-blocks in 7477c478bd9Sstevel@tonic-gate # the middle of code are ok 748578f6736SDominik Hassler if ($in_function && /^\s+\{/) { 7497c478bd9Sstevel@tonic-gate err("possible left brace starting a line"); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate if (/^\s*else\W/) { 753578f6736SDominik Hassler if ($prev =~ /^\s*\}$/) { 7547c478bd9Sstevel@tonic-gate err_prefix($prev, 7557c478bd9Sstevel@tonic-gate "else and right brace should be on same line"); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate $prev = $line; 7597c478bd9Sstevel@tonic-gate} 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gateif ($prev eq "") { 7627c478bd9Sstevel@tonic-gate err("last line in file is blank"); 7637c478bd9Sstevel@tonic-gate} 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate} 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate# 7687c478bd9Sstevel@tonic-gate# Continuation-line checking 7697c478bd9Sstevel@tonic-gate# 7707c478bd9Sstevel@tonic-gate# The rest of this file contains the code for the continuation checking 7717c478bd9Sstevel@tonic-gate# engine. It's a pretty simple state machine which tracks the expression 7727c478bd9Sstevel@tonic-gate# depth (unmatched '('s and '['s). 7737c478bd9Sstevel@tonic-gate# 7747c478bd9Sstevel@tonic-gate# Keep in mind that the argument to process_indent() has already been heavily 7757c478bd9Sstevel@tonic-gate# processed; all comments have been replaced by control-A, and the contents of 7767c478bd9Sstevel@tonic-gate# strings and character constants have been elided. 7777c478bd9Sstevel@tonic-gate# 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gatemy $cont_in; # currently inside of a continuation 7807c478bd9Sstevel@tonic-gatemy $cont_off; # skipping an initializer or definition 7817c478bd9Sstevel@tonic-gatemy $cont_noerr; # suppress cascading errors 7827c478bd9Sstevel@tonic-gatemy $cont_start; # the line being continued 7837c478bd9Sstevel@tonic-gatemy $cont_base; # the base indentation 7847c478bd9Sstevel@tonic-gatemy $cont_first; # this is the first line of a statement 7857c478bd9Sstevel@tonic-gatemy $cont_multiseg; # this continuation has multiple segments 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gatemy $cont_special; # this is a C statement (if, for, etc.) 7887c478bd9Sstevel@tonic-gatemy $cont_macro; # this is a macro 7897c478bd9Sstevel@tonic-gatemy $cont_case; # this is a multi-line case 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gatemy @cont_paren; # the stack of unmatched ( and [s we've seen 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gatesub 7947c478bd9Sstevel@tonic-gatereset_indent() 7957c478bd9Sstevel@tonic-gate{ 7967c478bd9Sstevel@tonic-gate $cont_in = 0; 7977c478bd9Sstevel@tonic-gate $cont_off = 0; 7987c478bd9Sstevel@tonic-gate} 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gatesub 8017c478bd9Sstevel@tonic-gatedelabel($) 8027c478bd9Sstevel@tonic-gate{ 8037c478bd9Sstevel@tonic-gate # 8047c478bd9Sstevel@tonic-gate # replace labels with tabs. Note that there may be multiple 8057c478bd9Sstevel@tonic-gate # labels on a line. 8067c478bd9Sstevel@tonic-gate # 8077c478bd9Sstevel@tonic-gate local $_ = $_[0]; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate while (/^(\t*)( *(?:(?:\w+\s*)|(?:case\b[^:]*)): *)(.*)$/) { 8107c478bd9Sstevel@tonic-gate my ($pre_tabs, $label, $rest) = ($1, $2, $3); 8117c478bd9Sstevel@tonic-gate $_ = $pre_tabs; 8127c478bd9Sstevel@tonic-gate while ($label =~ s/^([^\t]*)(\t+)//) { 8137c478bd9Sstevel@tonic-gate $_ .= "\t" x (length($2) + length($1) / 8); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate $_ .= ("\t" x (length($label) / 8)).$rest; 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate return ($_); 8197c478bd9Sstevel@tonic-gate} 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gatesub 8227c478bd9Sstevel@tonic-gateprocess_indent($) 8237c478bd9Sstevel@tonic-gate{ 8247c478bd9Sstevel@tonic-gate require strict; 8257c478bd9Sstevel@tonic-gate local $_ = $_[0]; # preserve the global $_ 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate s///g; # No comments 8287c478bd9Sstevel@tonic-gate s/\s+$//; # Strip trailing whitespace 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate return if (/^$/); # skip empty lines 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate # regexps used below; keywords taking (), macros, and continued cases 8337c478bd9Sstevel@tonic-gate my $special = '(?:(?:\}\s*)?else\s+)?(?:if|for|while|switch)\b'; 8347c478bd9Sstevel@tonic-gate my $macro = '[A-Z_][A-Z_0-9]*\('; 8357c478bd9Sstevel@tonic-gate my $case = 'case\b[^:]*$'; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate # skip over enumerations, array definitions, initializers, etc. 8387c478bd9Sstevel@tonic-gate if ($cont_off <= 0 && !/^\s*$special/ && 839578f6736SDominik Hassler (/(?:(?:\b(?:enum|struct|union)\s*[^\{]*)|(?:\s+=\s*))\{/ || 840578f6736SDominik Hassler (/^\s*\{/ && $prev =~ /=\s*(?:\/\*.*\*\/\s*)*$/))) { 8417c478bd9Sstevel@tonic-gate $cont_in = 0; 8427c478bd9Sstevel@tonic-gate $cont_off = tr/{/{/ - tr/}/}/; 8437c478bd9Sstevel@tonic-gate return; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate if ($cont_off) { 8467c478bd9Sstevel@tonic-gate $cont_off += tr/{/{/ - tr/}/}/; 8477c478bd9Sstevel@tonic-gate return; 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate if (!$cont_in) { 8517c478bd9Sstevel@tonic-gate $cont_start = $line; 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if (/^\t* /) { 8547c478bd9Sstevel@tonic-gate err("non-continuation indented 4 spaces"); 8557c478bd9Sstevel@tonic-gate $cont_noerr = 1; # stop reporting 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate $_ = delabel($_); # replace labels with tabs 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate # check if the statement is complete 8607c478bd9Sstevel@tonic-gate return if (/^\s*\}?$/); 8617c478bd9Sstevel@tonic-gate return if (/^\s*\}?\s*else\s*\{?$/); 8627c478bd9Sstevel@tonic-gate return if (/^\s*do\s*\{?$/); 863578f6736SDominik Hassler return if (/\{$/); 864578f6736SDominik Hassler return if (/\}[,;]?$/); 8657c478bd9Sstevel@tonic-gate 8666f55da5aSjwadams # Allow macros on their own lines 8676f55da5aSjwadams return if (/^\s*[A-Z_][A-Z_0-9]*$/); 8686f55da5aSjwadams 8697c478bd9Sstevel@tonic-gate # cases we don't deal with, generally non-kosher 870578f6736SDominik Hassler if (/\{/) { 8717c478bd9Sstevel@tonic-gate err("stuff after {"); 8727c478bd9Sstevel@tonic-gate return; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate # Get the base line, and set up the state machine 8767c478bd9Sstevel@tonic-gate /^(\t*)/; 8777c478bd9Sstevel@tonic-gate $cont_base = $1; 8787c478bd9Sstevel@tonic-gate $cont_in = 1; 8797c478bd9Sstevel@tonic-gate @cont_paren = (); 8807c478bd9Sstevel@tonic-gate $cont_first = 1; 8817c478bd9Sstevel@tonic-gate $cont_multiseg = 0; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate # certain things need special processing 8847c478bd9Sstevel@tonic-gate $cont_special = /^\s*$special/? 1 : 0; 8857c478bd9Sstevel@tonic-gate $cont_macro = /^\s*$macro/? 1 : 0; 8867c478bd9Sstevel@tonic-gate $cont_case = /^\s*$case/? 1 : 0; 8877c478bd9Sstevel@tonic-gate } else { 8887c478bd9Sstevel@tonic-gate $cont_first = 0; 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate # Strings may be pulled back to an earlier (half-)tabstop 8917c478bd9Sstevel@tonic-gate unless ($cont_noerr || /^$cont_base / || 8927c478bd9Sstevel@tonic-gate (/^\t*(?: )?(?:gettext\()?\"/ && !/^$cont_base\t/)) { 8937c478bd9Sstevel@tonic-gate err_prefix($cont_start, 8947c478bd9Sstevel@tonic-gate "continuation should be indented 4 spaces"); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate my $rest = $_; # keeps the remainder of the line 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate # 9017c478bd9Sstevel@tonic-gate # The split matches 0 characters, so that each 'special' character 9027c478bd9Sstevel@tonic-gate # is processed separately. Parens and brackets are pushed and 9037c478bd9Sstevel@tonic-gate # popped off the @cont_paren stack. For normal processing, we wait 9047c478bd9Sstevel@tonic-gate # until a ; or { terminates the statement. "special" processing 9057c478bd9Sstevel@tonic-gate # (if/for/while/switch) is allowed to stop when the stack empties, 9067c478bd9Sstevel@tonic-gate # as is macro processing. Case statements are terminated with a : 9077c478bd9Sstevel@tonic-gate # and an empty paren stack. 9087c478bd9Sstevel@tonic-gate # 9097c478bd9Sstevel@tonic-gate foreach $_ (split /[^\(\)\[\]\{\}\;\:]*/) { 9107c478bd9Sstevel@tonic-gate next if (length($_) == 0); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate # rest contains the remainder of the line 9137c478bd9Sstevel@tonic-gate my $rxp = "[^\Q$_\E]*\Q$_\E"; 9147c478bd9Sstevel@tonic-gate $rest =~ s/^$rxp//; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate if (/\(/ || /\[/) { 9177c478bd9Sstevel@tonic-gate push @cont_paren, $_; 9187c478bd9Sstevel@tonic-gate } elsif (/\)/ || /\]/) { 9197c478bd9Sstevel@tonic-gate my $cur = $_; 9207c478bd9Sstevel@tonic-gate tr/\)\]/\(\[/; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate my $old = (pop @cont_paren); 9237c478bd9Sstevel@tonic-gate if (!defined($old)) { 9247c478bd9Sstevel@tonic-gate err("unexpected '$cur'"); 9257c478bd9Sstevel@tonic-gate $cont_in = 0; 9267c478bd9Sstevel@tonic-gate last; 9277c478bd9Sstevel@tonic-gate } elsif ($old ne $_) { 9287c478bd9Sstevel@tonic-gate err("'$cur' mismatched with '$old'"); 9297c478bd9Sstevel@tonic-gate $cont_in = 0; 9307c478bd9Sstevel@tonic-gate last; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate # 9347c478bd9Sstevel@tonic-gate # If the stack is now empty, do special processing 9357c478bd9Sstevel@tonic-gate # for if/for/while/switch and macro statements. 9367c478bd9Sstevel@tonic-gate # 9377c478bd9Sstevel@tonic-gate next if (@cont_paren != 0); 9387c478bd9Sstevel@tonic-gate if ($cont_special) { 939578f6736SDominik Hassler if ($rest =~ /^\s*\{?$/) { 9407c478bd9Sstevel@tonic-gate $cont_in = 0; 9417c478bd9Sstevel@tonic-gate last; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate if ($rest =~ /^\s*;$/) { 9447c478bd9Sstevel@tonic-gate err("empty if/for/while body ". 9457c478bd9Sstevel@tonic-gate "not on its own line"); 9467c478bd9Sstevel@tonic-gate $cont_in = 0; 9477c478bd9Sstevel@tonic-gate last; 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate if (!$cont_first && $cont_multiseg == 1) { 9507c478bd9Sstevel@tonic-gate err_prefix($cont_start, 9517c478bd9Sstevel@tonic-gate "multiple statements continued ". 9527c478bd9Sstevel@tonic-gate "over multiple lines"); 9537c478bd9Sstevel@tonic-gate $cont_multiseg = 2; 9547c478bd9Sstevel@tonic-gate } elsif ($cont_multiseg == 0) { 9557c478bd9Sstevel@tonic-gate $cont_multiseg = 1; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate # We've finished this section, start 9587c478bd9Sstevel@tonic-gate # processing the next. 9597c478bd9Sstevel@tonic-gate goto section_ended; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate if ($cont_macro) { 9627c478bd9Sstevel@tonic-gate if ($rest =~ /^$/) { 9637c478bd9Sstevel@tonic-gate $cont_in = 0; 9647c478bd9Sstevel@tonic-gate last; 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate } elsif (/\;/) { 9687c478bd9Sstevel@tonic-gate if ($cont_case) { 9697c478bd9Sstevel@tonic-gate err("unexpected ;"); 9707c478bd9Sstevel@tonic-gate } elsif (!$cont_special) { 9717c478bd9Sstevel@tonic-gate err("unexpected ;") if (@cont_paren != 0); 9727c478bd9Sstevel@tonic-gate if (!$cont_first && $cont_multiseg == 1) { 9737c478bd9Sstevel@tonic-gate err_prefix($cont_start, 9747c478bd9Sstevel@tonic-gate "multiple statements continued ". 9757c478bd9Sstevel@tonic-gate "over multiple lines"); 9767c478bd9Sstevel@tonic-gate $cont_multiseg = 2; 9777c478bd9Sstevel@tonic-gate } elsif ($cont_multiseg == 0) { 9787c478bd9Sstevel@tonic-gate $cont_multiseg = 1; 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate if ($rest =~ /^$/) { 9817c478bd9Sstevel@tonic-gate $cont_in = 0; 9827c478bd9Sstevel@tonic-gate last; 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate if ($rest =~ /^\s*special/) { 9857c478bd9Sstevel@tonic-gate err("if/for/while/switch not started ". 9867c478bd9Sstevel@tonic-gate "on its own line"); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate goto section_ended; 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate } elsif (/\{/) { 9917c478bd9Sstevel@tonic-gate err("{ while in parens/brackets") if (@cont_paren != 0); 9927c478bd9Sstevel@tonic-gate err("stuff after {") if ($rest =~ /[^\s}]/); 9937c478bd9Sstevel@tonic-gate $cont_in = 0; 9947c478bd9Sstevel@tonic-gate last; 9957c478bd9Sstevel@tonic-gate } elsif (/\}/) { 9967c478bd9Sstevel@tonic-gate err("} while in parens/brackets") if (@cont_paren != 0); 9977c478bd9Sstevel@tonic-gate if (!$cont_special && $rest !~ /^\s*(while|else)\b/) { 9987c478bd9Sstevel@tonic-gate if ($rest =~ /^$/) { 9997c478bd9Sstevel@tonic-gate err("unexpected }"); 10007c478bd9Sstevel@tonic-gate } else { 10017c478bd9Sstevel@tonic-gate err("stuff after }"); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate $cont_in = 0; 10047c478bd9Sstevel@tonic-gate last; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate } elsif (/\:/ && $cont_case && @cont_paren == 0) { 10077c478bd9Sstevel@tonic-gate err("stuff after multi-line case") if ($rest !~ /$^/); 10087c478bd9Sstevel@tonic-gate $cont_in = 0; 10097c478bd9Sstevel@tonic-gate last; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate next; 10127c478bd9Sstevel@tonic-gatesection_ended: 10137c478bd9Sstevel@tonic-gate # End of a statement or if/while/for loop. Reset 10147c478bd9Sstevel@tonic-gate # cont_special and cont_macro based on the rest of the 10157c478bd9Sstevel@tonic-gate # line. 10167c478bd9Sstevel@tonic-gate $cont_special = ($rest =~ /^\s*$special/)? 1 : 0; 10177c478bd9Sstevel@tonic-gate $cont_macro = ($rest =~ /^\s*$macro/)? 1 : 0; 10187c478bd9Sstevel@tonic-gate $cont_case = 0; 10197c478bd9Sstevel@tonic-gate next; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate $cont_noerr = 0 if (!$cont_in); 10227c478bd9Sstevel@tonic-gate} 1023