1# Copyright (C) 2011 by the Massachusetts Institute of Technology. 2# All rights reserved. 3# 4# Export of this software from the United States of America may 5# require a specific license from the United States Government. 6# It is the responsibility of any person or organization contemplating 7# export to obtain such a license before exporting. 8# 9# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 10# distribute this software and its documentation for any purpose and 11# without fee is hereby granted, provided that the above copyright 12# notice appear in all copies and that both that copyright notice and 13# this permission notice appear in supporting documentation, and that 14# the name of M.I.T. not be used in advertising or publicity pertaining 15# to distribution of the software without specific, written prior 16# permission. Furthermore if you modify this software you must label 17# your software as modified software and not distribute it in such a 18# fashion that it might be confused with the original M.I.T. software. 19# M.I.T. makes no representations about the suitability of 20# this software for any purpose. It is provided "as is" without express 21# or implied warranty. 22 23# This program is intended to be used by "make check-copyright". It 24# checks for violations of the coding standards related to copyright 25# and license statements in source code comments. 26 27import os 28import sys 29import re 30 31def warn(fname, ln, msg): 32 print('%s: %d: %s' % (fname, ln + 1, msg)) 33 34def indicates_license(line): 35 return 'Copyright' in line or 'COPYRIGHT' in line or 'License' in line 36 37# Check a comment for boilerplate violations. Return true if the comment 38# is a license statement. 39def check_comment(comment, fname, ln, code_seen, nonlicense_seen): 40 text_seen = False 41 is_license = False 42 for line in comment: 43 if not is_license and indicates_license(line): 44 is_license = True 45 if text_seen: 46 warn(fname, ln, 'License begins after first line of comment') 47 elif code_seen: 48 warn(fname, ln, 'License after code') 49 elif nonlicense_seen: 50 warn(fname, ln, 'License after non-license comments') 51 break 52 # DB2 licenses start with '/*-' and we don't want to change them. 53 if line != '' and line != '-': 54 text_seen = True 55 return is_license 56 57def check_file(lines, fname): 58 # Skip emacs mode line if present. 59 ln = 0 60 if '-*- mode: c;' in lines[ln]: 61 ln += 1 62 63 # Check filename comment if present. 64 m = re.match(r'/\* ([^ ]*)( - .*)? \*/', lines[ln]) 65 if m: 66 if m.group(1) != fname: 67 warn(fname, ln, 'Wrong filename in comment') 68 ln += 1 69 70 # Scan for license statements. 71 in_comment = False 72 code_seen = False 73 nonlicense_seen = False 74 for line in lines[ln:]: 75 # Strip out whitespace and comments contained within a line. 76 if not in_comment: 77 line = re.sub(r'/\*.*?\*/', '', line) 78 line = line.strip() 79 80 if not in_comment and '/*' in line: 81 (line, sep, comment_part) = line.partition('/*') 82 comment = [comment_part.strip()] 83 comment_starts_at = ln 84 in_comment = True 85 elif in_comment and '*/' not in line: 86 comment.append(line.lstrip('*').lstrip()) 87 elif in_comment: 88 (comment_part, sep, line) = line.partition('*/') 89 comment.append(comment_part.strip()) 90 is_license = check_comment(comment, fname, comment_starts_at, 91 code_seen, nonlicense_seen) 92 nonlicense_seen = nonlicense_seen or not is_license 93 in_comment = False 94 elif line.strip() != '': 95 code_seen = True 96 97 ln += 1 98 99for fname in sys.argv[1:]: 100 if fname.startswith('./'): 101 fname = fname[2:] 102 f = open(fname) 103 lines = f.readlines() 104 f.close() 105 check_file(lines, fname) 106