state.py revision f591e195
1'''
2This module contains the namespace class and the singleton module class.
3'''
4from os.path import dirname, basename
5from xml.etree.cElementTree import parse
6
7from xcbgen import matcher
8from xcbgen.error import *
9from xcbgen.xtypes import *
10
11import __main__
12
13class Namespace(object):
14    '''
15    Contains the naming information for an extension.
16
17    Public fields:
18
19    header is the header attribute ("header file" name).
20    is_ext is true for extensions, false for xproto.
21    major_version and minor_version are extension version info.
22    ext_xname is the X extension name string.
23    ext_name is the XCB extension name prefix.
24    '''
25    def __init__(self, filename):
26        # Path info
27        self.path = filename
28        self.dir = dirname(filename)
29        self.file = basename(filename)
30
31        # Parse XML
32        self.root = parse(filename).getroot()
33        self.header = self.root.get('header')
34        self.ns = self.header + ':'
35
36        # Get root element attributes
37        if self.root.get('extension-xname', False):
38            self.is_ext = True
39            self.major_version = self.root.get('major-version')
40            self.minor_version = self.root.get('minor-version')
41            self.ext_xname = self.root.get('extension-xname')
42            self.ext_name = self.root.get('extension-name')
43            self.prefix = ('xcb', self.ext_name)
44        else:
45            self.is_ext = False
46            self.ext_name = ''
47            self.prefix = ('xcb',)
48
49
50class Module(object):
51    '''
52    This is the grand, encompassing class that represents an entire XCB specification.
53    Only gets instantiated once, in the main() routine.
54
55    Don't need to worry about this much except to declare it and to get the namespace.
56
57    Public fields:
58    namespace contains the namespace info for the spec.
59    '''
60    open = __main__.output['open']
61    close = __main__.output['close']
62
63    def __init__(self, filename, output):
64        self.namespace = Namespace(filename)
65        self.output = output
66
67        self.imports = []
68        self.types = {}
69        self.events = {}
70        self.errors = {}
71        self.all = []
72
73        # Register some common types
74        self.add_type('CARD8', '', ('uint8_t',), tcard8)
75        self.add_type('CARD16', '', ('uint16_t',), tcard16)
76        self.add_type('CARD32', '', ('uint32_t',), tcard32)
77        self.add_type('CARD64', '', ('uint64_t',), tcard64)
78        self.add_type('INT8', '', ('int8_t',), tint8)
79        self.add_type('INT16', '', ('int16_t',), tint16)
80        self.add_type('INT32', '', ('int32_t',), tint32)
81        self.add_type('INT64', '', ('int64_t',), tint64)
82        self.add_type('BYTE', '', ('uint8_t',), tcard8)
83        self.add_type('BOOL', '', ('uint8_t',), tcard8)
84        self.add_type('char', '', ('char',), tchar)
85        self.add_type('float', '', ('float',), tfloat)
86        self.add_type('double', '', ('double',), tdouble)
87        self.add_type('void', '', ('void',), tcard8)
88
89    # This goes out and parses the rest of the XML
90    def register(self):
91        matcher.execute(self, self.namespace)
92
93    # Recursively resolve all types
94    def resolve(self):
95        for (name, item) in self.all:
96            item.resolve(self)
97
98    # Call all the output methods
99    def generate(self):
100        self.open()
101
102        for (name, item) in self.all:
103            item.out(name)
104
105        self.close()
106
107    # Keeps track of what's been imported so far.
108    def add_import(self, name, namespace):
109        self.imports.append((name, namespace.header))
110
111    def has_import(self, name):
112        for (name_, header) in self.imports:
113            if name_ == name:
114                return True
115        return False
116
117    # Keeps track of non-request/event/error datatypes
118    def add_type(self, id, ns, name, item):
119        key = ns + id
120        if key in self.types:
121            return
122        self.types[key] = (name, item)
123        if name[:-1] == self.namespace.prefix:
124            self.all.append((name, item))
125
126    def get_type_impl(self, id, idx):
127        key = id
128        if key in self.types:
129            return self.types[key][idx]
130
131        key = self.namespace.ns + id
132        if key in self.types:
133            return self.types[key][idx]
134
135        for key in self.types.keys():
136            if key.rpartition(':')[2] == id:
137                return self.types[key][idx]
138
139        raise ResolveException('Type %s not found' % id)
140
141    def get_type(self, id):
142        return self.get_type_impl(id, 1)
143
144    def get_type_name(self, id):
145        return self.get_type_impl(id, 0)
146
147    # Keeps track of request datatypes
148    def add_request(self, id, name, item):
149        if name[:-1] == self.namespace.prefix:
150            self.all.append((name, item))
151
152    # Keeps track of event datatypes
153    def add_event(self, id, name, item):
154        self.events[id] = (name, item)
155        if name[:-1] == self.namespace.prefix:
156            self.all.append((name, item))
157
158    def get_event(self, id):
159        return self.events[id][1]
160
161    # Keeps track of error datatypes
162    def add_error(self, id, name, item):
163        self.errors[id] = (name, item)
164        if name[:-1] == self.namespace.prefix:
165            self.all.append((name, item))
166
167    def get_error(self, id):
168        return self.errors[id][1]
169