3 # Copyright (C) 2009 Chia-I Wu <olv@0xlab.org>
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # on the rights to use, copy, modify, merge, publish, distribute, sub
9 # license, and/or sell copies of the Software, and to permit persons to whom
10 # the Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 GLAPI
= "../../glapi/gen"
29 sys
.path
.append(GLAPI
)
35 def __init__(self
, api
, elts
=["enum", "type", "function"]):
39 def _check_enum(self
, e1
, e2
, strict
=True):
40 if e1
.name
!= e2
.name
:
41 raise ValueError("%s: name mismatch" % e1
.name
)
42 if e1
.value
!= e2
.value
:
43 raise ValueError("%s: value 0x%04x != 0x%04x"
44 % (e1
.name
, e1
.value
, e2
.value
))
46 def _check_type(self
, t1
, t2
, strict
=True):
47 if t1
.name
!= t2
.name
:
48 raise ValueError("%s: name mismatch" % t1
.name
)
49 if t1
.type_expr
.string() != t2
.type_expr
.string():
50 raise ValueError("%s: type %s != %s"
51 % (t1
.name
, t1
.type_expr
.string(), t2
.type_expr
.string()))
53 def _check_function(self
, f1
, f2
, strict
=True):
54 if f1
.name
!= f2
.name
:
55 raise ValueError("%s: name mismatch" % f1
.name
)
56 if f1
.return_type
!= f2
.return_type
:
57 raise ValueError("%s: return type %s != %s"
58 % (f1
.name
, f1
.return_type
, f2
.return_type
))
59 # there might be padded parameters
60 if strict
and len(f1
.parameters
) != len(f2
.parameters
):
61 raise ValueError("%s: parameter length %d != %d"
62 % (f1
.name
, len(f1
.parameters
), len(f2
.parameters
)))
63 if f1
.assign_offset
!= f2
.assign_offset
:
64 if ((f1
.assign_offset
and f2
.offset
< 0) or
65 (f2
.assign_offset
and f1
.offset
< 0)):
66 raise ValueError("%s: assign offset %d != %d"
67 % (f1
.name
, f1
.assign_offset
, f2
.assign_offset
))
68 elif not f1
.assign_offset
:
69 if f1
.offset
!= f2
.offset
:
70 raise ValueError("%s: offset %d != %d"
71 % (f1
.name
, f1
.offset
, f2
.offset
))
79 raise ValueError("%s: entry points %s != %s"
82 l1
= f1
.static_entry_points
83 l2
= f2
.static_entry_points
87 raise ValueError("%s: static entry points %s != %s"
91 for i
in xrange(len(f1
.parameters
)):
93 p2
= f2
.parameters
[i
+ pad
]
95 if not strict
and p1
.is_padding
!= p2
.is_padding
:
101 p2
= f2
.parameters
[i
+ pad
]
103 if strict
and p1
.name
!= p2
.name
:
104 raise ValueError("%s: parameter %d name %s != %s"
105 % (f1
.name
, i
, p1
.name
, p2
.name
))
106 if p1
.type_expr
.string() != p2
.type_expr
.string():
109 f1
.name
== "TexImage2D" and p1
.name
!= "internalformat"):
110 raise ValueError("%s: parameter %s type %s != %s"
111 % (f1
.name
, p1
.name
, p1
.type_expr
.string(),
112 p2
.type_expr
.string()))
114 def union(self
, other
):
115 union
= gl_XML
.gl_api(None)
117 if "enum" in self
.elts
:
118 union
.enums_by_name
= other
.enums_by_name
.copy()
119 for key
, val
in self
.api
.enums_by_name
.iteritems():
120 if key
not in union
.enums_by_name
:
121 union
.enums_by_name
[key
] = val
123 self
._check
_enum
(val
, other
.enums_by_name
[key
])
125 if "type" in self
.elts
:
126 union
.types_by_name
= other
.types_by_name
.copy()
127 for key
, val
in self
.api
.types_by_name
.iteritems():
128 if key
not in union
.types_by_name
:
129 union
.types_by_name
[key
] = val
131 self
._check
_type
(val
, other
.types_by_name
[key
])
133 if "function" in self
.elts
:
134 union
.functions_by_name
= other
.functions_by_name
.copy()
135 for key
, val
in self
.api
.functions_by_name
.iteritems():
136 if key
not in union
.functions_by_name
:
137 union
.functions_by_name
[key
] = val
139 self
._check
_function
(val
, other
.functions_by_name
[key
])
143 def intersection(self
, other
):
144 intersection
= gl_XML
.gl_api(None)
146 if "enum" in self
.elts
:
147 for key
, val
in self
.api
.enums_by_name
.iteritems():
148 if key
in other
.enums_by_name
:
149 self
._check
_enum
(val
, other
.enums_by_name
[key
])
150 intersection
.enums_by_name
[key
] = val
152 if "type" in self
.elts
:
153 for key
, val
in self
.api
.types_by_name
.iteritems():
154 if key
in other
.types_by_name
:
155 self
._check
_type
(val
, other
.types_by_name
[key
])
156 intersection
.types_by_name
[key
] = val
158 if "function" in self
.elts
:
159 for key
, val
in self
.api
.functions_by_name
.iteritems():
160 if key
in other
.functions_by_name
:
161 self
._check
_function
(val
, other
.functions_by_name
[key
])
162 intersection
.functions_by_name
[key
] = val
166 def difference(self
, other
):
167 difference
= gl_XML
.gl_api(None)
169 if "enum" in self
.elts
:
170 for key
, val
in self
.api
.enums_by_name
.iteritems():
171 if key
not in other
.enums_by_name
:
172 difference
.enums_by_name
[key
] = val
174 self
._check
_enum
(val
, other
.enums_by_name
[key
])
176 if "type" in self
.elts
:
177 for key
, val
in self
.api
.types_by_name
.iteritems():
178 if key
not in other
.types_by_name
:
179 difference
.types_by_name
[key
] = val
181 self
._check
_type
(val
, other
.types_by_name
[key
])
183 if "function" in self
.elts
:
184 for key
, val
in self
.api
.functions_by_name
.iteritems():
185 if key
not in other
.functions_by_name
:
186 difference
.functions_by_name
[key
] = val
188 self
._check
_function
(val
, other
.functions_by_name
[key
], False)
192 def cmp_enum(e1
, e2
):
193 if e1
.value
< e2
.value
:
195 elif e1
.value
> e2
.value
:
200 def cmp_type(t1
, t2
):
201 return t1
.size
- t2
.size
203 def cmp_function(f1
, f2
):
204 if f1
.name
> f2
.name
:
206 elif f1
.name
< f2
.name
:
211 def spaces(n
, str=""):
212 spaces
= n
- len(str)
217 def output_enum(e
, indent
=0):
218 attrs
= 'name="%s"' % e
.name
219 if e
.default_count
> 0:
220 tab
= spaces(37, attrs
)
221 attrs
+= '%scount="%d"' % (tab
, e
.default_count
)
222 tab
= spaces(48, attrs
)
223 val
= "%04x" % e
.value
224 val
= "0x" + val
.upper()
225 attrs
+= '%svalue="%s"' % (tab
, val
)
229 print '%s<enum %s/>' % (spaces(indent
), attrs
)
232 print '%s<enum %s>' % (spaces(indent
), attrs
)
233 for key
, val
in e
.functions
.iteritems():
234 attrs
= 'name="%s"' % key
235 if val
[0] != e
.default_count
:
236 attrs
+= ' count="%d"' % val
[0]
238 attrs
+= ' mode="get"'
240 print '%s<size %s/>' % (spaces(indent
* 2), attrs
)
242 print '%s</enum>' % spaces(indent
)
244 def output_type(t
, indent
=0):
245 tab
= spaces(16, t
.name
)
246 attrs
= 'name="%s"%ssize="%d"' % (t
.name
, tab
, t
.size
)
247 ctype
= t
.type_expr
.string()
248 if ctype
.find("unsigned") != -1:
249 attrs
+= ' unsigned="true"'
250 elif ctype
.find("signed") == -1:
251 attrs
+= ' float="true"'
252 print '%s<type %s/>' % (spaces(indent
), attrs
)
254 def output_function(f
, indent
=0):
255 attrs
= 'name="%s"' % f
.name
258 attrs
+= ' offset="assign"'
260 attrs
+= ' offset="%d"' % f
.offset
261 print '%s<function %s>' % (spaces(indent
), attrs
)
263 for p
in f
.parameters
:
264 attrs
= 'name="%s" type="%s"' \
265 % (p
.name
, p
.type_expr
.original_string
)
266 print '%s<param %s/>' % (spaces(indent
* 2), attrs
)
267 if f
.return_type
!= "void":
268 attrs
= 'type="%s"' % f
.return_type
269 print '%s<return %s/>' % (spaces(indent
* 2), attrs
)
271 print '%s</function>' % spaces(indent
)
273 def output_category(api
, indent
=0):
274 enums
= api
.enums_by_name
.values()
276 types
= api
.types_by_name
.values()
278 functions
= api
.functions_by_name
.values()
279 functions
.sort(cmp_function
)
282 output_enum(e
, indent
)
286 output_type(t
, indent
)
290 output_function(f
, indent
)
291 if f
!= functions
[-1]:
294 def is_api_empty(api
):
295 return bool(not api
.enums_by_name
and
296 not api
.types_by_name
and
297 not api
.functions_by_name
)
300 print "Usage: %s [-k elts] <%s> <file1> <file2>" % (sys
.argv
[0], "|".join(ops
))
301 print " -k elts A comma separated string of types of elements to"
302 print " skip. Possible types are enum, type, and function."
306 ops
= ["union", "intersection", "difference"]
307 elts
= ["enum", "type", "function"]
310 options
, args
= getopt
.getopt(sys
.argv
[1:], "k:")
316 op
, file1
, file2
= args
321 for opt
, val
in options
:
323 skips
= val
.split(",")
331 api1
= gl_XML
.parse_GL_API(file1
, glX_XML
.glx_item_factory())
332 api2
= gl_XML
.parse_GL_API(file2
, glX_XML
.glx_item_factory())
334 set = ApiSet(api1
, elts
)
335 func
= getattr(set, op
)
338 if not is_api_empty(result
):
339 cat_name
= "%s_of_%s_and_%s" \
340 % (op
, os
.path
.basename(file1
), os
.path
.basename(file2
))
342 print '<?xml version="1.0"?>'
343 print '<!DOCTYPE OpenGLAPI SYSTEM "%s/gl_API.dtd">' % GLAPI
347 print '<category name="%s">' % (cat_name
)
348 output_category(result
, 4)
353 if __name__
== "__main__":