xref: /freebsd/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
1#!/usr/local/bin/perl
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
23#
24# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2014, 2016 by Delphix. All rights reserved.
30#
31
32require 5.8.4;
33
34$PNAME = $0;
35$PNAME =~ s:.*/::;
36$USAGE = "Usage: $PNAME [file ...]\n";
37$errs = 0;
38
39sub err
40{
41	my($msg) = @_;
42
43	print "$file: $lineno: $msg\n";
44	$errs++;
45}
46
47sub dstyle
48{
49	open(FILE, "$file");
50	$lineno = 0;
51	$inclause = 0;
52	$skipnext = 0;
53
54	while (<FILE>) {
55		$lineno++;
56
57		chop;
58
59		if ($skipnext) {
60			$skipnext = 0;
61			next;
62		}
63
64		#
65		# Amazingly, some ident strings are longer than 80 characters!
66		#
67		if (/^#pragma ident/) {
68			next;
69		}
70
71		#
72		# The algorithm to calculate line length from cstyle.
73		#
74		$line = $_;
75		if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) {
76			# yes, there is a chance.
77			# replace tabs with spaces and check again.
78			$eline = $line;
79			1 while $eline =~
80			    s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
81
82			if (length($eline) > 80) {
83				err "line > 80 characters";
84			}
85		}
86
87		if (/\/\*DSTYLED\*\//) {
88			$skipnext = 1;
89			next;
90		}
91
92		if (/^#pragma/) {
93			next;
94		}
95
96		if (/^#include/) {
97			next;
98		}
99
100		#
101		# Before we do any more analysis, we want to prune out any
102		# quoted strings.  This is a bit tricky because we need
103		# to be careful of backslashed quotes within quoted strings.
104		# I'm sure there is a very crafty way to do this with a
105		# single regular expression, but that will have to wait for
106		# somone with better regex juju that I; we do this by first
107		# eliminating the backslashed quotes, and then eliminating
108		# whatever quoted strings are left.  Note that we eliminate
109		# the string by replacing it with "quotedstr"; this is to
110		# allow lines to end with a quoted string.  (If we simply
111		# eliminated the quoted string, dstyle might complain about
112		# the line ending in a space or tab.)
113		#
114		s/\\\"//g;
115		s/\"[^\"]*\"/quotedstr/g;
116
117		if (/[ \t]$/) {
118			err "space or tab at end of line";
119		}
120
121		if (/^[\t]+[ ]+[\t]+/) {
122			err "spaces between tabs";
123		}
124
125		if (/^[\t]* \*/) {
126			next;
127		}
128
129		if (/^        /) {
130			err "indented by spaces not tabs";
131		}
132
133		if (/^{}$/) {
134			next;
135		}
136
137		if (!/^enum/ && !/^\t*struct/ && !/^\t*union/ && !/^typedef/ &&
138		    !/^translator/ && !/^provider/ && !/\tif / &&
139		    !/ else /) {
140			if (/[\w\s]+{/) {
141				err "left brace not on its own line";
142			}
143
144			if (/{[\w\s]+/) {
145				err "left brace not on its own line";
146			}
147		}
148
149		if (!/;$/ && !/\t*}$/ && !/ else /) {
150			if (/[\w\s]+}/) {
151				err "right brace not on its own line";
152			}
153
154			if (/}[\w\s]+/) {
155				err "right brace not on its own line";
156			}
157		}
158
159		if (/^}/) {
160			$inclause = 0;
161		}
162
163		if (!$inclause && /^[\w ]+\//) {
164			err "predicate not at beginning of line";
165		}
166
167		if (!$inclause && /^\/[ \t]+\w/) {
168			err "space between '/' and expression in predicate";
169		}
170
171		if (!$inclause && /\w[ \t]+\/$/) {
172			err "space between expression and '/' in predicate";
173		}
174
175		if (!$inclause && /\s,/) {
176			err "space before comma in probe description";
177		}
178
179		if (!$inclause && /\w,[\w\s]/ && !/;$/) {
180			if (!/extern/ && !/\(/ && !/inline/) {
181				err "multiple probe descriptions on same line";
182			}
183		}
184
185		if ($inclause && /sizeof\(/) {
186			err "missing space after sizeof";
187		}
188
189		if ($inclause && /^[\w ]/) {
190			err "line doesn't begin with a tab";
191		}
192
193		if ($inclause && /,[\w]/) {
194			err "comma without trailing space";
195		}
196
197		if (/\w&&/ || /&&\w/ || /\w\|\|/ || /\|\|\w/) {
198			err "logical operator not set off with spaces";
199		}
200
201		#
202		# We want to catch "i<0" variants, but we don't want to
203		# erroneously flag translators.
204		#
205		if (!/\w<\w+>\(/) {
206			if (/\w>/ || / >\w/ || /\w</ || /<\w/) {
207				err "comparison operator not set " .
208				    "off with spaces";
209			}
210		}
211
212		if (/\w==/ || /==\w/ || /\w<=/ || />=\w/ || /\w!=/ || /!=\w/) {
213			err "comparison operator not set off with spaces";
214		}
215
216		if (/\w=/ || /=\w/) {
217			err "assignment operator not set off with spaces";
218		}
219
220		if (/^{/) {
221			$inclause = 1;
222		}
223        }
224}
225
226foreach $arg (@ARGV) {
227	if (-f $arg) {
228		push(@files, $arg);
229	} else {
230		die "$PNAME: $arg is not a valid file\n";
231	}
232}
233
234die $USAGE if (scalar(@files) == 0);
235
236foreach $file (@files) {
237	dstyle($file);
238}
239
240exit($errs != 0);
241