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