155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling#!/usr/bin/python 255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingimport sys 455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingimport gettext 555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingimport re 655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# List of supported languages 855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlinglanguages = sys.argv[1:] 955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 1055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Escape special characters in C strings 1155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingdef escapeCString (s): 1255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escapeSeqs = {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n', 13ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'} 1455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # " -> '' is a hack. Quotes (") aren't possible in XML attributes. 1555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Better use Unicode characters for typographic quotes in option 1655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # descriptions and translations. 1755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = 0 1855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = '' 1955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling while i < len(s): 20ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling # Special case: escape double quote with \u201c or \u201d, depending 21ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling # on whether it's an open or close quote. This is needed because plain 22ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling # double quotes are not possible in XML attributes. 23ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling if s[i] == '"': 24ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling if i == len(s)-1 or s[i+1].isspace(): 25ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling # close quote 26ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling q = u'\u201c' 27ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling else: 28ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling # open quote 29ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling q = u'\u201d' 30ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling r = r + q 31ad0dbe6b04f5d6d580a0a5dfe2018027f986acbdFelix Kuehling elif escapeSeqs.has_key(s[i]): 3255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + escapeSeqs[s[i]] 3355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 3455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + s[i] 3555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = i + 1 3655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling return r 3755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 3855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Expand escape sequences in C strings (needed for gettext lookup) 3955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingdef expandCString (s): 4055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escapeSeqs = {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n', 4155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 'r' : '\r', 't' : '\t', 'v' : '\v', 4255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling '"' : '"', '\\' : '\\'} 4355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = 0 4455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = False 4555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling hexa = False 4655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling octa = False 4755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling num = 0 4855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 0 4955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = '' 5055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling while i < len(s): 5155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if not escape: 5255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if s[i] == '\\': 5355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = True 5455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 5555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + s[i] 5655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif hexa: 5755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if (s[i] >= '0' and s[i] <= '9') or \ 5855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling (s[i] >= 'a' and s[i] <= 'f') or \ 5955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling (s[i] >= 'A' and s[i] <= 'F'): 6055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling num = num * 16 + int(s[i],16) 6155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = digits + 1 6255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 6355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 2 6455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if digits >= 2: 6555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling hexa = False 6655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = False 6755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + chr(num) 6855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif octa: 6955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if s[i] >= '0' and s[i] <= '7': 7055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling num = num * 8 + int(s[i],8) 7155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = digits + 1 7255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 7355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 3 7455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if digits >= 3: 7555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling octa = False 7655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = False 7755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + chr(num) 7855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 7955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if escapeSeqs.has_key(s[i]): 8055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + escapeSeqs[s[i]] 8155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = False 8255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif s[i] >= '0' and s[i] <= '7': 8355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling octa = True 8455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling num = int(s[i],8) 8555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if num <= 3: 8655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 1 8755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 8855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 2 8955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif s[i] == 'x' or s[i] == 'X': 9055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling hexa = True 9155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling num = 0 9255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling digits = 0 9355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 9455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling r = r + s[i] 9555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling escape = False 9655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = i + 1 9755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling return r 9855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 9955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Expand matches. The first match is always a DESC or DESC_BEGIN match. 10055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Subsequent matches are ENUM matches. 10155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# 10255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# DESC, DESC_BEGIN format: \1 \2=<lang> \3 \4=gettext(" \5=<text> \6=") \7 10355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# ENUM format: \1 \2=gettext(" \3=<text> \4=") \5 10455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingdef expandMatches (matches, translations, end=None): 10555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling assert len(matches) > 0 10655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling nTranslations = len(translations) 10755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = 0 10855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Expand the description+enums for all translations 10955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling for lang,trans in translations: 11055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling i = i + 1 11155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Make sure that all but the last line of a simple description 11255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # are extended with a backslash. 11355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling suffix = '' 11455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if len(matches) == 1 and i < len(translations) and \ 11555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling not matches[0].expand (r'\7').endswith('\\'): 11655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling suffix = ' \\' 11755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Expand the description line. Need to use ugettext in order to allow 11855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # non-ascii unicode chars in the original English descriptions. 11955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling text = escapeCString (trans.ugettext (unicode (expandCString ( 12055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling matches[0].expand (r'\5')), "utf-8"))).encode("utf-8") 12155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling print matches[0].expand (r'\1' + lang + r'\3"' + text + r'"\7') + suffix 12255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Expand any subsequent enum lines 12355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling for match in matches[1:]: 12455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling text = escapeCString (trans.ugettext (unicode (expandCString ( 12555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling match.expand (r'\3')), "utf-8"))).encode("utf-8") 12655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling print match.expand (r'\1"' + text + r'"\5') 12755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 12855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Expand description end 12955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if end: 13055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling print end, 13155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 13255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Compile a list of translation classes to all supported languages. 13355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# The first translation is always a NullTranslations. 13455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingtranslations = [("en", gettext.NullTranslations())] 13555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingfor lang in languages: 13655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling try: 13755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling trans = gettext.translation ("options", ".", [lang]) 13855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling except IOError: 13955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling sys.stderr.write ("Warning: language '%s' not found.\n" % lang) 14055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling continue 14155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling translations.append ((lang, trans)) 14255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 14355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Regular expressions: 14455ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingreLibintl_h = re.compile (r'#\s*include\s*<libintl.h>') 14555ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingreDESC = re.compile (r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') 14655ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingreDESC_BEGIN = re.compile (r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') 14755ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingreENUM = re.compile (r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') 14855ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingreDESC_END = re.compile (r'\s*DRI_CONF_DESC_END') 14955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 15055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Print a header 15155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingprint \ 15255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling"/***********************************************************************\n" \ 15355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling" *** THIS FILE IS GENERATED AUTOMATICALLY. DON'T EDIT! ***\n" \ 15455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling" ***********************************************************************/" 15555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 15655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# Process the options template and generate options.h with all 15755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling# translations. 15855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingtemplate = file ("t_options.h", "r") 15955ba0dccc92797a0411ce315328100e28f6343b7Felix KuehlingdescMatches = [] 16055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingfor line in template: 16155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if len(descMatches) > 0: 16255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling matchENUM = reENUM .match (line) 16355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling matchDESC_END = reDESC_END.match (line) 16455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if matchENUM: 16555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling descMatches.append (matchENUM) 16655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif matchDESC_END: 16755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling expandMatches (descMatches, translations, line) 16855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling descMatches = [] 16955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 17055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling sys.stderr.write ( 17155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling "Warning: unexpected line inside description dropped:\n%s\n" \ 17255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling % line) 17355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling continue 17455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if reLibintl_h.search (line): 17555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling # Ignore (comment out) #include <libintl.h> 17655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling print "/* %s * commented out by gen_xmlpool.py */" % line 17755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling continue 17855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling matchDESC = reDESC .match (line) 17955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling matchDESC_BEGIN = reDESC_BEGIN.match (line) 18055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling if matchDESC: 18155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling assert len(descMatches) == 0 18255ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling expandMatches ([matchDESC], translations) 18355ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling elif matchDESC_BEGIN: 18455ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling assert len(descMatches) == 0 18555ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling descMatches = [matchDESC_BEGIN] 18655ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling else: 18755ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling print line, 18855ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling 18955ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehlingif len(descMatches) > 0: 19055ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling sys.stderr.write ("Warning: unterminated description at end of file.\n") 19155ba0dccc92797a0411ce315328100e28f6343b7Felix Kuehling expandMatches (descMatches, translations) 192