remove-addrefs.py
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 14 2454966b9fb5748af44366d5d8f5806ffdb8d1e9
permissions -rw-r--r--
State as of now

#!/usr/bin/env python

"""Search for uses of NS_ADDREF and NS_IF_ADDREF
in the codebase, removing them or replacing them with simple statements as
appropriate.

Usage: remove-addrefs.py src-directory

A patch file is written to stdout"""

import sys, os, re

directory, = sys.argv[1:]

def writePatchHunk(oldText, newText, file, oldLineNo, newLineNo):
    """Writes a patch in unified diff format with no context.
    Returns the number of lines added (positive) or removed (negative)
    from the file."""

    oldLines = oldText.splitlines(True)
    newLines = newText.splitlines(True)
    print "--- %s" % file
    print "+++ %s" % file
    print "@@ -%(oldLineNo)s,%(oldcount)s +%(newLineNo)s,%(newcount)s @@" % \
	{'oldLineNo': oldLineNo,
         'newLineNo': newLineNo,
	 'oldcount': len(oldLines),
	 'newcount': len(newLines) }
    for line in oldLines:
	print "-%s" % line,
    for line in newLines:
	print "+%s" % line,

    return len(newLines) - len(oldLines)

finder = re.compile(r'(?P<whitespace>\s*)NS_(?:IF_)?ADDREF(?:_THIS)?\s*\((?P<contents>.*)\)\s*;\s*(?://.*)?(\\\n)?$')
fallback = re.compile(r'NS_(IF_)?ADDREF')

def run_single(file):
    """Replace statements in a single file."""

    fd = open(file, 'r')
    lines = fd.readlines()
    fd.close()

    oldLineNo = 0
    newLineNo = 0
    while oldLineNo < len(lines):
        oldLineNo += 1
        newLineNo += 1

        line = lines[oldLineNo - 1]
        m = finder.match(line)
        if m:
            contents = m.group('contents')
            if contents.find('=') != -1:
                # print >>sys.stderr, "File %s line %s: keeping %s" % (file, oldLineNo, contents)
                newLine = "%s%s;\n" % (m.group('whitespace'), contents)
                newLineNo += writePatchHunk(line, newLine, file, oldLineNo, newLineNo)
            else:
                # Look backwards to see if there's an unbraced "if"
                testLineNo = oldLineNo
                while True:
                    testLineNo -= 1
                    if testLineNo == -1:
                        raise "Something went wrong: file %s line %s" % (file, oldLineNo)
                    testLine = lines[testLineNo - 1]
                    testLine = testLine.strip(" \n\\")
                    if testLine.endswith(';') or testLine.endswith('{') or testLine.endswith('}'):
                        break
                    if testLine.startswith('if') or testLine.startswith('else'):
                        raise "Unbraced if: file %s line %s" % (file, oldLineNo)
                        
                newLineNo += writePatchHunk(line, "", file, oldLineNo, newLineNo)
        else:
            f = line.find('//')
            if f != -1:
                line = line[:f]
            if fallback.search(line):
                print >>sys.stderr, "File %s line %s: didn't process:\n%s" % (file, oldLineNo, line)


# print >>sys.stderr, "Walking directory %s" % directory
toProcess = []

for (dir, dirs, files) in os.walk(directory):
    if 'mork' in dirs:
        dirs.remove('mork')
    if 'eVC4' in dirs:
        dirs.remove('eVC4')
    for file in files:
        if file.endswith('.h') or file.endswith('.cpp'):
            toProcess.append(os.path.join(dir, file))

for i in xrange(0, len(toProcess)):
    path = toProcess[i]
    # print >>sys.stderr, "Processing (%s/%s): %s... " % (i + 1, len(toProcess), path)
    run_single(path)