| #!/usr/bin/env python |
| # Copyright (c) 2006 The Regents of The University of Michigan |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer; |
| # redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution; |
| # neither the name of the copyright holders nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| # |
| # Authors: Nathan Binkert |
| |
| from getopt import getopt, GetoptError |
| |
| import re |
| import sys |
| |
| tabsize = 8 |
| |
| lead = re.compile(r'^([ \t])+') |
| trail = re.compile(r'[ \t]+$') |
| any_control = re.compile(r'\b(if|while|for)[ \t]*[(]') |
| good_control = re.compile(r'\b(if|while|for) [(]') |
| |
| def linelen(line): |
| tabs = line.count('\t') |
| if not tabs: |
| return len(line) |
| |
| count = 0 |
| for c in line: |
| if c == '\t': |
| count += tabsize - count % tabsize |
| else: |
| count += 1 |
| |
| return count |
| |
| toolong = 0 |
| toolong80 = 0 |
| leadtabs = 0 |
| trailwhite = 0 |
| badcontrol = 0 |
| cret = 0 |
| |
| def validate(filename, verbose, code): |
| global toolong, toolong80, leadtabs, trailwhite, badcontrol, cret |
| |
| def msg(lineno, line, message): |
| print '%s:%d>' % (filename, lineno + 1), message |
| if verbose > 2: |
| print line |
| |
| def bad(): |
| if code is not None: |
| sys.exit(code) |
| |
| cpp = filename.endswith('.cc') or filename.endswith('.hh') |
| py = filename.endswith('.py') |
| |
| if py + cpp != 1: |
| raise AttributeError, \ |
| "I don't know how to deal with the file %s" % filename |
| |
| try: |
| f = file(filename, 'r') |
| except OSError: |
| if verbose > 0: |
| print 'could not open file %s' % filename |
| bad() |
| return |
| |
| for i,line in enumerate(f): |
| line = line.rstrip('\n') |
| |
| # no carriage returns |
| if line.find('\r') != -1: |
| cret += 1 |
| if verbose > 1: |
| msg(i, line, 'carriage return found') |
| bad() |
| |
| # lines max out at 79 chars |
| llen = linelen(line) |
| if llen > 79: |
| toolong += 1 |
| if llen == 80: |
| toolong80 += 1 |
| if verbose > 1: |
| msg(i, line, 'line too long (%d chars)' % llen) |
| bad() |
| |
| # no tabs used to indent |
| match = lead.search(line) |
| if match and match.group(1).find('\t') != -1: |
| leadtabs += 1 |
| if verbose > 1: |
| msg(i, line, 'using tabs to indent') |
| bad() |
| |
| # no trailing whitespace |
| if trail.search(line): |
| trailwhite +=1 |
| if verbose > 1: |
| msg(i, line, 'trailing whitespace') |
| bad() |
| |
| # for c++, exactly one space betwen if/while/for and ( |
| if cpp: |
| match = any_control.search(line) |
| if match and not good_control.search(line): |
| badcontrol += 1 |
| if verbose > 1: |
| msg(i, line, 'improper spacing after %s' % match.group(1)) |
| bad() |
| |
| if __name__ == '__main__': |
| progname = sys.argv[0] |
| |
| def usage(code=None): |
| print >>sys.stderr, '''%s [-n] [-q] [-v] <filenames>''' % progname |
| if code is not None: |
| sys.exit(code) |
| |
| try: |
| opts, args = getopt(sys.argv[1:], '-nv') |
| except GetoptError: |
| usage(2) |
| |
| code = 1 |
| verbose = 1 |
| for opt,arg in opts: |
| if opt == '-n': |
| code = None |
| if opt == '-q': |
| verbose -= 1 |
| if opt == '-v': |
| verbose += 1 |
| |
| for filename in args: |
| validate(filename, verbose=verbose, code=code) |
| |
| if verbose > 0: |
| print '''\ |
| %d violations of lines over 79 chars. %d of which are 80 chars exactly. |
| %d cases of whitespace at the end of a line. |
| %d cases of tabs to indent. |
| %d bad parens after if/while/for. |
| %d carriage returns found. |
| ''' % (toolong, toolong80, trailwhite, leadtabs, badcontrol, cret) |
| |