Files
asmjit/tools/autoexp-patch.py
kobalicekp 5c7123fbb3 Initial.
2014-02-02 03:17:30 +01:00

425 lines
9.7 KiB
Python

#!/usr/bin/env python
import os
AUTOEXP_FILES = [
# Visual Studio 8.0 (2005).
"C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
# Visual Studio 9.0 (2008).
"C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
# Visual Studio 10.0 (2010).
"C:\\Program Files\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat"
]
DIRECTIVE_SYMBOL = '@'
# =============================================================================
# [Log]
# =============================================================================
def log(str):
print(str)
# =============================================================================
# [Is...]
# =============================================================================
def isDirective(c):
return c == DIRECTIVE_SYMBOL
def isAlpha(c):
c = ord(c)
return (c >= ord('a') and c <= ord('z')) or (c >= ord('A') and c <= ord('Z'))
def isAlpha_(c):
return isAlpha(c) or (c == '_')
def isNumber(c):
c = ord(c)
return (c >= ord('0')) and (c <= ord('9'))
def isAlnum(c):
return isAlpha(c) or isNumber(c)
def isAlnum_(c):
return isAlnum(c) or (c == '_')
def isSpace(c):
return (c == ' ') or (c == '\t')
def isNewLine(c):
return c == '\n'
# =============================================================================
# [SyntaxError]
# =============================================================================
class SyntaxError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
# =============================================================================
# [Context]
# =============================================================================
class Context(object):
def __init__(self, data):
self.data = data
self.index = 0
self.size = len(data)
def isNewLine(self):
if self.index == 0:
return True
else:
return self.data[self.index - 1] == '\n'
def isEnd(self):
return self.index >= self.size
def getChar(self):
if self.index >= self.size:
return '\0'
return self.data[self.index]
def advance(self):
if self.index < self.size:
self.index += 1
def parseUntilTrue(self, func, advance):
while not self.isEnd():
c = self.data[self.index]
if func(c):
self.index += 1
continue
if advance:
self.index += 1
return True
return False
def parseUntilFalse(self, func, advance):
while not self.isEnd():
c = self.data[self.index]
if not func(c):
self.index += 1
continue
if advance:
self.index += 1
return True
return False
def skipString(self):
def func(c):
return c == '"'
return self.parseUntilFalse(func, True)
def skipSpaces(self):
return self.parseUntilTrue(isSpace, False)
def skipLine(self):
return self.parseUntilFalse(isNewLine, True)
def parseDirective(self, index):
start = index
data = self.data
size = self.size
c = data[index]
assert isAlpha_(c)
while True:
index += 1
if index >= size:
break
c = data[index]
if isAlnum_(c):
continue
break
self.index = index
return data[start:index]
def parseSymbol(self, index):
start = index
data = self.data
size = self.size
c = data[index]
assert isAlpha_(c)
while True:
index += 1
if index >= size:
return data[start:index]
c = data[index]
if isAlnum_(c):
continue
if c == ':' and index + 2 < size and data[index + 1] == ':' and isAlpha_(data[index + 2]):
index += 2
continue
self.index = index
return data[start:index]
def parseMacro(self, index):
start = index
end = None
data = self.data
size = self.size
if index >= size:
return ""
while True:
c = data[index]
index += 1
if c == '\n' or index >= size:
if end == None:
end = index - 1
break
if c == ';':
if end == None:
end = index
while start < end and isSpace(data[end - 1]):
end -= 1
self.index = index
return data[start:end]
def replaceRange(self, start, end, content):
old = self.data
self.data = old[0:start] + content + old[end:]
self.size = len(self.data)
assert(self.index >= end)
self.index -= end - start
self.index += len(content)
# =============================================================================
# [AutoExpDat]
# =============================================================================
class AutoExpDat(object):
def __init__(self, data):
self.library = None
self.symbols = {}
self.data = self.process(data.replace('\r', ''))
def process(self, data):
ctx = Context(data)
while not ctx.isEnd():
c = ctx.getChar()
# Skip comments.
if c == ';':
ctx.skipLine()
continue
# Skip strings.
if c == '"':
ctx.advance()
ctx.skipString()
continue
# Skip numbers.
if isNumber(c):
ctx.parseUntilTrue(isAlnum_, True)
continue
# Parse directives.
if isDirective(c) and ctx.isNewLine():
start = ctx.index
ctx.advance()
c = ctx.getChar()
# Remove lines that have '@' followed by space or newline.
if isNewLine(c) or c == '\0':
ctx.advance()
ctx.replaceRange(start, ctx.index, "")
continue
if isSpace(c):
ctx.skipLine()
ctx.replaceRange(start, ctx.index, "")
continue
directive = ctx.parseDirective(ctx.index)
c = ctx.getChar()
if not isSpace(c):
self.error("Directive Error: @" + directive + ".")
ctx.skipSpaces()
# Directive '@library'.
if directive == "library":
self.library = ctx.parseMacro(ctx.index)
# Directive '@define'.
elif directive == "define":
c = ctx.getChar()
if not isAlpha_(c):
self.error("Define Directive has to start with alpha character or underscore")
symbol = ctx.parseSymbol(ctx.index)
c = ctx.getChar()
# No Macro.
if isNewLine(c):
ctx.advance()
self.addSymbol(symbol, "")
# Has Macro.
else:
ctx.skipSpaces()
macro = ctx.parseMacro(ctx.index)
self.addSymbol(symbol, macro)
# Unknown Directive.
else:
self.error("Unknown Directive: @" + directive + ".")
ctx.replaceRange(start, ctx.index, "")
continue
# Parse/Replace symbol.
if isAlpha_(c) and ctx.index > 0 and ctx.data[ctx.index - 1] != '#':
start = ctx.index
symbol = ctx.parseSymbol(start)
if symbol in self.symbols:
ctx.replaceRange(start, start + len(symbol), self.symbols[symbol])
continue
ctx.advance()
return ctx.data
def addSymbol(self, symbol, macro):
if symbol in self.symbols:
self.error("Symbol '" + symbol + "' redefinition.")
else:
# Recurse.
macro = self.process(macro)
log("-- @define " + symbol + " " + macro)
self.symbols[symbol] = macro
def error(self, msg):
raise SyntaxError(msg)
# =============================================================================
# [LoadFile / SaveFile]
# =============================================================================
def loadFile(file):
h = None
data = None
try:
h = open(file, "rb")
data = h.read()
except:
pass
finally:
if h:
h.close()
return data
def saveFile(file, data):
h = None
result = False
try:
h = open(file, "wb")
h.truncate()
h.write(data)
result = True
except:
pass
finally:
if h:
h.close()
return result
# =============================================================================
# [PatchFile]
# =============================================================================
def patchFile(file, mark, data):
input = loadFile(file)
if not input:
return
beginMark = ";${" + mark + ":Begin}"
endMark = ";${" + mark + ":End}"
if beginMark in input:
# Replace.
if not endMark in input:
log("-- Corrupted File:\n" + " " + file)
return
beginMarkIndex = input.find(beginMark)
endMarkIndex = input.find(endMark)
beginMarkIndex = input.find('\n', beginMarkIndex) + 1
endMarkIndex = input.rfind('\n', 0, endMarkIndex) + 1
if beginMarkIndex == -1 or \
endMarkIndex == -1 or \
beginMarkIndex > endMarkIndex:
log("-- Corrupted File:\n" + " " + file)
return
output = input[:beginMarkIndex] + data + input[endMarkIndex:]
else:
# Add.
output = input
output += "\n"
output += beginMark + "\n"
output += data
output += endMark + "\n"
if input == output:
log("-- Unaffected:\n" + " " + file)
else:
log("-- Patching:\n" + " " + file)
if not saveFile(file, output):
log("!! Can't write:\n" + " " + file)
def main():
src = loadFile("autoexp.dat")
if src == None:
log("!! Can't read autoexp.dat")
return
src = AutoExpDat(src)
if not src.library:
log("!! Library not defined, use @library directive.")
return
for file in AUTOEXP_FILES:
patchFile(file, src.library, src.data)
main()