178fe7221Sdduvall#!/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 678fe7221Sdduvall# Common Development and Distribution License (the "License"). 778fe7221Sdduvall# 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# 2278fe7221Sdduvall 237c478bd9Sstevel@tonic-gate# 24*c711c1a5SToomas Soome# Copyright 2015 Toomas Soome <tsoome@me.com> 25cdf0c1d5Smjnelson# Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2678fe7221Sdduvall# Use is subject to license terms. 277c478bd9Sstevel@tonic-gate# 287c478bd9Sstevel@tonic-gate# jstyle - check for some common stylistic errors. 297c478bd9Sstevel@tonic-gate# 307c478bd9Sstevel@tonic-gate 3178fe7221Sdduvallrequire 5.006; 3278fe7221Sdduvalluse Getopt::Std; 3378fe7221Sdduvalluse strict; 347c478bd9Sstevel@tonic-gate 3578fe7221Sdduvallmy $usage = 3678fe7221Sdduvall"usage: jstyle [-c] [-h] [-p] [-t] [-v] [-C] file ... 377c478bd9Sstevel@tonic-gate -c check continuation line indenting 387c478bd9Sstevel@tonic-gate -h perform heuristic checks that are sometimes wrong 397c478bd9Sstevel@tonic-gate -p perform some of the more picky checks 407c478bd9Sstevel@tonic-gate -t insist on indenting by tabs 417c478bd9Sstevel@tonic-gate -v verbose 427c478bd9Sstevel@tonic-gate -C don't check anything in header block comments 437c478bd9Sstevel@tonic-gate"; 447c478bd9Sstevel@tonic-gate 4578fe7221Sdduvallmy %opts; 4678fe7221Sdduvall 4778fe7221Sdduvall# Keep -s, as it's been around for a while. It just doesn't do anything 4878fe7221Sdduvall# anymore. 4978fe7221Sdduvallif (!getopts("chpstvC", \%opts)) { 507c478bd9Sstevel@tonic-gate print $usage; 51cdf0c1d5Smjnelson exit 2; 527c478bd9Sstevel@tonic-gate} 537c478bd9Sstevel@tonic-gate 5478fe7221Sdduvallmy $check_continuation = $opts{'c'}; 5578fe7221Sdduvallmy $heuristic = $opts{'h'}; 5678fe7221Sdduvallmy $picky = $opts{'p'}; 5778fe7221Sdduvallmy $tabs = $opts{'t'}; 5878fe7221Sdduvallmy $verbose = $opts{'v'}; 5978fe7221Sdduvallmy $ignore_hdr_comment = $opts{'C'}; 6078fe7221Sdduvall 6178fe7221Sdduvallmy ($filename, $line, $prev); 62cdf0c1d5Smjnelsonmy $err_stat = 0; # Exit status 6378fe7221Sdduvall 6478fe7221Sdduvallmy $fmt; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gateif ($verbose) { 677c478bd9Sstevel@tonic-gate $fmt = "%s: %d: %s\n%s\n"; 687c478bd9Sstevel@tonic-gate} else { 697c478bd9Sstevel@tonic-gate $fmt = "%s: %d: %s\n"; 707c478bd9Sstevel@tonic-gate} 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate# Note, following must be in single quotes so that \s and \w work right. 7378fe7221Sdduvallmy $typename = '(int|char|boolean|byte|short|long|float|double)'; 7478fe7221Sdduvallmy $keywords = '(for|if|while|switch|return|catch|synchronized|throw|assert)'; 7578fe7221Sdduvall# See perlre(1) for the meaning of (??{ ... }) 7678fe7221Sdduvallmy $annotations = ""; $annotations = qr/@\w+\((?:(?>[^()]+)|(??{ $annotations }))*\)/; 7778fe7221Sdduvallmy $generics = ""; $generics = qr/<(([\s\w,.?[\]]| & )+|(??{ $generics }))*>/; 7878fe7221Sdduvallmy $relationalops = qr/>=|<=|<|>|!=|==/; 7978fe7221Sdduvallmy $shiftops = qr/<<<|>>>|<<|>>/; 8078fe7221Sdduvallmy $shiftassignmentops = qr/[<>]{2,3}=/; 8178fe7221Sdduvallmy $assignmentops = qr/[-+\/*|&^%]?=/; 8278fe7221Sdduvall# These need to be in decreasing order of length 8378fe7221Sdduvallmy $allops = qr/$shiftassignmentops|$shiftops|$relationalops|$assignmentops/; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gateif ($#ARGV >= 0) { 8678fe7221Sdduvall foreach my $arg (@ARGV) { 877c478bd9Sstevel@tonic-gate if (!open(STDIN, $arg)) { 887c478bd9Sstevel@tonic-gate printf "%s: can not open\n", $arg; 897c478bd9Sstevel@tonic-gate } else { 907c478bd9Sstevel@tonic-gate &jstyle($arg); 9178fe7221Sdduvall close STDIN; 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate} else { 957c478bd9Sstevel@tonic-gate &jstyle("<stdin>"); 967c478bd9Sstevel@tonic-gate} 97cdf0c1d5Smjnelsonexit $err_stat; 987c478bd9Sstevel@tonic-gate 9978fe7221Sdduvallsub err($) { 100*c711c1a5SToomas Soome if ($verbose) { 101*c711c1a5SToomas Soome printf $fmt, $filename, $., $_[0], $line; 102*c711c1a5SToomas Soome } else { 103*c711c1a5SToomas Soome printf $fmt, $filename, $., $_[0]; 104*c711c1a5SToomas Soome } 105cdf0c1d5Smjnelson $err_stat = 1; 1067c478bd9Sstevel@tonic-gate} 1077c478bd9Sstevel@tonic-gate 10878fe7221Sdduvallsub jstyle($) { 10978fe7221Sdduvall 11078fe7221Sdduvallmy $in_comment = 0; 11178fe7221Sdduvallmy $in_header_comment = 0; 11278fe7221Sdduvallmy $in_continuation = 0; 11378fe7221Sdduvallmy $in_class = 0; 11478fe7221Sdduvallmy $in_declaration = 0; 11578fe7221Sdduvallmy $nextok = 0; 11678fe7221Sdduvallmy $nocheck = 0; 11778fe7221Sdduvallmy $expect_continuation = 0; 11878fe7221Sdduvallmy $continuation_indent; 11978fe7221Sdduvallmy $okmsg; 12078fe7221Sdduvallmy $comment_prefix; 12178fe7221Sdduvallmy $comment_done; 12278fe7221Sdduvallmy $cpp_comment; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate$filename = $_[0]; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gateline: while (<STDIN>) { 1277c478bd9Sstevel@tonic-gate s/\r?\n$//; # strip return and newline 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate # save the original line, then remove all text from within 1307c478bd9Sstevel@tonic-gate # double or single quotes, we do not want to check such text. 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate $line = $_; 1337c478bd9Sstevel@tonic-gate s/"[^"]*"/\"\"/g; 1347c478bd9Sstevel@tonic-gate s/'.'/''/g; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate # an /* END JSTYLED */ comment ends a no-check block. 1377c478bd9Sstevel@tonic-gate if ($nocheck) { 1387c478bd9Sstevel@tonic-gate if (/\/\* *END *JSTYLED *\*\//) { 1397c478bd9Sstevel@tonic-gate $nocheck = 0; 1407c478bd9Sstevel@tonic-gate } else { 1417c478bd9Sstevel@tonic-gate next line; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate # a /*JSTYLED*/ comment indicates that the next line is ok. 1467c478bd9Sstevel@tonic-gate if ($nextok) { 1477c478bd9Sstevel@tonic-gate if ($okmsg) { 14878fe7221Sdduvall err($okmsg); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate $nextok = 0; 1517c478bd9Sstevel@tonic-gate $okmsg = 0; 1527c478bd9Sstevel@tonic-gate if (/\/\* *JSTYLED.*\*\//) { 1537c478bd9Sstevel@tonic-gate /^.*\/\* *JSTYLED *(.*) *\*\/.*$/; 1547c478bd9Sstevel@tonic-gate $okmsg = $1; 1557c478bd9Sstevel@tonic-gate $nextok = 1; 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate $prev = $line; 1587c478bd9Sstevel@tonic-gate next line; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate # remember whether we expect to be inside a continuation line. 1627c478bd9Sstevel@tonic-gate $in_continuation = $expect_continuation; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate # check for proper continuation line. blank lines 1657c478bd9Sstevel@tonic-gate # in the middle of the 1667c478bd9Sstevel@tonic-gate # continuation do not count. 1677c478bd9Sstevel@tonic-gate # XXX - only check within functions. 1687c478bd9Sstevel@tonic-gate if ($check_continuation && $expect_continuation && $in_class && 1697c478bd9Sstevel@tonic-gate !/^\s*$/) { 1707c478bd9Sstevel@tonic-gate # continuation line must start with whitespace of 1717c478bd9Sstevel@tonic-gate # previous line, plus either 4 spaces or a tab, but 1727c478bd9Sstevel@tonic-gate # do not check lines that start with a string constant 1737c478bd9Sstevel@tonic-gate # since they are often shifted to the left to make them 1747c478bd9Sstevel@tonic-gate # fit on the line. 1757c478bd9Sstevel@tonic-gate if (!/^$continuation_indent \S/ && 1767c478bd9Sstevel@tonic-gate !/^$continuation_indent\t\S/ && !/^\s*"/) { 17778fe7221Sdduvall err("continuation line improperly indented"); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate $expect_continuation = 0; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate # a /* BEGIN JSTYLED */ comment starts a no-check block. 1837c478bd9Sstevel@tonic-gate if (/\/\* *BEGIN *JSTYLED *\*\//) { 1847c478bd9Sstevel@tonic-gate $nocheck = 1; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate # a /*JSTYLED*/ comment indicates that the next line is ok. 1887c478bd9Sstevel@tonic-gate if (/\/\* *JSTYLED.*\*\//) { 1897c478bd9Sstevel@tonic-gate /^.*\/\* *JSTYLED *(.*) *\*\/.*$/; 1907c478bd9Sstevel@tonic-gate $okmsg = $1; 1917c478bd9Sstevel@tonic-gate $nextok = 1; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate if (/\/\/ *JSTYLED/) { 1947c478bd9Sstevel@tonic-gate /^.*\/\/ *JSTYLED *(.*)$/; 1957c478bd9Sstevel@tonic-gate $okmsg = $1; 1967c478bd9Sstevel@tonic-gate $nextok = 1; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate # is this the beginning or ending of a class? 2007c478bd9Sstevel@tonic-gate if (/^(public\s+)*\w(class|interface)\s/) { 2017c478bd9Sstevel@tonic-gate $in_class = 1; 2027c478bd9Sstevel@tonic-gate $in_declaration = 1; 2037c478bd9Sstevel@tonic-gate $prev = $line; 2047c478bd9Sstevel@tonic-gate next line; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate if (/^}\s*(\/\*.*\*\/\s*)*$/) { 2077c478bd9Sstevel@tonic-gate $in_class = 0; 2087c478bd9Sstevel@tonic-gate $prev = $line; 2097c478bd9Sstevel@tonic-gate next line; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 21278fe7221Sdduvall if ($comment_done) { 21378fe7221Sdduvall $in_comment = 0; 21478fe7221Sdduvall $in_header_comment = 0; 21578fe7221Sdduvall $comment_done = 0; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate # does this looks like the start of a block comment? 21878fe7221Sdduvall if (/^\s*\/\*/ && !/^\s*\/\*.*\*\//) { 21978fe7221Sdduvall if (/^\s*\/\*./ && !/^\s*\/\*\*$/) { 22078fe7221Sdduvall err("improper first line of block comment"); 2217c478bd9Sstevel@tonic-gate } 22278fe7221Sdduvall if (!/^(\t| )*\/\*/) { 22378fe7221Sdduvall err("block comment not indented properly"); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate $in_comment = 1; 22678fe7221Sdduvall /^(\s*)\//; 22778fe7221Sdduvall $comment_prefix = $1; 22878fe7221Sdduvall if ($comment_prefix eq "") { 2297c478bd9Sstevel@tonic-gate $in_header_comment = 1; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate $prev = $line; 2327c478bd9Sstevel@tonic-gate next line; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate # are we still in the block comment? 23578fe7221Sdduvall if ($in_comment) { 23678fe7221Sdduvall if (/^$comment_prefix \*\/$/) { 23778fe7221Sdduvall $comment_done = 1; 23878fe7221Sdduvall } elsif (/\*\//) { 23978fe7221Sdduvall $comment_done = 1; 24078fe7221Sdduvall err("improper block comment close") 24178fe7221Sdduvall unless ($ignore_hdr_comment && $in_header_comment); 24278fe7221Sdduvall } elsif (!/^$comment_prefix \*[ \t]/ && 24378fe7221Sdduvall !/^$comment_prefix \*$/) { 24478fe7221Sdduvall err("improper block comment") 24578fe7221Sdduvall unless ($ignore_hdr_comment && $in_header_comment); 24678fe7221Sdduvall } 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if ($in_header_comment && $ignore_hdr_comment) { 2507c478bd9Sstevel@tonic-gate $prev = $line; 2517c478bd9Sstevel@tonic-gate next line; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate # check for errors that might occur in comments and in code. 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate # check length of line. 2577c478bd9Sstevel@tonic-gate # first, a quick check to see if there is any chance of being too long. 2587c478bd9Sstevel@tonic-gate if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) { 2597c478bd9Sstevel@tonic-gate # yes, there is a chance. 2607c478bd9Sstevel@tonic-gate # replace tabs with spaces and check again. 26178fe7221Sdduvall my $eline = $line; 2627c478bd9Sstevel@tonic-gate 1 while $eline =~ 2637c478bd9Sstevel@tonic-gate s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; 2647c478bd9Sstevel@tonic-gate if (length($eline) > 80) { 26578fe7221Sdduvall err("line > 80 characters"); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 269dd2b4cceSdduvall # Allow spaces to be used to draw pictures in header comments, but 270dd2b4cceSdduvall # disallow blocks of spaces almost everywhere else. In particular, 271dd2b4cceSdduvall # five spaces are also allowed at the end of a line's indentation 272dd2b4cceSdduvall # if the rest of the line belongs to a block comment. 273dd2b4cceSdduvall if (!$in_header_comment && 274dd2b4cceSdduvall /[^ ] / && 275dd2b4cceSdduvall !(/^\t* \*/ && !/^\t* \*.* /)) { 27678fe7221Sdduvall err("spaces instead of tabs"); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate if ($tabs && /^ / && !/^ \*[ \t\/]/ && !/^ \*$/ && 2797c478bd9Sstevel@tonic-gate (!/^ \w/ || $in_class != 0)) { 28078fe7221Sdduvall err("indent by spaces instead of tabs"); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate if (!$in_comment && (/^(\t )* {1,3}\S/ || /^(\t )* {5,7}\S/) && 2837c478bd9Sstevel@tonic-gate !(/^\s*[-+|&\/?:=]/ || ($prev =~ /,\s*$/))) { 28478fe7221Sdduvall err("indent not a multiple of 4"); 2857c478bd9Sstevel@tonic-gate } 28678fe7221Sdduvall if (/\s$/) { 28778fe7221Sdduvall err("space or tab at end of line"); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gateif (0) { 2907c478bd9Sstevel@tonic-gate if (/^[\t]+ [^ \t\*]/ || /^[\t]+ \S/ || /^[\t]+ \S/) { 29178fe7221Sdduvall err("continuation line not indented by 4 spaces"); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate} 29478fe7221Sdduvall if (/\/\//) { 29578fe7221Sdduvall $cpp_comment = 1; 2967c478bd9Sstevel@tonic-gate } 29778fe7221Sdduvall if (!$cpp_comment && /[^ \t(\/]\/\*/ && !/\w\(\/\*.*\*\/\);/) { 29878fe7221Sdduvall err("comment preceded by non-blank"); 2997c478bd9Sstevel@tonic-gate } 30078fe7221Sdduvall if (/\t +\t/) { 30178fe7221Sdduvall err("spaces between tabs"); 30278fe7221Sdduvall } 30378fe7221Sdduvall if (/ \t+ /) { 30478fe7221Sdduvall err("tabs between spaces"); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if ($in_comment) { # still in comment 3087c478bd9Sstevel@tonic-gate $prev = $line; 3097c478bd9Sstevel@tonic-gate next line; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 31278fe7221Sdduvall if (!$cpp_comment && ((/\/\*\S/ && !/\/\*\*/) || /\/\*\*\S/)) { 31378fe7221Sdduvall err("missing blank after open comment"); 3147c478bd9Sstevel@tonic-gate } 31578fe7221Sdduvall if (!$cpp_comment && /\S\*\//) { 31678fe7221Sdduvall err("missing blank before close comment"); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate # check for unterminated single line comments. 3197c478bd9Sstevel@tonic-gate if (/\S.*\/\*/ && !/\S.*\/\*.*\*\//) { 32078fe7221Sdduvall err("unterminated single line comment"); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 32378fe7221Sdduvall # delete any comments and check everything else. Be sure to leave 32478fe7221Sdduvall # //-style comments intact, and if there are multiple comments on a 32578fe7221Sdduvall # line, preserve whatever's in between. 32678fe7221Sdduvall s/(?<!\/)\/\*.*?\*\///g; 32778fe7221Sdduvall # Check for //-style comments only outside of block comments 32878fe7221Sdduvall if (m{(//(?!$))} && substr($_, $+[0], 1) !~ /[ \t]/) { 32978fe7221Sdduvall err("missing blank after start comment"); 33078fe7221Sdduvall } 3317c478bd9Sstevel@tonic-gate s/\/\/.*$//; # C++ comments 33278fe7221Sdduvall $cpp_comment = 0; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate # delete any trailing whitespace; we have already checked for that. 3357c478bd9Sstevel@tonic-gate s/\s*$//; 3367c478bd9Sstevel@tonic-gate 33778fe7221Sdduvall # We don't style (yet) what's inside annotations, so just delete them. 33878fe7221Sdduvall s/$annotations//; 33978fe7221Sdduvall 3407c478bd9Sstevel@tonic-gate # following checks do not apply to text in comments. 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate # if it looks like an operator at the end of the line, and it is 3437c478bd9Sstevel@tonic-gate # not really the end of a comment (...*/), and it is not really 3447c478bd9Sstevel@tonic-gate # a label (done:), and it is not a case label (case FOO:), 3457c478bd9Sstevel@tonic-gate # or we are not in a function definition (ANSI C style) and the 3467c478bd9Sstevel@tonic-gate # operator is a "," (to avoid hitting "int\nfoo(\n\tint i,\n\tint j)"), 3477c478bd9Sstevel@tonic-gate # or we are in a function and the operator is a 3487c478bd9Sstevel@tonic-gate # "*" (to avoid hitting on "char*\nfunc()"). 3497c478bd9Sstevel@tonic-gate if ((/[-+|&\/?:=]$/ && !/\*\/$/ && !/^\s*\w*:$/ && 3507c478bd9Sstevel@tonic-gate !/^\s\s*case\s\s*\w*:$/) || 3517c478bd9Sstevel@tonic-gate /,$/ || 3527c478bd9Sstevel@tonic-gate ($in_class && /\*$/)) { 3537c478bd9Sstevel@tonic-gate $expect_continuation = 1; 3547c478bd9Sstevel@tonic-gate if (!$in_continuation) { 3557c478bd9Sstevel@tonic-gate /^(\s*)\S/; 3567c478bd9Sstevel@tonic-gate $continuation_indent = $1; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate } 35978fe7221Sdduvall while (/($allops)/g) { 36078fe7221Sdduvall my $z = substr($_, $-[1] - 1); 36178fe7221Sdduvall if ($z !~ /\s\Q$1\E(?:\s|$)/) { 36278fe7221Sdduvall my $m = $1; 36378fe7221Sdduvall my $shift; 36478fe7221Sdduvall # @+ is available only in the currently active 36578fe7221Sdduvall # dynamic scope. Assign it to a new variable 36678fe7221Sdduvall # to pass it into the if block. 36778fe7221Sdduvall if ($z =~ /($generics)/ && 36878fe7221Sdduvall ($shift = $+[1])) { 36978fe7221Sdduvall pos $_ += $shift; 37078fe7221Sdduvall next; 37178fe7221Sdduvall } 37278fe7221Sdduvall 37378fe7221Sdduvall # These need to be in decreasing order of length 37478fe7221Sdduvall # (violable as long as there's no ambiguity) 37578fe7221Sdduvall my $nospace = "missing space around"; 37678fe7221Sdduvall if ($m =~ $shiftassignmentops) { 37778fe7221Sdduvall err("$nospace assignment operator"); 37878fe7221Sdduvall } elsif ($m =~ $shiftops) { 37978fe7221Sdduvall err("$nospace shift operator"); 38078fe7221Sdduvall } elsif ($m =~ $relationalops) { 38178fe7221Sdduvall err("$nospace relational operator"); 38278fe7221Sdduvall } elsif ($m =~ $assignmentops) { 38378fe7221Sdduvall err("$nospace assignment operator"); 38478fe7221Sdduvall } 38578fe7221Sdduvall } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate if (/[,;]\S/ && !/\bfor \(;;\)/) { 38878fe7221Sdduvall err("comma or semicolon followed by non-blank"); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate # allow "for" statements to have empty "while" clauses 3917c478bd9Sstevel@tonic-gate if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) { 39278fe7221Sdduvall err("comma or semicolon preceded by blank"); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gateif (0) { 3957c478bd9Sstevel@tonic-gate if (/^\s*(&&|\|\|)/) { 39678fe7221Sdduvall err("improper boolean continuation"); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate} 3997c478bd9Sstevel@tonic-gate if ($picky && /\S *(&&|\|\|)/ || /(&&|\|\|) *\S/) { 40078fe7221Sdduvall err("more than one space around boolean operator"); 4017c478bd9Sstevel@tonic-gate } 40278fe7221Sdduvall if (/\b$keywords\(/) { 40378fe7221Sdduvall err("missing space between keyword and paren"); 4047c478bd9Sstevel@tonic-gate } 40578fe7221Sdduvall if (/(\b$keywords\b.*){2,}/ && !/\bcase\b.*/) { # "case" excepted 40678fe7221Sdduvall err("more than one keyword on line"); 4077c478bd9Sstevel@tonic-gate } 40878fe7221Sdduvall if (/\b$keywords\s\s+\(/ && 4097c478bd9Sstevel@tonic-gate !/^#if\s+\(/) { 41078fe7221Sdduvall err("extra space between keyword and paren"); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate # try to detect "func (x)" but not "if (x)" or 4137c478bd9Sstevel@tonic-gate # "int (*func)();" 4147c478bd9Sstevel@tonic-gate if (/\w\s\(/) { 41578fe7221Sdduvall my $save = $_; 4167c478bd9Sstevel@tonic-gate # strip off all keywords on the line 41778fe7221Sdduvall s/\b$keywords\s\(/XXX(/g; 4187c478bd9Sstevel@tonic-gate #s/\b($typename|void)\s+\(+/XXX(/og; 4197c478bd9Sstevel@tonic-gate if (/\w\s\(/) { 42078fe7221Sdduvall err("extra space between function name and left paren"); 4217c478bd9Sstevel@tonic-gate } 42278fe7221Sdduvall $_ = $save; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate if (/\(\s/) { 42578fe7221Sdduvall err("whitespace after left paren"); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate # allow "for" statements to have empty "continue" clauses 4287c478bd9Sstevel@tonic-gate if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) { 42978fe7221Sdduvall err("whitespace before right paren"); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate if (/^\s*\(void\)[^ ]/) { 43278fe7221Sdduvall err("missing space after (void) cast"); 4337c478bd9Sstevel@tonic-gate } 434*c711c1a5SToomas Soome if (/\S\{/ && !/\{\{/) { 43578fe7221Sdduvall err("missing space before left brace"); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate if ($in_class && /^\s+{/ && ($prev =~ /\)\s*$/)) { 43878fe7221Sdduvall err("left brace starting a line"); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate if (/}(else|while)/) { 44178fe7221Sdduvall err("missing space after right brace"); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate if (/}\s\s+(else|while)/) { 44478fe7221Sdduvall err("extra space after right brace"); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate if (/\b$typename\*/o) { 44778fe7221Sdduvall err("missing space between type name and *"); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate if ($heuristic) { 4507c478bd9Sstevel@tonic-gate # cannot check this everywhere due to "struct {\n...\n} foo;" 4517c478bd9Sstevel@tonic-gate if ($in_class && !$in_declaration && 4527c478bd9Sstevel@tonic-gate /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|)*$/ && 4537c478bd9Sstevel@tonic-gate !/} (else|while)/ && !/}}/) { 45478fe7221Sdduvall err("possible bad text following right brace"); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate # cannot check this because sub-blocks in 4577c478bd9Sstevel@tonic-gate # the middle of code are ok 4587c478bd9Sstevel@tonic-gate if ($in_class && /^\s+{/) { 45978fe7221Sdduvall err("possible left brace starting a line"); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate if (/^\s*else\W/) { 4637c478bd9Sstevel@tonic-gate if ($prev =~ /^\s*}$/) { 46478fe7221Sdduvall my $str = "else and right brace should be on same line"; 4657c478bd9Sstevel@tonic-gate printf $fmt, $filename, $., $str, $prev; 4667c478bd9Sstevel@tonic-gate if ($verbose) { 4677c478bd9Sstevel@tonic-gate printf "%s\n", $line; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate $prev = $line; 4727c478bd9Sstevel@tonic-gate} 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gateif ($picky && $prev eq "") { 47578fe7221Sdduvall err("last line in file is blank"); 4767c478bd9Sstevel@tonic-gate} 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate} 479