233 lines
7.6 KiB
Python
Executable File
233 lines
7.6 KiB
Python
Executable File
import re
|
|
import os
|
|
import sys
|
|
import glob
|
|
import optparse
|
|
import stat
|
|
|
|
SyntaxHelp = """
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Usage:
|
|
// Old New
|
|
// Will convert any string "Old" to "New" provided that
|
|
// "Old" is _not_ preceeded or succeeded by an identifier character
|
|
// (A-Z, a-z, 0-9, _)
|
|
//
|
|
// In other words:
|
|
// Old becomes New
|
|
// Old() New()
|
|
// OldStuff OldStuff
|
|
// a+Old a+New
|
|
// OldOld OldOld
|
|
// Old Old New New
|
|
//
|
|
// C++ style comments like these will be ignored
|
|
//
|
|
// If you want to delete the Old string, use "***NULL***" as the New string:
|
|
// OBSOLETE_ENUM ***NULL***
|
|
// (replaces OBSOLETE_ENUM with an empty string)
|
|
//
|
|
// If you need spaces in the Old or New strings, use a
|
|
// "->" to seperate the old and new
|
|
// #include "core/stream.h" -> #include "file/stream.h"
|
|
//
|
|
// whitespace in the Old string will match any amount of whitespace in
|
|
// the file that's being modified. So "#include <system>" would match
|
|
// #include <system>
|
|
// #include <system>
|
|
// #include <system>
|
|
//
|
|
// Also, both "Old" and "New" can be python (and perl, and sed) style
|
|
// regular expressions if you begin the line with *REGEX*
|
|
//
|
|
// So if you want to match exactly one whitespace character you could use
|
|
// the whitespace matching token \s.
|
|
// *REGEX* #include\s<system> -> #include <system>
|
|
// will match
|
|
// #include <system>
|
|
// but not
|
|
// #include <system>
|
|
//
|
|
// Characters to watch out for: [ ] ( ) \ ? + * .
|
|
// These all have special meaning for regular expressions,
|
|
// you may need to backslash escape them to make them work.
|
|
// They will work normally on lines that don't begin with *REGEX*
|
|
"""
|
|
|
|
|
|
|
|
PerforceCommand = None
|
|
ForceWrite = False
|
|
Quiet = False
|
|
|
|
def CreateSubstitutionList(substFileName):
|
|
if (substFileName == "-"):
|
|
print "Enter substitutions below.\nType ^Z (Ctrl-Z) + return, or a '.' on its own line to stop"
|
|
substs = sys.stdin
|
|
else:
|
|
print "Reading substitutions from ", substFileName
|
|
substs = file(substFileName, "r")
|
|
|
|
exprs = []
|
|
lineNo = 0
|
|
numNormal = 0
|
|
numRegexp = 0
|
|
while substs:
|
|
line = substs.readline()
|
|
if not line:
|
|
break
|
|
lineNo = lineNo + 1
|
|
strippedLine = line.strip()
|
|
if len(strippedLine) == 0:
|
|
continue
|
|
if strippedLine[0] == "/" and strippedLine[1] == '/':
|
|
continue
|
|
if substs == sys.stdin and len(strippedLine) == 1 and strippedLine[0] == ".":
|
|
break
|
|
words = line.split()
|
|
before = ""
|
|
after = ""
|
|
if len(words) < 2:
|
|
print "Error: line %d, not enough tokens: %s" % (lineNo, line)
|
|
|
|
regex = 0
|
|
if words[0] == "*REGEX*":
|
|
regex = 1
|
|
words = words[1:]
|
|
line = line.replace("*REGEX*", "", 1)
|
|
strippedLine = strippedLine.replace("*REGEX*", "", 1)
|
|
strippedLine = strippedLine.strip()
|
|
|
|
if len(words) == 2:
|
|
before = words[0]
|
|
after = words[1]
|
|
else:
|
|
# check for special conversion token ->
|
|
if "->" in words:
|
|
wsWords = strippedLine.split("->")
|
|
if len(wsWords) != 2:
|
|
print "Error: line %d, too many tokens: %s" % (lineNo, line)
|
|
continue
|
|
else:
|
|
before = wsWords[0].strip()
|
|
after = wsWords[1].strip()
|
|
else:
|
|
print "Error: line %d, too many tokens: %s" % (lineNo, line)
|
|
continue
|
|
|
|
if after == "***NULL***":
|
|
after = ""
|
|
|
|
|
|
if regex:
|
|
expr = re.compile(before)
|
|
sub = after
|
|
numRegexp += 1
|
|
else:
|
|
before = re.escape(before)
|
|
before = re.sub("(\\\\\s)+", "\\s+", before) # turns all runs of spaces in the before string into \s+
|
|
after = re.sub("\\\\", "\\\\\\\\", after) # turns all \s in the after string into \\s
|
|
expr = re.compile('(?<!\w)%s(?!\w)' % before) # disallow matches in the middle of a word
|
|
sub = after
|
|
numNormal += 1
|
|
|
|
exprs.append((expr, sub))
|
|
if not Quiet:
|
|
print "Read %d expressions (%d normal, %d regexp)" % (len(exprs), numNormal, numRegexp)
|
|
return exprs
|
|
|
|
def BatchSubstituteFile(exprs, fileName):
|
|
global PerforceCommand, ForceWrite
|
|
if not Quiet:
|
|
print "Processing file ", fileName, "...",
|
|
|
|
inFile = file(fileName, "r")
|
|
|
|
inLines = inFile.readlines()
|
|
|
|
inFile.close()
|
|
|
|
outLines = []
|
|
|
|
totalSubs = 0
|
|
for line in inLines:
|
|
for (expr, sub) in exprs:
|
|
numSubs = 0
|
|
(line, numSubs) = expr.subn(sub, line)
|
|
totalSubs = totalSubs + numSubs
|
|
outLines.append(line)
|
|
|
|
p4string = PerforceCommand
|
|
|
|
if (totalSubs > 0):
|
|
if p4string:
|
|
os.system(p4string + " " + fileName)
|
|
if ForceWrite:
|
|
os.chmod(fileName, stat.S_IWRITE)
|
|
try:
|
|
outFile = file(fileName, "w")
|
|
for line in outLines:
|
|
outFile.write(line)
|
|
except:
|
|
print
|
|
sys.stderr.write("Error: Couldn't write to file " + fileName + "\n")
|
|
return
|
|
|
|
if Quiet:
|
|
if totalSubs > 0:
|
|
print "Processing file ", fileName, "...", totalSubs, "substitutions made."
|
|
else:
|
|
print totalSubs, "substitutions made."
|
|
|
|
def FindFiles(globs):
|
|
fileList = []
|
|
for i in globs:
|
|
fileList += (glob.glob(i))
|
|
return fileList
|
|
|
|
if __name__ == "__main__":
|
|
opt = optparse.OptionParser(usage="Usage: %prog [options] <substlist.txt> <fileglob>+")
|
|
opt.add_option("-r", "--recurse", dest="recurse", action="store_true", default=False, help="Apply substitutions to all subdirectories under the current directory")
|
|
opt.add_option("-p", "--perforce", dest="perforce", action="store_true", default=False, help="Check files out from perforce before modifying")
|
|
opt.add_option("-f", "--force", dest="force", action="store_true", default=False, help="Make files writable if they are read only")
|
|
opt.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, help="Only print when substitutions are made")
|
|
opt.add_option("--syntax", dest="print_syntax", action="store_true", default=False, help="Print a description of the substitution list syntax")
|
|
|
|
(options, outargs) = opt.parse_args(sys.argv[1:])
|
|
|
|
if options.print_syntax:
|
|
print SyntaxHelp
|
|
sys.exit(1)
|
|
|
|
if len(outargs) < 2:
|
|
opt.print_help()
|
|
print "If substlist.txt is '-', reads from stdin"
|
|
sys.exit(1)
|
|
|
|
scriptName = outargs[0]
|
|
globs = outargs[1:]
|
|
|
|
if options.perforce:
|
|
PerforceCommand = "p4 edit"
|
|
ForceWrite = options.force
|
|
Quiet = options.quiet
|
|
|
|
exprs = CreateSubstitutionList(scriptName)
|
|
|
|
if options.recurse:
|
|
origDir = os.getcwd()
|
|
for (dirName, unused1, unused2) in os.walk(os.getcwd()):
|
|
if not Quiet:
|
|
print "Checking directory", dirName
|
|
os.chdir(dirName)
|
|
for f in FindFiles(globs):
|
|
BatchSubstituteFile(exprs, f)
|
|
os.chdir(origDir)
|
|
else:
|
|
for f in FindFiles(globs):
|
|
BatchSubstituteFile(exprs, f)
|
|
|
|
|
|
|