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# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
27#
28
29#
30# Check that source files contain a valid comment block
31#
32
33import re, sys
34
35CmntChrs = r'#*!/\\";. '
36
37class CmtBlkError(Exception):
38	def __init__(self, lineno, seen, shouldbe):
39		Exception.__init__(self)
40		self.lineno = lineno
41		self.seen = seen
42		self.shouldbe = shouldbe
43
44def checkblock(block, blk_text):
45	line = block['start']
46	lictxt = block['block']
47
48	for actual, valid in map(lambda x, y: (x and x.lstrip(CmntChrs), y),
49			       lictxt, blk_text):
50		if actual != valid:
51			raise CmtBlkError(line, actual, valid)
52		line += 1
53
54def cmtblkchk(fh, blk_name, blk_text, filename=None,
55	      lenient=False, verbose=False, output=sys.stderr):
56
57	ret = 0
58	blocks = []
59	lic = []
60	in_cmt = False
61	start = 0
62	lineno = 0
63
64	StartText = '%s HEADER START' % blk_name
65	EndText = '%s HEADER END' % blk_name
66	full_text = [StartText, ''] + blk_text + ['', EndText]
67
68	StartRE = re.compile(r'^[%s ]*%s' % (CmntChrs, StartText))
69	EndRE = re.compile(r'^[%s ]*%s' % (CmntChrs, EndText))
70
71	if not filename:
72		filename = fh.name
73
74	for line in fh:
75		line = line.rstrip('\r\n')
76		lineno += 1
77
78		if StartRE.search(line):
79			in_cmt = True
80			lic.append(line)
81			start = lineno
82		elif in_cmt and EndRE.search(line):
83			in_cmt = False
84			lic.append(line)
85			blocks.append({'start':start, 'block':lic})
86			start = 0
87			lic = []
88		elif in_cmt:
89			lic.append(line)
90
91	if in_cmt:
92		output.write('%s: %s: Error: Incomplete %s block\n''' %
93		    (filename, start, blk_name))
94
95	# Check for no comment block, warn if we're not being lenient
96	if not len(blocks) and not lenient:
97		if not ret:
98			ret = 2
99		output.write("%s: Warning: No %s block\n" %
100			     (filename, blk_name))
101
102	# Check for multiple comment blocks
103	if len(blocks) > 1:
104		ret = 1
105		output.write('%s: Error: Multiple %s blocks\n'
106			     '    at lines %s\n''' %
107			     (filename, blk_name,
108			      ', '.join([str(x['start']) for x in blocks])))
109
110	# Validate each comment block
111	for b in blocks:
112		try:
113			checkblock(b, full_text)
114		except CmtBlkError as e:
115			ret = 1
116			output.write(
117				"%s: %d: Error: Invalid line in %s block:\n"
118				"    should be\n"
119				"    '%s'\n"
120				"    is\n"
121				"    '%s'\n" % (filename, e.lineno, blk_name,
122						e.shouldbe, e.seen))
123			break
124
125	if verbose and not ret:
126		output.write("%s: Valid %s block\n" %
127			     (filename, blk_name))
128
129	return ret
130