X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Futil%2Fxmlpool%2Fgen_xmlpool.py;h=3a352312644218ff52b10b7a102655deb5e95739;hb=d415748955034b659c8b577adc727b1fd39948b8;hp=64e631f74c43e3cd3948846bf33a40ee0c23b877;hpb=f9415d760af0bfd00b579c96e5ac866db43e38fe;p=mesa.git diff --git a/src/util/xmlpool/gen_xmlpool.py b/src/util/xmlpool/gen_xmlpool.py index 64e631f74c4..3a352312644 100644 --- a/src/util/xmlpool/gen_xmlpool.py +++ b/src/util/xmlpool/gen_xmlpool.py @@ -1,4 +1,4 @@ - +# encoding=utf-8 # # Usage: # gen_xmlpool.py /path/to/t_option.h localedir lang lang lang ... @@ -7,77 +7,68 @@ # `{localedir}/{language}/LC_MESSAGES/options.mo`. # -from __future__ import print_function - -import sys +from __future__ import print_function, unicode_literals +import argparse import gettext +import io +import os import re - +import sys if sys.version_info < (3, 0): gettext_method = 'ugettext' else: gettext_method = 'gettext' -# Path to t_options.h -template_header_path = sys.argv[1] - -localedir = sys.argv[2] - -# List of supported languages -languages = sys.argv[3:] - # Escape special characters in C strings -def escapeCString (s): +def escapeCString(s): escapeSeqs = {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n', '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'} # " -> '' is a hack. Quotes (") aren't possible in XML attributes. # Better use Unicode characters for typographic quotes in option # descriptions and translations. + last_quote = '”' i = 0 r = '' - while i < len(s): - # Special case: escape double quote with \u201c or \u201d, depending + for c in s: + # Special case: escape double quote with “ or ”, depending # on whether it's an open or close quote. This is needed because plain # double quotes are not possible in XML attributes. - if s[i] == '"': - if i == len(s)-1 or s[i+1].isspace(): - # close quote - q = u'\u201c' + if c == '"': + if last_quote == '”': + q = '“' else: - # open quote - q = u'\u201d' + q = '”' + last_quote = q r = r + q - elif s[i] in escapeSeqs: - r = r + escapeSeqs[s[i]] + elif c in escapeSeqs: + r = r + escapeSeqs[c] else: - r = r + s[i] - i = i + 1 + r = r + c return r # Expand escape sequences in C strings (needed for gettext lookup) -def expandCString (s): +def expandCString(s): escapeSeqs = {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n', 'r' : '\r', 't' : '\t', 'v' : '\v', '"' : '"', '\\' : '\\'} - i = 0 escape = False hexa = False octa = False num = 0 digits = 0 r = u'' - while i < len(s): + for c in s: if not escape: - if s[i] == '\\': + if c == '\\': escape = True else: - r = r + s[i] + r = r + c elif hexa: - if (s[i] >= '0' and s[i] <= '9') or \ - (s[i] >= 'a' and s[i] <= 'f') or \ - (s[i] >= 'A' and s[i] <= 'F'): - num = num * 16 + int(s[i],16) + if (c >= '0' and c <= '9') or \ + (c >= 'a' and c <= 'f') or \ + (c >= 'A' and c <= 'F'): + num = num * 16 + int(c, 16) digits = digits + 1 else: digits = 2 @@ -86,8 +77,8 @@ def expandCString (s): escape = False r = r + chr(num) elif octa: - if s[i] >= '0' and s[i] <= '7': - num = num * 8 + int(s[i],8) + if c >= '0' and c <= '7': + num = num * 8 + int(c, 8) digits = digits + 1 else: digits = 3 @@ -96,24 +87,23 @@ def expandCString (s): escape = False r = r + chr(num) else: - if s[i] in escapeSeqs: - r = r + escapeSeqs[s[i]] + if c in escapeSeqs: + r = r + escapeSeqs[c] escape = False - elif s[i] >= '0' and s[i] <= '7': + elif c >= '0' and c <= '7': octa = True - num = int(s[i],8) + num = int(c, 8) if num <= 3: digits = 1 else: digits = 2 - elif s[i] == 'x' or s[i] == 'X': + elif c == 'x' or c == 'X': hexa = True num = 0 digits = 0 else: - r = r + s[i] + r = r + c escape = False - i = i + 1 return r # Expand matches. The first match is always a DESC or DESC_BEGIN match. @@ -121,7 +111,7 @@ def expandCString (s): # # DESC, DESC_BEGIN format: \1 \2= \3 \4=gettext(" \5= \6=") \7 # ENUM format: \1 \2=gettext(" \3= \4=") \5 -def expandMatches (matches, translations, end=None): +def expandMatches(matches, translations, outfile, end=None): assert len(matches) > 0 nTranslations = len(translations) i = 0 @@ -132,101 +122,95 @@ def expandMatches (matches, translations, end=None): # are extended with a backslash. suffix = '' if len(matches) == 1 and i < len(translations) and \ - not matches[0].expand (r'\7').endswith('\\'): + not matches[0].expand(r'\7').endswith('\\'): suffix = ' \\' - text = escapeCString (getattr(trans, gettext_method) (expandCString ( + text = escapeCString(getattr(trans, gettext_method)(expandCString( matches[0].expand (r'\5')))) - text = (matches[0].expand (r'\1' + lang + r'\3"' + text + r'"\7') + suffix) - - # In Python 2, stdout expects encoded byte strings, or else it will - # encode them with the ascii 'codec' - if sys.version_info.major == 2: - text = text.encode('utf-8') + text = (matches[0].expand(r'\1' + lang + r'\3"' + text + r'"\7') + suffix) - print(text) + outfile.write(text + '\n') # Expand any subsequent enum lines for match in matches[1:]: - text = escapeCString (getattr(trans, gettext_method) (expandCString ( - match.expand (r'\3')))) - text = match.expand (r'\1"' + text + r'"\5') - - # In Python 2, stdout expects encoded byte strings, or else it will - # encode them with the ascii 'codec' - if sys.version_info.major == 2: - text = text.encode('utf-8') + text = escapeCString(getattr(trans, gettext_method)(expandCString( + match.expand(r'\3')))) + text = match.expand(r'\1"' + text + r'"\5') - print(text) + outfile.write(text + '\n') # Expand description end if end: - print(end, end='') - -# Compile a list of translation classes to all supported languages. -# The first translation is always a NullTranslations. -translations = [("en", gettext.NullTranslations())] -for lang in languages: - try: - trans = gettext.translation ("options", localedir, [lang]) - except IOError: - sys.stderr.write ("Warning: language '%s' not found.\n" % lang) - continue - translations.append ((lang, trans)) + outfile.write(end) # Regular expressions: -reLibintl_h = re.compile (r'#\s*include\s*') -reDESC = re.compile (r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') -reDESC_BEGIN = re.compile (r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') -reENUM = re.compile (r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') -reDESC_END = re.compile (r'\s*DRI_CONF_DESC_END') - -# Print a header -print("/***********************************************************************\n" \ -" *** THIS FILE IS GENERATED AUTOMATICALLY. DON'T EDIT! ***\n" \ -" ***********************************************************************/") - -# Process the options template and generate options.h with all -# translations. -template = open (template_header_path, "rb") -descMatches = [] -for line in template: - line = line.decode('utf-8') - - if len(descMatches) > 0: - matchENUM = reENUM .match (line) - matchDESC_END = reDESC_END.match (line) - if matchENUM: - descMatches.append (matchENUM) - elif matchDESC_END: - expandMatches (descMatches, translations, line) +reLibintl_h = re.compile(r'#\s*include\s*') +reDESC = re.compile(r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reDESC_BEGIN = re.compile(r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reENUM = re.compile(r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reDESC_END = re.compile(r'\s*DRI_CONF_DESC_END') + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--template', required=True) + parser.add_argument('--output', required=True) + parser.add_argument('--localedir', required=True) + parser.add_argument('--languages', nargs='*', default=[]) + args = parser.parse_args() + + # Compile a list of translation classes to all supported languages. + # The first translation is always a NullTranslations. + translations = [("en", gettext.NullTranslations())] + for lang in args.languages: + try: + filename = os.path.join(args.localedir, '{}.gmo'.format(lang)) + with io.open(filename, 'rb') as f: + trans = gettext.GNUTranslations(f) + except (IOError, OSError): + print("Warning: language '%s' not found." % lang, file=sys.stderr) + continue + translations.append((lang, trans)) + + with io.open(args.output, mode='wt', encoding='utf-8') as output: + output.write("/* This is file is generated automatically. Don't edit! */\n") + + # Process the options template and generate options.h with all + # translations. + with io.open(args.template, mode="rt", encoding='utf-8') as template: descMatches = [] - else: - sys.stderr.write ( - "Warning: unexpected line inside description dropped:\n%s\n" \ - % line) - continue - if reLibintl_h.search (line): - # Ignore (comment out) #include - print("/* %s * commented out by gen_xmlpool.py */" % line) - continue - matchDESC = reDESC .match (line) - matchDESC_BEGIN = reDESC_BEGIN.match (line) - if matchDESC: - assert len(descMatches) == 0 - expandMatches ([matchDESC], translations) - elif matchDESC_BEGIN: - assert len(descMatches) == 0 - descMatches = [matchDESC_BEGIN] - else: - # In Python 2, stdout expects encoded byte strings, or else it will - # encode them with the ascii 'codec' - if sys.version_info.major == 2: - line = line.encode('utf-8') - - print(line, end='') - -template.close() - -if len(descMatches) > 0: - sys.stderr.write ("Warning: unterminated description at end of file.\n") - expandMatches (descMatches, translations) + for line in template: + if descMatches: + matchENUM = reENUM.match(line) + matchDESC_END = reDESC_END.match(line) + if matchENUM: + descMatches.append(matchENUM) + elif matchDESC_END: + expandMatches(descMatches, translations, output, line) + descMatches = [] + else: + print("Warning: unexpected line inside description dropped:\n", + line, file=sys.stderr) + continue + if reLibintl_h.search(line): + # Ignore (comment out) #include + output.write("/* %s * commented out by gen_xmlpool.py */\n" % line) + continue + matchDESC = reDESC.match(line) + matchDESC_BEGIN = reDESC_BEGIN.match(line) + if matchDESC: + assert not descMatches + expandMatches([matchDESC], translations, output) + elif matchDESC_BEGIN: + assert not descMatches + descMatches = [matchDESC_BEGIN] + else: + + output.write(line) + + if descMatches: + print("Warning: unterminated description at end of file.", file=sys.stderr) + expandMatches(descMatches, translations, output) + + +if __name__ == '__main__': + main()