• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3# Mesa 3-D graphics library
4# Version:  7.9
5#
6# Copyright (C) 2010 LunarG Inc.
7#
8# Permission is hereby granted, free of charge, to any person obtaining a
9# copy of this software and associated documentation files (the "Software"),
10# to deal in the Software without restriction, including without limitation
11# the rights to use, copy, modify, merge, publish, distribute, sublicense,
12# and/or sell copies of the Software, and to permit persons to whom the
13# Software is furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included
16# in all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24# DEALINGS IN THE SOFTWARE.
25#
26# Authors:
27#    Chia-I Wu <olv@lunarg.com>
28
29import sys
30# make it possible to import glapi
31import os
32GLAPI = "./%s/../glapi/gen" % (os.path.dirname(sys.argv[0]))
33sys.path.append(GLAPI)
34
35import re
36from optparse import OptionParser
37
38# number of dynamic entries
39ABI_NUM_DYNAMIC_ENTRIES = 256
40
41class ABIEntry(object):
42    """Represent an ABI entry."""
43
44    _match_c_param = re.compile(
45            '^(?P<type>[\w\s*]+?)(?P<name>\w+)(\[(?P<array>\d+)\])?$')
46
47    def __init__(self, cols, attrs):
48        self._parse(cols)
49
50        self.slot = attrs['slot']
51        self.hidden = attrs['hidden']
52        self.alias = attrs['alias']
53        self.handcode = attrs['handcode']
54
55    def c_prototype(self):
56        return '%s %s(%s)' % (self.c_return(), self.name, self.c_params())
57
58    def c_return(self):
59        ret = self.ret
60        if not ret:
61            ret = 'void'
62
63        return ret
64
65    def c_params(self):
66        """Return the parameter list used in the entry prototype."""
67        c_params = []
68        for t, n, a in self.params:
69            sep = '' if t.endswith('*') else ' '
70            arr = '[%d]' % a if a else ''
71            c_params.append(t + sep + n + arr)
72        if not c_params:
73            c_params.append('void')
74
75        return ", ".join(c_params)
76
77    def c_args(self):
78        """Return the argument list used in the entry invocation."""
79        c_args = []
80        for t, n, a in self.params:
81            c_args.append(n)
82
83        return ", ".join(c_args)
84
85    def _parse(self, cols):
86        ret = cols.pop(0)
87        if ret == 'void':
88            ret = None
89
90        name = cols.pop(0)
91
92        params = []
93        if not cols:
94            raise Exception(cols)
95        elif len(cols) == 1 and cols[0] == 'void':
96            pass
97        else:
98            for val in cols:
99                params.append(self._parse_param(val))
100
101        self.ret = ret
102        self.name = name
103        self.params = params
104
105    def _parse_param(self, c_param):
106        m = self._match_c_param.match(c_param)
107        if not m:
108            raise Exception('unrecognized param ' + c_param)
109
110        c_type = m.group('type').strip()
111        c_name = m.group('name')
112        c_array = m.group('array')
113        c_array = int(c_array) if c_array else 0
114
115        return (c_type, c_name, c_array)
116
117    def __str__(self):
118        return self.c_prototype()
119
120    def __cmp__(self, other):
121        # compare slot, alias, and then name
122        res = cmp(self.slot, other.slot)
123        if not res:
124            if not self.alias:
125                res = -1
126            elif not other.alias:
127                res = 1
128
129            if not res:
130                res = cmp(self.name, other.name)
131
132        return res
133
134def abi_parse_xml(xml):
135    """Parse a GLAPI XML file for ABI entries."""
136    import gl_XML, glX_XML
137
138    api = gl_XML.parse_GL_API(xml, glX_XML.glx_item_factory())
139
140    entry_dict = {}
141    for func in api.functionIterateByOffset():
142        # make sure func.name appear first
143        entry_points = func.entry_points[:]
144        entry_points.remove(func.name)
145        entry_points.insert(0, func.name)
146
147        for name in entry_points:
148            attrs = {
149                    'slot': func.offset,
150                    'hidden': not func.is_static_entry_point(name),
151                    'alias': None if name == func.name else func.name,
152                    'handcode': bool(func.has_different_protocol(name)),
153            }
154
155            # post-process attrs
156            if attrs['alias']:
157                try:
158                    alias = entry_dict[attrs['alias']]
159                except KeyError:
160                    raise Exception('failed to alias %s' % attrs['alias'])
161                if alias.alias:
162                    raise Exception('recursive alias %s' % ent.name)
163                attrs['alias'] = alias
164            if attrs['handcode']:
165                attrs['handcode'] = func.static_glx_name(name)
166            else:
167                attrs['handcode'] = None
168
169            if entry_dict.has_key(name):
170                raise Exception('%s is duplicated' % (name))
171
172            cols = []
173            cols.append(func.return_type)
174            cols.append(name)
175            params = func.get_parameter_string(name)
176            cols.extend([p.strip() for p in params.split(',')])
177
178            ent = ABIEntry(cols, attrs)
179            entry_dict[ent.name] = ent
180
181    entries = entry_dict.values()
182    entries.sort()
183
184    return entries
185
186def abi_parse_line(line):
187    cols = [col.strip() for col in line.split(',')]
188
189    attrs = {
190            'slot': -1,
191            'hidden': False,
192            'alias': None,
193            'handcode': None,
194    }
195
196    # extract attributes from the first column
197    vals = cols[0].split(':')
198    while len(vals) > 1:
199        val = vals.pop(0)
200        if val.startswith('slot='):
201            attrs['slot'] = int(val[5:])
202        elif val == 'hidden':
203            attrs['hidden'] = True
204        elif val.startswith('alias='):
205            attrs['alias'] = val[6:]
206        elif val.startswith('handcode='):
207            attrs['handcode'] = val[9:]
208        elif not val:
209            pass
210        else:
211            raise Exception('unknown attribute %s' % val)
212    cols[0] = vals[0]
213
214    return (attrs, cols)
215
216def abi_parse(filename):
217    """Parse a CSV file for ABI entries."""
218    fp = open(filename) if filename != '-' else sys.stdin
219    lines = [line.strip() for line in fp.readlines()
220            if not line.startswith('#') and line.strip()]
221
222    entry_dict = {}
223    next_slot = 0
224    for line in lines:
225        attrs, cols = abi_parse_line(line)
226
227        # post-process attributes
228        if attrs['alias']:
229            try:
230                alias = entry_dict[attrs['alias']]
231            except KeyError:
232                raise Exception('failed to alias %s' % attrs['alias'])
233            if alias.alias:
234                raise Exception('recursive alias %s' % ent.name)
235            slot = alias.slot
236            attrs['alias'] = alias
237        else:
238            slot = next_slot
239            next_slot += 1
240
241        if attrs['slot'] < 0:
242            attrs['slot'] = slot
243        elif attrs['slot'] != slot:
244            raise Exception('invalid slot in %s' % (line))
245
246        ent = ABIEntry(cols, attrs)
247        if entry_dict.has_key(ent.name):
248            raise Exception('%s is duplicated' % (ent.name))
249        entry_dict[ent.name] = ent
250
251    entries = entry_dict.values()
252    entries.sort()
253
254    return entries
255
256def abi_sanity_check(entries):
257    if not entries:
258        return
259
260    all_names = []
261    last_slot = entries[-1].slot
262    i = 0
263    for slot in xrange(last_slot + 1):
264        if entries[i].slot != slot:
265            raise Exception('entries are not ordered by slots')
266        if entries[i].alias:
267            raise Exception('first entry of slot %d aliases %s'
268                    % (slot, entries[i].alias.name))
269        handcode = None
270        while i < len(entries) and entries[i].slot == slot:
271            ent = entries[i]
272            if not handcode and ent.handcode:
273                handcode = ent.handcode
274            elif ent.handcode != handcode:
275                raise Exception('two aliases with handcode %s != %s',
276                        ent.handcode, handcode)
277
278            if ent.name in all_names:
279                raise Exception('%s is duplicated' % (ent.name))
280            if ent.alias and ent.alias.name not in all_names:
281                raise Exception('failed to alias %s' % (ent.alias.name))
282            all_names.append(ent.name)
283            i += 1
284    if i < len(entries):
285        raise Exception('there are %d invalid entries' % (len(entries) - 1))
286
287class ABIPrinter(object):
288    """MAPI Printer"""
289
290    def __init__(self, entries):
291        self.entries = entries
292
293        # sort entries by their names
294        self.entries_sorted_by_names = self.entries[:]
295        self.entries_sorted_by_names.sort(lambda x, y: cmp(x.name, y.name))
296
297        self.indent = ' ' * 3
298        self.noop_warn = 'noop_warn'
299        self.noop_generic = 'noop_generic'
300        self.current_get = 'entry_current_get'
301
302        self.api_defines = []
303        self.api_headers = ['"KHR/khrplatform.h"']
304        self.api_call = 'KHRONOS_APICALL'
305        self.api_entry = 'KHRONOS_APIENTRY'
306        self.api_attrs = 'KHRONOS_APIATTRIBUTES'
307
308        self.c_header = ''
309
310        self.lib_need_table_size = True
311        self.lib_need_noop_array = True
312        self.lib_need_stubs = True
313        self.lib_need_all_entries = True
314        self.lib_need_non_hidden_entries = False
315
316    def c_notice(self):
317        return '/* This file is automatically generated by mapi_abi.py.  Do not modify. */'
318
319    def c_public_includes(self):
320        """Return includes of the client API headers."""
321        defines = ['#define ' + d for d in self.api_defines]
322        includes = ['#include ' + h for h in self.api_headers]
323        return "\n".join(defines + includes)
324
325    def need_entry_point(self, ent):
326        """Return True if an entry point is needed for the entry."""
327        # non-handcode hidden aliases may share the entry they alias
328        use_alias = (ent.hidden and ent.alias and not ent.handcode)
329        return not use_alias
330
331    def c_public_declarations(self, prefix):
332        """Return the declarations of public entry points."""
333        decls = []
334        for ent in self.entries:
335            if not self.need_entry_point(ent):
336                continue
337            export = self.api_call if not ent.hidden else ''
338            decls.append(self._c_decl(ent, prefix, True, export) + ';')
339
340        return "\n".join(decls)
341
342    def c_mapi_table(self):
343        """Return defines of the dispatch table size."""
344        num_static_entries = self.entries[-1].slot + 1
345        return ('#define MAPI_TABLE_NUM_STATIC %d\n' + \
346                '#define MAPI_TABLE_NUM_DYNAMIC %d') % (
347                        num_static_entries, ABI_NUM_DYNAMIC_ENTRIES)
348
349    def c_mapi_table_initializer(self, prefix):
350        """Return the array initializer for mapi_table_fill."""
351        entries = [self._c_function(ent, prefix)
352                for ent in self.entries if not ent.alias]
353        pre = self.indent + '(mapi_proc) '
354        return pre + (',\n' + pre).join(entries)
355
356    def c_mapi_table_spec(self):
357        """Return the spec for mapi_init."""
358        specv1 = []
359        line = '"1'
360        for ent in self.entries:
361            if not ent.alias:
362                line += '\\0"\n'
363                specv1.append(line)
364                line = '"'
365            line += '%s\\0' % ent.name
366        line += '";'
367        specv1.append(line)
368
369        return self.indent + self.indent.join(specv1)
370
371    def _c_function(self, ent, prefix, mangle=False, stringify=False):
372        """Return the function name of an entry."""
373        formats = {
374                True: { True: '%s_STR(%s)', False: '%s(%s)' },
375                False: { True: '"%s%s"', False: '%s%s' },
376        }
377        fmt = formats[prefix.isupper()][stringify]
378        name = ent.name
379        if mangle and ent.hidden:
380            name = '_dispatch_stub_' + str(ent.slot)
381        return fmt % (prefix, name)
382
383    def _c_function_call(self, ent, prefix):
384        """Return the function name used for calling."""
385        if ent.handcode:
386            # _c_function does not handle this case
387            formats = { True: '%s(%s)', False: '%s%s' }
388            fmt = formats[prefix.isupper()]
389            name = fmt % (prefix, ent.handcode)
390        elif self.need_entry_point(ent):
391            name = self._c_function(ent, prefix, True)
392        else:
393            name = self._c_function(ent.alias, prefix, True)
394        return name
395
396    def _c_decl(self, ent, prefix, mangle=False, export=''):
397        """Return the C declaration for the entry."""
398        decl = '%s %s %s(%s)' % (ent.c_return(), self.api_entry,
399                self._c_function(ent, prefix, mangle), ent.c_params())
400        if export:
401            decl = export + ' ' + decl
402        if self.api_attrs:
403            decl += ' ' + self.api_attrs
404
405        return decl
406
407    def _c_cast(self, ent):
408        """Return the C cast for the entry."""
409        cast = '%s (%s *)(%s)' % (
410                ent.c_return(), self.api_entry, ent.c_params())
411
412        return cast
413
414    def c_private_declarations(self, prefix):
415        """Return the declarations of private functions."""
416        decls = [self._c_decl(ent, prefix) + ';'
417                for ent in self.entries if not ent.alias]
418
419        return "\n".join(decls)
420
421    def c_public_dispatches(self, prefix, no_hidden):
422        """Return the public dispatch functions."""
423        dispatches = []
424        for ent in self.entries:
425            if ent.hidden and no_hidden:
426                continue
427
428            if not self.need_entry_point(ent):
429                continue
430
431            export = self.api_call if not ent.hidden else ''
432
433            proto = self._c_decl(ent, prefix, True, export)
434            cast = self._c_cast(ent)
435
436            ret = ''
437            if ent.ret:
438                ret = 'return '
439            stmt1 = self.indent
440            stmt1 += 'const struct mapi_table *_tbl = %s();' % (
441                    self.current_get)
442            stmt2 = self.indent
443            stmt2 += 'mapi_func _func = ((const mapi_func *) _tbl)[%d];' % (
444                    ent.slot)
445            stmt3 = self.indent
446            stmt3 += '%s((%s) _func)(%s);' % (ret, cast, ent.c_args())
447
448            disp = '%s\n{\n%s\n%s\n%s\n}' % (proto, stmt1, stmt2, stmt3)
449
450            if ent.handcode:
451                disp = '#if 0\n' + disp + '\n#endif'
452
453            dispatches.append(disp)
454
455        return '\n\n'.join(dispatches)
456
457    def c_public_initializer(self, prefix):
458        """Return the initializer for public dispatch functions."""
459        names = []
460        for ent in self.entries:
461            if ent.alias:
462                continue
463
464            name = '%s(mapi_func) %s' % (self.indent,
465                    self._c_function_call(ent, prefix))
466            names.append(name)
467
468        return ',\n'.join(names)
469
470    def c_stub_string_pool(self):
471        """Return the string pool for use by stubs."""
472        # sort entries by their names
473        sorted_entries = self.entries[:]
474        sorted_entries.sort(lambda x, y: cmp(x.name, y.name))
475
476        pool = []
477        offsets = {}
478        count = 0
479        for ent in sorted_entries:
480            offsets[ent] = count
481            pool.append('%s' % (ent.name))
482            count += len(ent.name) + 1
483
484        pool_str =  self.indent + '"' + \
485                ('\\0"\n' + self.indent + '"').join(pool) + '";'
486        return (pool_str, offsets)
487
488    def c_stub_initializer(self, prefix, pool_offsets):
489        """Return the initializer for struct mapi_stub array."""
490        stubs = []
491        for ent in self.entries_sorted_by_names:
492            stubs.append('%s{ (void *) %d, %d, NULL }' % (
493                self.indent, pool_offsets[ent], ent.slot))
494
495        return ',\n'.join(stubs)
496
497    def c_noop_functions(self, prefix, warn_prefix):
498        """Return the noop functions."""
499        noops = []
500        for ent in self.entries:
501            if ent.alias:
502                continue
503
504            proto = self._c_decl(ent, prefix, False, 'static')
505
506            stmt1 = self.indent;
507            space = ''
508            for t, n, a in ent.params:
509                stmt1 += "%s(void) %s;" % (space, n)
510                space = ' '
511
512            if ent.params:
513                stmt1 += '\n';
514
515            stmt1 += self.indent + '%s(%s);' % (self.noop_warn,
516                    self._c_function(ent, warn_prefix, False, True))
517
518            if ent.ret:
519                stmt2 = self.indent + 'return (%s) 0;' % (ent.ret)
520                noop = '%s\n{\n%s\n%s\n}' % (proto, stmt1, stmt2)
521            else:
522                noop = '%s\n{\n%s\n}' % (proto, stmt1)
523
524            noops.append(noop)
525
526        return '\n\n'.join(noops)
527
528    def c_noop_initializer(self, prefix, use_generic):
529        """Return an initializer for the noop dispatch table."""
530        entries = [self._c_function(ent, prefix)
531                for ent in self.entries if not ent.alias]
532        if use_generic:
533            entries = [self.noop_generic] * len(entries)
534
535        entries.extend([self.noop_generic] * ABI_NUM_DYNAMIC_ENTRIES)
536
537        pre = self.indent + '(mapi_func) '
538        return pre + (',\n' + pre).join(entries)
539
540    def c_asm_gcc(self, prefix, no_hidden):
541        asm = []
542
543        for ent in self.entries:
544            if ent.hidden and no_hidden:
545                continue
546
547            if not self.need_entry_point(ent):
548                continue
549
550            name = self._c_function(ent, prefix, True, True)
551
552            if ent.handcode:
553                asm.append('#if 0')
554
555            if ent.hidden:
556                asm.append('".hidden "%s"\\n"' % (name))
557
558            if ent.alias and not (ent.alias.hidden and no_hidden):
559                asm.append('".globl "%s"\\n"' % (name))
560                asm.append('".set "%s", "%s"\\n"' % (name,
561                    self._c_function(ent.alias, prefix, True, True)))
562            else:
563                asm.append('STUB_ASM_ENTRY(%s)"\\n"' % (name))
564                asm.append('"\\t"STUB_ASM_CODE("%d")"\\n"' % (ent.slot))
565
566            if ent.handcode:
567                asm.append('#endif')
568            asm.append('')
569
570        return "\n".join(asm)
571
572    def output_for_lib(self):
573        print self.c_notice()
574
575        if self.c_header:
576            print
577            print self.c_header
578
579        print
580        print '#ifdef MAPI_TMP_DEFINES'
581        print self.c_public_includes()
582        print
583        print self.c_public_declarations(self.prefix_lib)
584        print '#undef MAPI_TMP_DEFINES'
585        print '#endif /* MAPI_TMP_DEFINES */'
586
587        if self.lib_need_table_size:
588            print
589            print '#ifdef MAPI_TMP_TABLE'
590            print self.c_mapi_table()
591            print '#undef MAPI_TMP_TABLE'
592            print '#endif /* MAPI_TMP_TABLE */'
593
594        if self.lib_need_noop_array:
595            print
596            print '#ifdef MAPI_TMP_NOOP_ARRAY'
597            print '#ifdef DEBUG'
598            print
599            print self.c_noop_functions(self.prefix_noop, self.prefix_warn)
600            print
601            print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop)
602            print self.c_noop_initializer(self.prefix_noop, False)
603            print '};'
604            print
605            print '#else /* DEBUG */'
606            print
607            print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop)
608            print self.c_noop_initializer(self.prefix_noop, True)
609            print '};'
610            print
611            print '#endif /* DEBUG */'
612            print '#undef MAPI_TMP_NOOP_ARRAY'
613            print '#endif /* MAPI_TMP_NOOP_ARRAY */'
614
615        if self.lib_need_stubs:
616            pool, pool_offsets = self.c_stub_string_pool()
617            print
618            print '#ifdef MAPI_TMP_PUBLIC_STUBS'
619            print 'static const char public_string_pool[] ='
620            print pool
621            print
622            print 'static const struct mapi_stub public_stubs[] = {'
623            print self.c_stub_initializer(self.prefix_lib, pool_offsets)
624            print '};'
625            print '#undef MAPI_TMP_PUBLIC_STUBS'
626            print '#endif /* MAPI_TMP_PUBLIC_STUBS */'
627
628        if self.lib_need_all_entries:
629            print
630            print '#ifdef MAPI_TMP_PUBLIC_ENTRIES'
631            print self.c_public_dispatches(self.prefix_lib, False)
632            print
633            print 'static const mapi_func public_entries[] = {'
634            print self.c_public_initializer(self.prefix_lib)
635            print '};'
636            print '#undef MAPI_TMP_PUBLIC_ENTRIES'
637            print '#endif /* MAPI_TMP_PUBLIC_ENTRIES */'
638
639            print
640            print '#ifdef MAPI_TMP_STUB_ASM_GCC'
641            print '__asm__('
642            print self.c_asm_gcc(self.prefix_lib, False)
643            print ');'
644            print '#undef MAPI_TMP_STUB_ASM_GCC'
645            print '#endif /* MAPI_TMP_STUB_ASM_GCC */'
646
647        if self.lib_need_non_hidden_entries:
648            all_hidden = True
649            for ent in self.entries:
650                if not ent.hidden:
651                    all_hidden = False
652                    break
653            if not all_hidden:
654                print
655                print '#ifdef MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN'
656                print self.c_public_dispatches(self.prefix_lib, True)
657                print
658                print '/* does not need public_entries */'
659                print '#undef MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN'
660                print '#endif /* MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN */'
661
662                print
663                print '#ifdef MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN'
664                print '__asm__('
665                print self.c_asm_gcc(self.prefix_lib, True)
666                print ');'
667                print '#undef MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN'
668                print '#endif /* MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN */'
669
670    def output_for_app(self):
671        print self.c_notice()
672        print
673        print self.c_private_declarations(self.prefix_app)
674        print
675        print '#ifdef API_TMP_DEFINE_SPEC'
676        print
677        print 'static const char %s_spec[] =' % (self.prefix_app)
678        print self.c_mapi_table_spec()
679        print
680        print 'static const mapi_proc %s_procs[] = {' % (self.prefix_app)
681        print self.c_mapi_table_initializer(self.prefix_app)
682        print '};'
683        print
684        print '#endif /* API_TMP_DEFINE_SPEC */'
685
686class GLAPIPrinter(ABIPrinter):
687    """OpenGL API Printer"""
688
689    def __init__(self, entries, api=None):
690        api_entries = self._get_api_entries(entries, api)
691        super(GLAPIPrinter, self).__init__(api_entries)
692
693        self.api_defines = ['GL_GLEXT_PROTOTYPES']
694        self.api_headers = ['"GL/gl.h"', '"GL/glext.h"']
695        self.api_call = 'GLAPI'
696        self.api_entry = 'APIENTRY'
697        self.api_attrs = ''
698
699        self.lib_need_table_size = False
700        self.lib_need_noop_array = False
701        self.lib_need_stubs = False
702        self.lib_need_all_entries = False
703        self.lib_need_non_hidden_entries = True
704
705        self.prefix_lib = 'GLAPI_PREFIX'
706        self.prefix_app = '_mesa_'
707        self.prefix_noop = 'noop'
708        self.prefix_warn = self.prefix_lib
709
710        self.c_header = self._get_c_header()
711
712    def _get_api_entries(self, entries, api):
713        """Override the entry attributes according to API."""
714        import copy
715
716        # no override
717        if api is None:
718            return entries
719
720        api_entries = {}
721        for ent in entries:
722            ent = copy.copy(ent)
723
724            # override 'hidden' and 'handcode'
725            ent.hidden = ent.name not in api
726            ent.handcode = False
727            if ent.alias:
728                ent.alias = api_entries[ent.alias.name]
729
730            api_entries[ent.name] = ent
731
732        # sanity check
733        missed = [name for name in api if name not in api_entries]
734        if missed:
735            raise Exception('%s is missing' % str(missed))
736
737        entries = api_entries.values()
738        entries.sort()
739
740        return entries
741
742    def _get_c_header(self):
743        header = """#ifndef _GLAPI_TMP_H_
744#define _GLAPI_TMP_H_
745#ifdef USE_MGL_NAMESPACE
746#define GLAPI_PREFIX(func)  mgl##func
747#define GLAPI_PREFIX_STR(func)  "mgl"#func
748#else
749#define GLAPI_PREFIX(func)  gl##func
750#define GLAPI_PREFIX_STR(func)  "gl"#func
751#endif /* USE_MGL_NAMESPACE */
752
753typedef int GLfixed;
754typedef int GLclampx;
755#endif /* _GLAPI_TMP_H_ */"""
756
757        return header
758
759class ES1APIPrinter(GLAPIPrinter):
760    """OpenGL ES 1.x API Printer"""
761
762    def __init__(self, entries):
763        from gles_api import es1_api
764
765        super(ES1APIPrinter, self).__init__(entries, es1_api)
766        self.prefix_lib = 'gl'
767        self.prefix_warn = 'gl'
768
769    def _get_c_header(self):
770        header = """#ifndef _GLAPI_TMP_H_
771#define _GLAPI_TMP_H_
772typedef int GLfixed;
773typedef int GLclampx;
774#endif /* _GLAPI_TMP_H_ */"""
775
776        return header
777
778class ES2APIPrinter(GLAPIPrinter):
779    """OpenGL ES 2.x API Printer"""
780
781    def __init__(self, entries):
782        from gles_api import es2_api
783
784        super(ES2APIPrinter, self).__init__(entries, es2_api)
785        self.prefix_lib = 'gl'
786        self.prefix_warn = 'gl'
787
788    def _get_c_header(self):
789        header = """#ifndef _GLAPI_TMP_H_
790#define _GLAPI_TMP_H_
791typedef int GLfixed;
792typedef int GLclampx;
793#endif /* _GLAPI_TMP_H_ */"""
794
795        return header
796
797class SharedGLAPIPrinter(GLAPIPrinter):
798    """Shared GLAPI API Printer"""
799
800    def __init__(self, entries):
801        super(SharedGLAPIPrinter, self).__init__(entries, [])
802
803        self.lib_need_table_size = True
804        self.lib_need_noop_array = True
805        self.lib_need_stubs = True
806        self.lib_need_all_entries = True
807        self.lib_need_non_hidden_entries = False
808
809        self.prefix_lib = 'shared'
810        self.prefix_warn = 'gl'
811
812    def _get_c_header(self):
813        header = """#ifndef _GLAPI_TMP_H_
814#define _GLAPI_TMP_H_
815typedef int GLfixed;
816typedef int GLclampx;
817#endif /* _GLAPI_TMP_H_ */"""
818
819        return header
820
821class VGAPIPrinter(ABIPrinter):
822    """OpenVG API Printer"""
823
824    def __init__(self, entries):
825        super(VGAPIPrinter, self).__init__(entries)
826
827        self.api_defines = ['VG_VGEXT_PROTOTYPES']
828        self.api_headers = ['"VG/openvg.h"', '"VG/vgext.h"']
829        self.api_call = 'VG_API_CALL'
830        self.api_entry = 'VG_API_ENTRY'
831        self.api_attrs = 'VG_API_EXIT'
832
833        self.prefix_lib = 'vg'
834        self.prefix_app = 'vega'
835        self.prefix_noop = 'noop'
836        self.prefix_warn = 'vg'
837
838def parse_args():
839    printers = ['vgapi', 'glapi', 'es1api', 'es2api', 'shared-glapi']
840    modes = ['lib', 'app']
841
842    parser = OptionParser(usage='usage: %prog [options] <filename>')
843    parser.add_option('-p', '--printer', dest='printer',
844            help='printer to use: %s' % (", ".join(printers)))
845    parser.add_option('-m', '--mode', dest='mode',
846            help='target user: %s' % (", ".join(modes)))
847
848    options, args = parser.parse_args()
849    if not args or options.printer not in printers or \
850            options.mode not in modes:
851        parser.print_help()
852        sys.exit(1)
853
854    return (args[0], options)
855
856def main():
857    printers = {
858        'vgapi': VGAPIPrinter,
859        'glapi': GLAPIPrinter,
860        'es1api': ES1APIPrinter,
861        'es2api': ES2APIPrinter,
862        'shared-glapi': SharedGLAPIPrinter,
863    }
864
865    filename, options = parse_args()
866
867    if filename.endswith('.xml'):
868        entries = abi_parse_xml(filename)
869    else:
870        entries = abi_parse(filename)
871    abi_sanity_check(entries)
872
873    printer = printers[options.printer](entries)
874    if options.mode == 'lib':
875        printer.output_for_lib()
876    else:
877        printer.output_for_app()
878
879if __name__ == '__main__':
880    main()
881