Remove broken Python port of wmlxgettext

This commit is contained in:
Ignacio R. Morelle 2015-06-21 22:43:45 -03:00
parent 53e8f54e02
commit 8b59af444d
2 changed files with 2 additions and 256 deletions

View file

@ -73,7 +73,8 @@ Version 1.13.0+dev:
lobby with music and sound enabled (bug #23633, bug #23599) with libvorbis
builds affected by Debian bug #782831.
* Moved [role] tag to Lua (fix for bug #23630)
* Removed broken Python port of wmlxgettext from data/tools/.
Version 1.13.0:
* Security fixes:
* Fixed arbitrary file read from WML/Lua API (CVE-2015-0844, bug #23440).

View file

@ -1,255 +0,0 @@
#!/usr/bin/env python
#
# wmlxgettext - extract .po files from Wesnoth WML
#
# WARNING! This file is basically a "proof of concept" and was meant as
# replacement for the perl script "utils/wmlxgettext". This script you
# are looking at is not used for the extraction of strings in Wesnoth mainline.
# During tests it has shown to be significantly slower than the existing
# solution so (at least for the moment) that older implementation will be used.
# This also means that this script can (partly) be broken and/or not lead to
# the results you might expect.
import sys, os, time, re, getopt
from wesnoth.wmltools import *
from wesnoth.wmliterator import *
# Disable the script so people don't accidentally use it and wonder why it doesn't do what they expect
sys.stderr.write("""You probably want to use 'utils/wmlxgettext' instead
This script was intended as a replacement but is not currently used
It does not generate the same results as the perl version anymore\n""")
# In case we're called by some big script that either swallows or swamps stderr
print "This is not the wmlxgettext script you're looking for"
sys.exit(1)
# Code swiped from wmllint: probably should live in the wesnoth module
vctypes = (".svn", ".git")
def cfgfile(fn):
"Is a file interesting for translation purposes?"
return fn.endswith(".cfg")
def allcfgfiles(dir):
"Get the names of all cfgfile files under dir."
datafiles = []
if not os.path.isdir(dir):
if cfgfile(dir):
if not os.path.exists(dir):
sys.stderr.write("wmllint: %s does not exist\n" % dir)
else:
datafiles.append(dir)
else:
for root, dirs, files in os.walk(dir):
for vcsubdir in vctypes:
if vcsubdir in dirs:
dirs.remove(vcsubdir)
for name in files:
if cfgfile(os.path.join(root, name)):
datafiles.append(os.path.join(root, name))
return map(os.path.normpath, datafiles)
class WmllintIterator(WmlIterator):
"Fold an Emacs-compatible error reporter into WmlIterator."
def printError(self, *misc):
"""Emit an error locator compatible with Emacs compilation mode."""
if not hasattr(self, 'lineno') or self.lineno == -1:
print >>sys.stderr, '"%s":' % self.fname
else:
print >>sys.stderr, '"%s", line %d:' % (self.fname, self.lineno+1),
for item in misc:
print >>sys.stderr, item,
print >>sys.stderr #terminate line
# Swiped code ends here
def interesting(text):
"Is the given text line interesting to render as part of a context?"
# Ignore translatables, those are guaranteed to be nearby
if re.search('_ *"', text):
return False
return True
if __name__ == "__main__":
def help():
sys.stderr.write("""\
Usage: wmlxgettext [options] dirpath
Options may be any of these:
-h, --help Emit this help message and quit
-d dir, --directory=dir operate on specified directory
-s dn, --domain=dn Generate only for specified domain
-v val. --verbose=val Set warning level
Options may be followed by any number of directiories to check. If no
directories are given, all files under the current directory are checked.
""")
directory = os.getcwd()
# Deduce package and version
pop_to_top("wmlxgettext")
m = re.search(r"#define VERSION\s+(.*)", open("src/wesconfig.h").read())
if not m:
print >>sys.stderr, "wmlgettext: can't get Wesnoth version."
sys.exit(1)
else:
version = string_strip(m.group(1))
os.chdir(directory)
print '''\
msgid ""
msgstr ""
"Project-Id-Version: wesnoth %s\\n"
"Report-Msgid-Bugs-To: http://bugs.wesnoth.org/\\n"
"POT-Creation-Date: %s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL\@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL\@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
''' % (version, time.strftime("%Y-%m-%d, %H:%M+0000", time.gmtime()))
try:
domain = None
verbose = 0
# Process options
(options, arguments) = getopt.getopt(sys.argv[1:], "d:h:s:v:",
[
'directory=',
'help',
'domain=',
'verbose=',
])
for (switch, val) in options:
if switch in ('-d', '--directory'):
directory = val
elif switch in ('-h', '--help'):
help()
sys.exit(0)
elif switch in ('-s', '--domain'):
domain = val
elif switch in ('-v', '--verbose'):
verbose = int(val)
if not arguments:
arguments = '.'
os.chdir(directory)
opener_stack = []
attributes_stack = []
translatables = []
contexts = {}
find_translatable = re.compile('_ *"([^"]*)"')
def get_translatables(nav, fn):
"Mine translatable strings "
itor = find_translatable.finditer(nav.text)
for match in itor:
opener_stack.append((nav.element, fn, nav.lineno))
translatables.append((match.group(1), opener_stack[:]))
opener_stack.pop()
def inMacroContinuation(nav):
return opener_stack and type(opener_stack[-1][0]) == type("") \
and opener_stack[-1][0].startswith("{")
def isInlineMacro(nav):
return type(nav.element) == type([]) and nav.element and nav.element[0].startswith("{")
def handle_element(nav, fn):
if isAttribute(nav):
if verbose > 1:
print "Attribute", nav, "with ancestors", nav.ancestors()
attributes_stack[-1].append(nav.text.strip())
get_translatables(nav, fn)
elif isCloser(nav):
if verbose > 1:
print "Closing scope", nav
contexts[opener_stack.pop()] = attributes_stack.pop()
elif isOpener(nav):
if verbose > 1:
print "Opening scope", nav
attributes_stack.append([])
opener_stack.append((nav.element, fn, nav.lineno))
elif isMacroOpener(nav):
if verbose > 1:
print "Opening macro scope", nav
opener_stack.append((nav.element, fn, nav.lineno))
get_translatables(nav, fn)
elif isMacroCloser(nav):
if verbose > 1:
print "Closing macro scope", nav
opener_stack.pop()
elif inMacroContinuation(nav):
if verbose > 1:
print "In macro continuation", repr(nav.text)
nav.element = "argument"
get_translatables(nav, fn)
elif isInlineMacro(nav):
if verbose > 1:
print "Inline macro", nav
nav.element = nav.element[0]
get_translatables(nav, fn)
elif nav.element == "#po":
if verbose > 1:
print "Passthrough for", nav
opener_stack.append((nav.element, fn, nav.lineno))
translatables.append((nav.text.lstrip(), opener_stack[:]))
opener_stack.pop()
elif verbose > 1:
print "Unhandled", nav
# Gather a list describing the context of every
# translatable string.
for dir in arguments:
seqno = 0
for fn in allcfgfiles(dir):
if verbose >= 2:
print fn + ":"
lines = file(fn).readlines()
if domain is not None:
if lines[0].startswith("#textdomain"):
belongs_to = lines[0].split()[1]
if belongs_to != domain:
if verbose:
print "wmlxgettext: skipping %s, wrong domain" % fn
continue
opener_stack.append(("<toplevel>", fn, 0))
attributes_stack.append([])
for nav in WmllintIterator(lines, fn):
handle_element(nav, fn)
opener_stack.pop()
# Debugging output
if verbose:
print "Translatables:"
for (translatable, context) in translatables:
print "%s: %s" % (translatable, context)
print "Contexts:"
for (key, value) in contexts.items():
print key, "->", value
# Generate a report from the translatables
notes = ""
for (translatable, context) in translatables:
if translatable.startswith("#po"):
notes += translatable.replace("po:", "")
continue
attribs = ""
for (i, (tag, file, line)) in enumerate(context):
if i == len(context)-1 or tag.startswith("{"):
print "# %s, line %d: %s" % (file, line, tag)
else:
for (key, value) in contexts.items():
value = filter(interesting, value)
if key[0] == tag and key[1] == file and key[2] == line:
attribs = " has " + ", ".join(value)
print "# %s, line %d: %s%s" % (file, line, tag, attribs)
if notes:
print notes,
notes = ""
print 'msgid "%s"' % translatable
print 'msgstr ""'
print ""
except KeyboardInterrupt:
print >>sys.stderr, "wmlxgettext: aborted."