From c6448e413798921c63e1a36507c9c21be1fab2d9 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Thu, 26 Feb 2009 17:50:01 +0000 Subject: [PATCH] Beginning of new tool for transforming coordinates in WML. --- data/tools/wmlflip | 189 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100755 data/tools/wmlflip diff --git a/data/tools/wmlflip b/data/tools/wmlflip new file mode 100755 index 00000000000..d0fb30e23d3 --- /dev/null +++ b/data/tools/wmlflip @@ -0,0 +1,189 @@ +#!/usr/bin/env python +""" +wmlflip -- return the sizes of maps listed on the command line. + +Flip macro coordinate arguments on a map. Use this if you've mirror-reversed +a map and need to change coordinate-using macros. Takes a cross-reference +of all known macros and looks for formals that are either X, Y, *_X, or _Y, +so it's guaranteed to catch everything. +""" + +import sys, os, time, re, getopt, sre_constants, md5 +from wesnoth.wmltools import * + +class ParseArgs: + def __init__(self, fp, verbose=False): + self.fp = fp + self.verbose = verbose + self.parsed = [] + self.namestack = [] + self.pushback = None + self.lead = "" + self.parse_until(['']) + def getchar(self): + if self.pushback: + c = self.pushback + self.pushback = None + return c + else: + return self.fp.read(1) + def ungetchar(self, c): + if verbose: + print "pushing back", c + self.pushback = c + def parse_until(self, enders): + "Parse until we reach specified terminator." + if self.verbose: + self.lead += "*" + print self.lead + " parse_until(%s) starts" % enders + while True: + c = self.getchar() + if self.verbose: + print self.lead + "I see", c + if c in enders: + if self.verbose: + print self.lead + "parse_until(%s) ends" % enders + self.lead = self.lead[:-1] + return c + elif c == '{': + self.parse_call() + def parse_call(self): + "We see a start of call." + if self.verbose: + self.lead += "*" + print self.lead + "parse_call()" + self.namestack.append(["", []]) + # Fill in the name of the called macro + while True: + c = self.getchar() + if c.isalnum() or c == '_': + self.namestack[-1][0] += c + else: + break + if self.verbose: + print self.lead + "name", self.namestack[-1] + # Discard if no arguments + if c == '}': + self.namestack.pop() + if self.verbose: + print self.lead + "parse_call() ends" + self.lead = self.lead[:-1] + return + # If non-space, this is something like a filename include; + # skip until closing } + if not c.isspace(): + while True: + c = self.getchar() + if c == '}': + if self.verbose: + print self.lead + "parse_call() ends" + self.lead = self.lead[:-1] + return + # It's a macro call with arguments; + # parse them, recording the character offsets + while self.parse_actual(): + continue + # Discard trailing } + self.getchar() + # Record the scope we just parsed + self.parsed.append(self.namestack.pop()) + if self.verbose: + print self.lead + "parse_call() ends" + self.lead = self.lead[:-1] + def parse_actual(self): + "Parse an actual argument." + # Skip leading whitespace + if self.verbose: + self.lead += "*" + print self.lead + "parse_actual() begins" + while True: + c = self.getchar() + if not c.isspace(): + break + if c == '}': + if self.verbose: + print "** parse_actual() returns False" + self.lead = self.lead[:-1] + return False + # Looks like we have a real argument + argstart = self.fp.tell() - 1 + # Skip leading translation mark, if any + if c == "_": + c = self.getchar() + # Get the argument itself + if c == '{': + self.parse_call() + argend = self.fp.tell() + elif c == '(': + self.parse_until([")"]) + argend = self.fp.tell() + elif c == '"': + if verbose: + print self.lead + "starting string argument" + self.parse_until(['"']) + argend = self.fp.tell() + else: + ender = self.parse_until(['', ' ', '\t', '\r', '\n', '}']) + argend = self.fp.tell() - 1 + self.ungetchar(ender) + self.namestack[-1][1].append((argstart, argend)) + if self.verbose: + print self.lead + "parse_actual() returns True" + self.lead = self.lead[:-1] + return True + def dump(self): + print self.parsed + +if __name__ == '__main__': + here = os.getcwd() + + flip_x = flip_y = verbose = False + (options, arguments) = getopt.getopt(sys.argv[1:], "xyv") + + for (switch, val) in options: + if switch in ('-h', '--help'): + sys.stderr.write(__doc__) + sys.exit(0) + elif switch in ('-x'): + flip_x = True + elif switch in ('-y'): + flip_y = True + elif switch == '-v': + verbose = True + if verbose: + print "Debugging output enabled." + + if 0: + # Cross-reference all files. + pop_to_top("wmlflip") + cref = CrossRef(scopelist()) + os.chdir(here) + if verbose: + print "Cross-reference complete," + + # Look at all definitions. Extract those with in "_?X" or "_?Y". + # Generate a dictionary of names mapping to offsets of arguments + # to be transformed. + relevant = {} + for name in cref.xref: + for ref in cref.xref[name]: + have_x = have_y = None + for (i, arg) in enumerate(ref.args): + if arg == "X" or arg.endswith("_X"): + have_x = i + if arg == "Y" or arg.endswith("_Y"): + have_y = i + if have_x is not None and have_y is not None: + relevant[name] = (have_x, have_y) + + # For each file named on the command line... + for filename in arguments: + if verbose: + print "Processing file", filename + fp = open(filename, "r") + parsed = ParseArgs(fp, verbose) + parsed.dump() + # THIS IS NOT COMPLETE + fp.close() + +