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.direct_imports = []
69        self.import_level = 0
70        self.types = {}
71        self.events = {}
72        self.errors = {}
73        self.all = []
74
75        # Register some common types
76        self.add_type('CARD8', '', ('u8',), tcard8)
77        self.add_type('CARD16', '', ('u16',), tcard16)
78        self.add_type('CARD32', '', ('u32',), tcard32)
79        self.add_type('CARD64', '', ('u64',), tcard64)
80        self.add_type('INT8', '', ('i8',), tint8)
81        self.add_type('INT16', '', ('i16',), tint16)
82        self.add_type('INT32', '', ('i32',), tint32)
83        self.add_type('INT64', '', ('i64',), tint64)
84        self.add_type('BYTE', '', ('u8',), tcard8)
85        self.add_type('BOOL', '', ('BOOL',), tbool)
86        self.add_type('char', '', ('c_char',), tchar)
87        self.add_type('float', '', ('f32',), tfloat)
88        self.add_type('double', '', ('f64',), tdouble)
89        self.add_type('void', '', ('c_void',), tcard8)
90
91    # This goes out and parses the rest of the XML
92    def register(self):
93        matcher.execute(self, self.namespace)
94
95    # Recursively resolve all types
96    def resolve(self):
97        for (name, item) in self.all:
98            self.pads = 0
99            item.resolve(self)
100
101    # Call all the output methods
102    def generate(self):
103        self.open()
104
105        for (name, item) in self.all:
106            item.out(name)
107
108        self.close()
109
110    # Keeps track of what's been imported so far.
111    def add_import(self, name, namespace):
112        if self.import_level == 0:
113            self.direct_imports.append((name, namespace.header))
114        self.imports.append((name, namespace.header))
115
116    def has_import(self, name):
117        for (name_, header) in self.imports:
118            if name_ == name:
119                return True
120        return False
121
122    # Keeps track of non-request/event/error datatypes
123    def add_type(self, id, ns, name, item):
124        key = ns + id
125        if key in self.types:
126            return
127        self.types[key] = (name, item)
128        if name[:-1] == self.namespace.prefix:
129            self.all.append((name, item))
130
131    def get_type_impl(self, id, idx):
132        key = id
133        if key in self.types:
134            return self.types[key][idx]
135
136        key = self.namespace.ns + id
137        if key in self.types:
138            return self.types[key][idx]
139
140        for key in self.types.keys():
141            if key.rpartition(':')[2] == id:
142                return self.types[key][idx]
143
144        raise ResolveException('Type %s not found' % id)
145
146    def get_type(self, id):
147        return self.get_type_impl(id, 1)
148
149    def get_type_name(self, id):
150        return self.get_type_impl(id, 0)
151
152    # Keeps track of request datatypes
153    def add_request(self, id, name, item):
154        if name[:-1] == self.namespace.prefix:
155            self.all.append((name, item))
156
157    # Keeps track of event datatypes
158    def add_event(self, id, name, item):
159        self.events[id] = (name, item)
160        if name[:-1] == self.namespace.prefix:
161            self.all.append((name, item))
162
163    def get_event(self, id):
164        return self.events[id][1]
165
166    # Keeps track of error datatypes
167    def add_error(self, id, name, item):
168        self.errors[id] = (name, item)
169        if name[:-1] == self.namespace.prefix:
170            self.all.append((name, item))
171
172    def get_error(self, id):
173        return self.errors[id][1]
174