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