xref: /illumos-gate/usr/src/tools/onbld/Checks/CmtBlk.py (revision 75eba5b6d79ed4d2ce3daf7b2806306b6b69a938)
1#! /usr/bin/python
2
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or http://www.opensolaris.org/os/licensing.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
26#
27
28#
29# Check that source files contain a valid comment block
30#
31
32import re, sys
33
34CmntChrs = r'#*!/\\";. '
35
36class CmtBlkError(Exception):
37	def __init__(self, lineno, seen, shouldbe):
38		Exception.__init__(self)
39		self.lineno = lineno
40		self.seen = seen
41		self.shouldbe = shouldbe
42
43def checkblock(block, blk_text):
44	line = block['start']
45	lictxt = block['block']
46
47	for actual, valid in map(lambda x, y: (x and x.lstrip(CmntChrs), y),
48			       lictxt, blk_text):
49		if actual != valid:
50			raise CmtBlkError(line, actual, valid)
51		line += 1
52
53def cmtblkchk(fh, blk_name, blk_text, filename=None,
54	      lenient=False, verbose=False, output=sys.stderr):
55
56	ret = 0
57	blocks = []
58	lic = []
59	in_cmt = False
60	start = 0
61	lineno = 0
62
63	StartText = '%s HEADER START' % blk_name
64	EndText = '%s HEADER END' % blk_name
65	full_text = [StartText, ''] + blk_text + ['', EndText]
66
67	StartRE = re.compile(r'^[%s ]*%s' % (CmntChrs, StartText))
68	EndRE = re.compile(r'^[%s ]*%s' % (CmntChrs, EndText))
69
70	if not filename:
71		filename = fh.name
72
73	for line in fh:
74		line = line.rstrip('\r\n')
75		lineno += 1
76
77		if StartRE.search(line):
78			in_cmt = True
79			lic.append(line)
80			start = lineno
81		elif in_cmt and EndRE.search(line):
82			in_cmt = False
83			lic.append(line)
84			blocks.append({'start':start, 'block':lic})
85			start = 0
86			lic = []
87		elif in_cmt:
88			lic.append(line)
89
90	if in_cmt:
91		output.write('%s: %s: Error: Incomplete %s block\n''' %
92		    (filename, start, blk_name))
93
94	# Check for no comment block, warn if we're not being lenient
95	if not len(blocks) and not lenient:
96		if not ret:
97			ret = 2
98		output.write("%s: Warning: No %s block\n" %
99			     (filename, blk_name))
100
101	# Check for multiple comment blocks
102	if len(blocks) > 1:
103		ret = 1
104		output.write('%s: Error: Multiple %s blocks\n'
105			     '    at lines %s\n''' %
106			     (filename, blk_name,
107			      ', '.join([str(x['start']) for x in blocks])))
108
109	# Validate each comment block
110	for b in blocks:
111		try:
112			checkblock(b, full_text)
113		except CmtBlkError, e:
114			ret = 1
115			output.write(
116				"%s: %d: Error: Invalid line in %s block:\n"
117				"    should be\n"
118				"    '%s'\n"
119				"    is\n"
120				"    '%s'\n" % (filename, e.lineno, blk_name,
121						e.shouldbe, e.seen))
122			break
123
124	if verbose and not ret:
125		output.write("%s: Valid %s block\n" %
126			     (filename, blk_name))
127
128	return ret
129