xmlconfig: remove GL type dependencies
[mesa.git] / src / mesa / drivers / dri / common / xmlpool / gen_xmlpool.py
1
2 #
3 # Usage:
4 # gen_xmlpool.py /path/to/t_option.h localedir lang lang lang ...
5 #
6 # For each given language, this script expects to find a .mo file at
7 # `{localedir}/{language}/LC_MESSAGES/options.mo`.
8 #
9
10 import sys
11 import gettext
12 import re
13
14 # Path to t_options.h
15 template_header_path = sys.argv[1]
16
17 localedir = sys.argv[2]
18
19 # List of supported languages
20 languages = sys.argv[3:]
21
22 # Escape special characters in C strings
23 def escapeCString (s):
24 escapeSeqs = {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n',
25 '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'}
26 # " -> '' is a hack. Quotes (") aren't possible in XML attributes.
27 # Better use Unicode characters for typographic quotes in option
28 # descriptions and translations.
29 i = 0
30 r = ''
31 while i < len(s):
32 # Special case: escape double quote with \u201c or \u201d, depending
33 # on whether it's an open or close quote. This is needed because plain
34 # double quotes are not possible in XML attributes.
35 if s[i] == '"':
36 if i == len(s)-1 or s[i+1].isspace():
37 # close quote
38 q = u'\u201c'
39 else:
40 # open quote
41 q = u'\u201d'
42 r = r + q
43 elif escapeSeqs.has_key(s[i]):
44 r = r + escapeSeqs[s[i]]
45 else:
46 r = r + s[i]
47 i = i + 1
48 return r
49
50 # Expand escape sequences in C strings (needed for gettext lookup)
51 def expandCString (s):
52 escapeSeqs = {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n',
53 'r' : '\r', 't' : '\t', 'v' : '\v',
54 '"' : '"', '\\' : '\\'}
55 i = 0
56 escape = False
57 hexa = False
58 octa = False
59 num = 0
60 digits = 0
61 r = ''
62 while i < len(s):
63 if not escape:
64 if s[i] == '\\':
65 escape = True
66 else:
67 r = r + s[i]
68 elif hexa:
69 if (s[i] >= '0' and s[i] <= '9') or \
70 (s[i] >= 'a' and s[i] <= 'f') or \
71 (s[i] >= 'A' and s[i] <= 'F'):
72 num = num * 16 + int(s[i],16)
73 digits = digits + 1
74 else:
75 digits = 2
76 if digits >= 2:
77 hexa = False
78 escape = False
79 r = r + chr(num)
80 elif octa:
81 if s[i] >= '0' and s[i] <= '7':
82 num = num * 8 + int(s[i],8)
83 digits = digits + 1
84 else:
85 digits = 3
86 if digits >= 3:
87 octa = False
88 escape = False
89 r = r + chr(num)
90 else:
91 if escapeSeqs.has_key(s[i]):
92 r = r + escapeSeqs[s[i]]
93 escape = False
94 elif s[i] >= '0' and s[i] <= '7':
95 octa = True
96 num = int(s[i],8)
97 if num <= 3:
98 digits = 1
99 else:
100 digits = 2
101 elif s[i] == 'x' or s[i] == 'X':
102 hexa = True
103 num = 0
104 digits = 0
105 else:
106 r = r + s[i]
107 escape = False
108 i = i + 1
109 return r
110
111 # Expand matches. The first match is always a DESC or DESC_BEGIN match.
112 # Subsequent matches are ENUM matches.
113 #
114 # DESC, DESC_BEGIN format: \1 \2=<lang> \3 \4=gettext(" \5=<text> \6=") \7
115 # ENUM format: \1 \2=gettext(" \3=<text> \4=") \5
116 def expandMatches (matches, translations, end=None):
117 assert len(matches) > 0
118 nTranslations = len(translations)
119 i = 0
120 # Expand the description+enums for all translations
121 for lang,trans in translations:
122 i = i + 1
123 # Make sure that all but the last line of a simple description
124 # are extended with a backslash.
125 suffix = ''
126 if len(matches) == 1 and i < len(translations) and \
127 not matches[0].expand (r'\7').endswith('\\'):
128 suffix = ' \\'
129 # Expand the description line. Need to use ugettext in order to allow
130 # non-ascii unicode chars in the original English descriptions.
131 text = escapeCString (trans.ugettext (unicode (expandCString (
132 matches[0].expand (r'\5')), "utf-8"))).encode("utf-8")
133 print matches[0].expand (r'\1' + lang + r'\3"' + text + r'"\7') + suffix
134 # Expand any subsequent enum lines
135 for match in matches[1:]:
136 text = escapeCString (trans.ugettext (unicode (expandCString (
137 match.expand (r'\3')), "utf-8"))).encode("utf-8")
138 print match.expand (r'\1"' + text + r'"\5')
139
140 # Expand description end
141 if end:
142 print end,
143
144 # Compile a list of translation classes to all supported languages.
145 # The first translation is always a NullTranslations.
146 translations = [("en", gettext.NullTranslations())]
147 for lang in languages:
148 try:
149 trans = gettext.translation ("options", localedir, [lang])
150 except IOError:
151 sys.stderr.write ("Warning: language '%s' not found.\n" % lang)
152 continue
153 translations.append ((lang, trans))
154
155 # Regular expressions:
156 reLibintl_h = re.compile (r'#\s*include\s*<libintl.h>')
157 reDESC = re.compile (r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
158 reDESC_BEGIN = re.compile (r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
159 reENUM = re.compile (r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
160 reDESC_END = re.compile (r'\s*DRI_CONF_DESC_END')
161
162 # Print a header
163 print \
164 "/***********************************************************************\n" \
165 " *** THIS FILE IS GENERATED AUTOMATICALLY. DON'T EDIT! ***\n" \
166 " ***********************************************************************/"
167
168 # Process the options template and generate options.h with all
169 # translations.
170 template = file (template_header_path, "r")
171 descMatches = []
172 for line in template:
173 if len(descMatches) > 0:
174 matchENUM = reENUM .match (line)
175 matchDESC_END = reDESC_END.match (line)
176 if matchENUM:
177 descMatches.append (matchENUM)
178 elif matchDESC_END:
179 expandMatches (descMatches, translations, line)
180 descMatches = []
181 else:
182 sys.stderr.write (
183 "Warning: unexpected line inside description dropped:\n%s\n" \
184 % line)
185 continue
186 if reLibintl_h.search (line):
187 # Ignore (comment out) #include <libintl.h>
188 print "/* %s * commented out by gen_xmlpool.py */" % line
189 continue
190 matchDESC = reDESC .match (line)
191 matchDESC_BEGIN = reDESC_BEGIN.match (line)
192 if matchDESC:
193 assert len(descMatches) == 0
194 expandMatches ([matchDESC], translations)
195 elif matchDESC_BEGIN:
196 assert len(descMatches) == 0
197 descMatches = [matchDESC_BEGIN]
198 else:
199 print line,
200
201 if len(descMatches) > 0:
202 sys.stderr.write ("Warning: unterminated description at end of file.\n")
203 expandMatches (descMatches, translations)