state.py revision a27842ff
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        # Events
37        self.events = {}
38
39        # Get root element attributes
40        if self.root.get('extension-xname', False):
41            self.is_ext = True
42            self.major_version = self.root.get('major-version')
43            self.minor_version = self.root.get('minor-version')
44            self.ext_xname = self.root.get('extension-xname')
45            self.ext_name = self.root.get('extension-name')
46            self.prefix = ('xcb', self.ext_name)
47        else:
48            self.is_ext = False
49            self.ext_name = ''
50            self.prefix = ('xcb',)
51
52    def add_event(self, id, name, item):
53        self.events[id] = (name, item)
54
55    def get_event_by_opcode(self, opcode, is_ge_event):
56        for id, (name, event) in self.events.items():
57            if event.is_ge_event == is_ge_event:
58                opcode_specific_name = event.get_name_for_opcode( opcode )
59                if opcode_specific_name is not None:
60                    return (opcode_specific_name, event)
61        return None
62
63
64class Module(object):
65    '''
66    This is the grand, encompassing class that represents an entire XCB specification.
67    Only gets instantiated once, in the main() routine.
68
69    Don't need to worry about this much except to declare it and to get the namespace.
70
71    Public fields:
72    namespace contains the namespace info for the spec.
73    '''
74    open = __main__.output['open']
75    close = __main__.output['close']
76
77    def __init__(self, filename, output):
78        self.namespace = Namespace(filename)
79        self.output = output
80
81        self.imports = []
82        self.direct_imports = []
83        self.import_level = 0
84        self.types = {}
85        self.events = {}
86        self.errors = {}
87        self.all = []
88
89        # dict of namespaces by ext_name
90        self.namespaces = {}
91        # enter the main namespace here
92        self.namespaces[self.namespace.ext_name] = self.namespace
93
94        # Register some common types
95        self.add_type('CARD8', '', ('uint8_t',), tcard8)
96        self.add_type('CARD16', '', ('uint16_t',), tcard16)
97        self.add_type('CARD32', '', ('uint32_t',), tcard32)
98        self.add_type('CARD64', '', ('uint64_t',), tcard64)
99        self.add_type('INT8', '', ('int8_t',), tint8)
100        self.add_type('INT16', '', ('int16_t',), tint16)
101        self.add_type('INT32', '', ('int32_t',), tint32)
102        self.add_type('INT64', '', ('int64_t',), tint64)
103        self.add_type('BYTE', '', ('uint8_t',), tcard8)
104        self.add_type('BOOL', '', ('uint8_t',), tcard8)
105        self.add_type('char', '', ('char',), tchar)
106        self.add_type('float', '', ('float',), tfloat)
107        self.add_type('double', '', ('double',), tdouble)
108        self.add_type('void', '', ('void',), tcard8)
109
110    # This goes out and parses the rest of the XML
111    def register(self):
112        matcher.execute(self, self.namespace)
113
114    # Recursively resolve all types
115    def resolve(self):
116        self.add_events_to_namespaces()
117        for (name, item) in self.all:
118            self.pads = 0
119            item.resolve(self)
120
121    # Call all the output methods
122    def generate(self):
123        self.open()
124
125        for (name, item) in self.all:
126            item.out(name)
127
128        self.close()
129
130    # Keeps track of what's been imported so far.
131    def add_import(self, name, namespace):
132        if self.import_level == 0:
133            self.direct_imports.append((name, namespace.header))
134        self.imports.append((name, namespace.header))
135        self.namespaces[namespace.ext_name] = namespace
136
137    def has_import(self, name):
138        for (name_, header) in self.imports:
139            if name_ == name:
140                return True
141        return False
142
143    # Keeps track of non-request/event/error datatypes
144    def add_type(self, id, ns, name, item):
145        key = ns + id
146        if key in self.types:
147            return
148        self.types[key] = (name, item)
149        if name[:-1] == self.namespace.prefix:
150            self.all.append((name, item))
151
152    def get_type_impl(self, id, idx):
153        key = id
154        if key in self.types:
155            return self.types[key][idx]
156
157        key = self.namespace.ns + id
158        if key in self.types:
159            return self.types[key][idx]
160
161        for key in self.types.keys():
162            if key.rpartition(':')[2] == id:
163                return self.types[key][idx]
164
165        raise ResolveException('Type %s not found' % id)
166
167    def get_type(self, id):
168        return self.get_type_impl(id, 1)
169
170    def get_type_name(self, id):
171        return self.get_type_impl(id, 0)
172
173    def get_namespace(self, ext_name):
174        return self.namespaces[ext_name]
175
176    # Keeps track of request datatypes
177    def add_request(self, id, name, item):
178        if name[:-1] == self.namespace.prefix:
179            self.all.append((name, item))
180
181    # Keeps track of event datatypes
182    def add_event(self, id, name, item):
183        self.events[id] = (name, item)
184        if name[:-1] == self.namespace.prefix:
185            self.all.append((name, item))
186
187
188    def add_events_to_namespaces(self):
189        # add to its namespace object
190        for id, (name,item) in self.events.items():
191            if name[:-1] == ('xcb',):
192                # core event
193                namespace_name = ''
194            else:
195                # extension event
196                namespace_name = name[-2]
197
198            namespace = self.namespaces[namespace_name]
199
200            if namespace is not None:
201                namespace.add_event(id, name, item)
202
203
204    def get_event(self, id):
205        return self.events[id][1]
206
207    # Keeps track of error datatypes
208    def add_error(self, id, name, item):
209        self.errors[id] = (name, item)
210        if name[:-1] == self.namespace.prefix:
211            self.all.append((name, item))
212
213    def get_error(self, id):
214        return self.errors[id][1]
215