"""This file takes the message schemas from message.py and produces a C source file that reads and writes the messages. It's all fairly imcomprehensible. I also go to rather outrageous lengths to generate nice C, not sure why. """ from pairtype import * from binary import * import message from message import TempEntity import StringIO, sys import tempentitycode class CType(object): crep = None weak = False def __init__(self, **kw): self.__dict__.update(kw) class Long(CType): crep = 'long' class Float(CType): crep = 'float' class CharP(CType): crep = 'char *' class CharPP(CType): crep = 'char *' class __extend__(pairtype(CType, CType)): def merge((l, r)): if l.__class__ == r.__class__: return l.__class__(weak=l.weak and r.weak) if l.weak: return r if r.weak: return l raise Exception, 'clash' def merge(t1, t2): return pair(t1, t2).merge() def return_output(f): def wrapped(*args, **kw): o = StringIO.StringIO() save = sys.stdout sys.stdout = o try: r = f(*args, **kw) assert r is None return o.getvalue()[:-1] finally: sys.stdout = save return wrapped class Variable(object): def __init__(self, name, ctype): self.name = name self.ctype = ctype def __str__(self): return "\t%s\t%s;"%(self.ctype.crep, self.name) class ArrayVariable(Variable): def __init__(self, name, ctype): Variable.__init__(self, name, ctype) self.count = 0 def __str__(self): return "\t%s\t%s[%s];"%(self.ctype.crep, self.name, self.count) def typeof(dataitem): if isinstance(dataitem, RepeatedDataItem): v = ArrayVariable(dataitem.name, _typeof(dataitem.sub)) v.count = dataitem.mcount return v else: v = Variable(dataitem.name, _typeof(dataitem)) return v def _typeof(dataitem): if isinstance(dataitem, StructDataItem): if dataitem.code in ['mask & 0x%x) ? (%s) : (Py_INCREF(Py_None), Py_None)'%( d.bit, getset_simple(d.sub, v)) else: print getset_simple(d.sub, v) else: raise Exception, d @return_output def getset_get(d): if isinstance(d, RepeatedDataItem): print 'PyObject* r;' print print 'r = PyTuple_New(%s);'%(d.mcount,) print 'if (!r)' print '\treturn NULL;' print for i in range(d.count): print 'PyTuple_SET_ITEM(r, %s, '%i+getset_simple(d.sub, 'obj->%s[%i]'%(d.name,i))+');' i += 1 for e in d.extensions: for i in range(i, i+d.count): print 'PyTuple_SET_ITEM(r, %s, '%i+getset_simple(e.sub, 'obj->%s[%i]'%(d.name,i))+');' i += 1 print print 'return r;' elif isinstance(d, STRINGLIST): print '''PyObject *r; PyObject *s; int i = 0; r = PyList_New(0); if (r == NULL) return NULL; while (1) { if (!obj->%(name)s[i]) return r; s = PyString_FromString(&obj->%(name)s[i]); if (s == NULL || PyList_Append(r, s) < 0) { Py_DECREF(r); return NULL; } i += PyString_Size(s) + 1; } return r;'''%dict(name=d.name) elif isinstance(d, message.MaskRead): print 'return PyInt_FromLong(obj->mask);' elif isinstance(d, SimpleDataItem): print 'return', getset_simple(d, 'obj->%s'%(d.name,))+';' else: raise Exception, d def indent(text): return '\t' + '\n\t'.join(text.split('\n')) def getset_func_get_name(t, d): return '%s_%s_get'%(t.__name__, d.name) def getset_set_simple(d, v): if isinstance(d, (StructDataItem, ScaledDataItem)) \ or (isinstance(d, ConditionalDataItem) and not isinstance(d.default, CONST)): t = typeof(d).ctype.crep conv, err = {'float':('PyFloat_AsDouble', '-1.0'), 'long':('PyInt_AsLong', '-1')}[t] return '''%s newval; newval = %s(value); if (newval == %s && PyErr_Occurred()) return -1; obj->%s = newval; return 0;'''%(t,conv,err,v) elif isinstance(d, ConditionalDataItem): if d.defNone: t = typeof(d).ctype.crep conv, err = {'float':('PyFloat_AsDouble', '-1.0'), 'long':('PyInt_AsLong', '-1')}[t] return '''%s newval; if (value == Py_None) { obj->mask &=~ %s; return 0; } newval = %s(value); if (newval == %s && PyErr_Occurred()) return -1; obj->mask |= %s; obj->%s = newval; return 0;'''%(t,d.bit,conv,err,d.bit,v) else: t = typeof(d).ctype.crep conv, err = {'float':('PyFloat_AsDouble', '-1.0'), 'long':('PyInt_AsLong', '-1')}[t] return '''%s newval; newval = %s(value); if (newval == %s && PyErr_Occurred()) return -1; if (newval == %s) obj->mask &=~ %s; else obj->mask |= %s; obj->%s = newval; return 0;'''%(t, conv, err, d.default.c, d.bit, d.bit, v) else: return '''PyErr_SetString(PyExc_ValueError, "urk"); return -1;''' @return_output def getset_set(d): if isinstance(d, RepeatedDataItem): pyvars = ['x%s'%i for i in range(d.mcount)] cvars = ['y%s'%i for i in range(d.mcount)] ctype = typeof(d).ctype.crep conv, err, b = {'float':('PyFloat_AsDouble', '-1.0', '0.0'), 'long':('PyInt_AsLong', '-1', '0')}[ctype] print '''PyObject %s; %s %s; if (!PyTuple_Check(value)) { PyErr_SetString(PyExc_TypeError, "a tuple is required"); return -1; } if (PyTuple_Size(value) != %s) { PyErr_SetString(PyExc_TypeError, "a tuple is of length %s is required"); return -1; } '''%(', '.join(['*'+v for v in pyvars]), ctype, ', '.join([v+'='+b for v in cvars]), d.mcount, d.mcount) i = 0 for d2 in [d] + d.extensions: d2 = d.sub for i in range(i, i+d.count): pyvar = pyvars[i] cvar = cvars[i] if isinstance(d2, ConditionalDataItem) and d2.defNone: print '''%s = PyTuple_GET_ITEM(value, %s); if (%s != Py_None) { %s = %s(%s); if (%s == %s && PyErr_Occurred()) return -1; } '''%(pyvar, i, pyvar, cvar, conv, pyvar, cvar, err) else: print '''%s = PyTuple_GET_ITEM(value, %s); %s = %s(%s); if (%s == %s && PyErr_Occurred()) return -1; '''%(pyvar, i, cvar, conv, pyvar, cvar, err) i += 1 i = 0 for d2 in [d] + d.extensions: d2 = d2.sub for i in range(i, i+d.count): if isinstance(d2, ConditionalDataItem): if d2.defNone: print '''if (%s == Py_None) { obj->mask &=~ %s; } else { obj->mask |= %s; obj->%s[%s] = %s; }'''%(pyvars[i], d2.bit, d2.bit, d.name, i, cvars[i]) else: print '''if (%s == %s) obj->mask &=~ %s; else obj->mask |= %s; obj->%s[%s] = %s; '''%(cvars[i], d2.default.c, d2.bit, d2.bit, d.name, i, cvars[i]) else: print 'obj->%s[%s] = %s;'%(d.name, i, cvars[i]) i += 1 print '''return 0;''' elif isinstance(d, STRING): print '''const char *s; char *newp; int len; s = PyString_AsString(value); if (s == NULL) return -1; len = strlen(s); newp = malloc(len+1); if (newp == NULL) { PyErr_NoMemory(); return -1; } strcpy(newp, s); free(obj->%s); obj->%s = newp; return 0;'''%(d.name, d.name) elif isinstance(d, STRINGLIST): print '''char **s; char *newp, *p; int nstrings, totlength = 0, i, l; if (!PyList_Check(value)) return -1; nstrings = PyList_Size(value); s = malloc(nstrings*sizeof(char*)); if (s == NULL) { PyErr_NoMemory(); return -1; } for (i = 0; i < nstrings; i++) { s[i] = PyString_AsString(PyList_GET_ITEM(value, i)); if (s[i] == NULL) { free(s); return -1; } l = strlen(s[i]); totlength += l + 1; } newp = malloc(totlength + 1); if (newp == NULL) { PyErr_NoMemory(); free(s); return -1; } p = newp; for (i = 0; i < nstrings; i++) { strcpy(p, s[i]); p += strlen(s[i]) + 1; } *p = \'\\0\'; free(s); free(obj->%s); obj->%s = newp; return 0;'''%(d.name, d.name) elif isinstance(d, SimpleDataItem): print getset_set_simple(d, d.name) else: print '''PyErr_SetString(PyExc_ValueError, "urk"); return -1;''' def getset_func_set_name(t, d): return '%s_%s_set'%(t.__name__, d.name) getset_func_get = ''' static PyObject* %s(msg_%s *obj, void* context) { %s } ''' getset_func_set = ''' static int %s(msg_%s *obj, PyObject *value, void* context) { %s } ''' @return_output def make_getset_funcs(t, d): print getset_func_get%(getset_func_get_name(t, d), t.__name__, indent(getset_get(d))) if d.name not in ['opcode', 'mask']: s = getset_func_set%(getset_func_set_name(t, d), t.__name__, indent(getset_set(d))) assert 'return NULL' not in s, s print s @return_output def length_di(d): if isinstance(d, StructDataItem): print 'length += %s;'%(d.width,) elif isinstance(d, ScaledDataItem): print length_di(d.sub) elif isinstance(d, ConditionalDataItem): yes = length_di(d.sub) no = length_di(d.default) if no == 'length += 0;': if yes.startswith('length +=') and '\n' not in yes: print 'if (self->mask & %s) '%(d.bit,) + yes else: print 'if (self->mask & %s) {'%(d.bit,) print indent(yes) print '}' else: print 'if (self->mask & %s) {'%(d.bit,) print indent(yes) print '}' print 'else {' print indent(no) print '}' elif isinstance(d, CONST): print 'length += %s;'%(d.width,) elif isinstance(d, RepeatedDataItem): if d.count != 1: print 'length += %s;'%(d.sub.width*d.count,) else: print length_di(d.sub) elif isinstance(d, Extend): print length_di(d.sub) elif isinstance(d, STRING): print 'length += strlen(self->%s) + 1;'%(d.name,) elif isinstance(d, STRINGLIST): print '''\ { int i = 0, j = 0; do { i = 0; while (i < 255 && self->%s[j + i]) i++; j += i + 1; } while (self->%s[j]); length += j + 1; }'''%(d.name, d.name) elif isinstance(d, message.MaskRead): print 'if (self->mask & 0xFF00) length += 1;' else: raise Exception, d @return_output def write_di_struct(d, v): if isinstance(d, ScaledDataItem): print write_di_struct(d.sub, '%s/%s'%(v, d.scale)) elif d.code == 'mask & %s) {'%(d.bit,) print indent(yes) print '}' if not isinstance(d.default, CONST): print 'else {' print indent(write_di_struct(d.default, v)) print '}' elif isinstance(d, RepeatedDataItem): for i in range(d.start, d.start + d.count): print write_di(d.sub, '%s[%s]'%(v, i)) elif isinstance(d, Extend): print write_di(d.sub, v) elif isinstance(d, STRING): print 'p = write_string(p, self->%s);'%d.name elif isinstance(d, STRINGLIST): print 'p = write_stringlist(p, self->%s);'%d.name elif isinstance(d, message.MaskRead): print '*(p-1) = 0x80 | (self->mask & 0x7E);' print 'if (self->mask & 0xFF00) {' print ' p = write_byte(p, (self->mask & 0xFF00)>>8);' print '}' else: raise Exception, d serialize_body_tmpl = '''\ %(lengthdecl)s PyObject *result; char *p; %(lencode)s result = PyString_FromStringAndSize(NULL, %(length)s); if (result == NULL) return NULL; p = PyString_AS_STRING(result); %(writecode)s #if DEBUGGING if (PyString_AsString(result) + %(length)s != p) printf("*** %%s -- %%d\\n", self->ob_type->tp_name, PyString_AsString(result) + %(length)s - p); #endif return result;''' def serialize_body(t): if t is TempEntity: length = 'length' lencode = tempentitycode.serializebodylencode elif t.fixedwidth: length = str(t.width) lencode = '' else: length = 'length' lencode = [] for n, d in t.layout: lencode.append(length_di(d)) newlencode = [] count = 0 for part in lencode: if part.startswith('length += ') and '\n' not in part \ and 'strlen' not in part: n = int(part.split()[-1][:-1]) count += n else: newlencode.append(part) if count: newlencode.insert(0, 'length = %s;'%count) lencode = indent('\n'.join(newlencode)) if t is TempEntity: writecode = tempentitycode.serializebodywritecode else: writecode = [] for n, d in t.layout: writecode.append(write_di(d, 'self->%s'%d.name)) writecode = indent('\n'.join(writecode)) if lencode: lencode = '\n' + lencode + '\n' if length == 'length': lengthdecl = 'int length;\n' else: lengthdecl = '' return serialize_body_tmpl%dict(lencode=lencode, writecode=writecode, length=length, lengthdecl=lengthdecl) @return_output def typeobject(t): ds = t.dataitems if t is TempEntity: ds = [BYTE(), LONG(), LONG(), COORD()*3, COORD()*3, BYTE(), BYTE()] names = ['opcode', 'entitytype', 'entity', 'origin', 'trace_endpos', 'range', 'color'] for n, d in zip(names, ds): d.name = n # getsets for d in ds: print make_getset_funcs(t, d) print 'static PyGetSetDef %s_getsets[] = {'%(t.__name__,) for d in ds: if d.name not in ['opcode', 'mask']: print '\t{"%s", (getter)%s, (setter)%s, "", NULL},'%( d.name, getset_func_get_name(t, d), getset_func_set_name(t, d)) else: print '\t{"%s", (getter)%s, NULL, "", NULL},'%( d.name, getset_func_get_name(t, d)) print '\t{NULL, NULL}' print '};' # methods print ''' static PyObject* %s_serialize(msg_%s* self, PyObject* noarg) { %s } '''%(t.__name__, t.__name__, serialize_body(t)) print 'static PyMethodDef %s_methods[] = {'%(t.__name__,) print ' {"serialize", (PyCFunction)%s_serialize, METH_NOARGS, ""},'%(t.__name__,) print '''\ {NULL, NULL} }; ''' # type methods print ''' static void del_%s(msg_%s* msg) {'''%(t.__name__, t.__name__) for d in t.dataitems: if isinstance(d, (STRING, STRINGLIST)): print '\tfree(msg->%s);'%(d.name,) print '''\tPyObject_Del(msg); }''' if ds[1:]: print ''' static PyObject* repr_%s(msg_%s* msg) { PyObject* l; PyObject* t; PyObject* s1; PyObject* v; PyObject* w; l = PyList_New(0); t = PyTuple_New(1); '''%(t.__name__, t.__name__) for d in ds[1:]: print '''\ w = PyObject_GetAttrString((PyObject*)msg, "%s"); if (w == NULL) { goto out2; } PyTuple_SetItem(t, 0, w); s1 = PyString_FromString("%s=%%r"); if (s1 == NULL) { goto out2; } v = PyString_Format(s1, t); if (v == NULL) { goto out3; } if (PyList_Append(l, v) < 0) { goto out4; } Py_DECREF(v); Py_DECREF(s1);'''%(d.name, d.name) print print ''' Py_DECREF(t); v = PyString_FromString(", "); if (v == NULL) { Py_DECREF(l); return NULL; } w = _PyString_Join(v, l); Py_DECREF(v); Py_DECREF(l); if (w == NULL) { return NULL; } v = PyString_FromFormat("%s(%%s)", PyString_AS_STRING(w)); Py_DECREF(w); return v; out4: Py_DECREF(v); out3: Py_DECREF(s1); out2: Py_DECREF(l); Py_DECREF(t); return NULL; }'''%(t.__name__,) else: print ''' static PyObject* repr_%s(msg_%s* msg) { return PyString_FromString("%s()"); } '''%(t.__name__, t.__name__, t.__name__) # and finally, the type object print typeobj_tmpl%dict(name=t.__name__) def read_code_dead_simple(d): if isinstance(d, StructDataItem): if d.code == 'mask & 0x%x) {'%d.bit print indent(read_code_simple(place, d.sub)) print '}' print 'else {' print indent(read_code_simple(place, d.default)) print '}' elif isinstance(d, ScaledDataItem): print read_code_simple(place, d.sub) print place + ' *= ' + repr(d.scale) + ';' else: print '%s = %s;'%(place, read_code_dead_simple(d)) @return_output def read_code_d(d): print '/* %s */'%(d.name,) if isinstance(d, STRINGLIST): print 'r->%s = read_stringlist(block);'%(d.name,) elif isinstance(d, message.MaskRead): print '''r->mask = r->opcode&0x7F; if (r->mask & 0x1) { int m0; m0 = read_byte(block)&0xFF; r->mask |= m0 << 8; }''' elif isinstance(d, SimpleDataItem): print read_code_simple('r->%s'%(d.name,), d) elif isinstance(d, Extend): print read_code_simple('r->%s'%(d.name,), d.sub) else: raise Exception print @return_output def read_code(t): print reader_head%{'name':t.__name__} if t is TempEntity: print indent(tempentitycode.readcode) else: for n, d in t.layout: print indent(read_code_d(d)) if t is message.Time: print indent('block->blocktime = r->time;') print reader_tail reader_head = ''' static PyObject* read_%(name)s(dem_block *block) { msg_%(name)s* r; r = PyObject_New(msg_%(name)s, &typeobj_%(name)s); if (r == NULL) return NULL; ''' reader_tail = '''\ return (PyObject*)r; } ''' def do_type(t): structcode.append(struct(t)) typeobjcode.append(typeobject(t)) readercode.append(read_code(t)) sourcecode_tmpl='''\ #include #define DEBUGGING 0 typedef struct dem_block { PyObject_HEAD int size; int offset; float angles[3]; float blocktime; int error; unsigned char* data; } dem_block; static unsigned char read_byte(dem_block* block) { unsigned char r = 0; if (!block->error && block->offset < block->size + 1) { r = block->data[block->offset]; block->offset++; } else { block->error = 1; } return r; } static short read_short(dem_block* block) { short r = 0; if (!block->error && block->offset < block->size + 2) { r = block->data[block->offset]; r |= block->data[block->offset + 1] << 8; block->offset += 2; } else { block->error = 1; } return r; } static long read_long(dem_block* block) { long r = 0; if (!block->error && block->offset < block->size + 2) { r = block->data[block->offset]; r |= block->data[block->offset + 1] << 8; r |= block->data[block->offset + 2] << 16; r |= block->data[block->offset + 3] << 24; block->offset += 4; } else { block->error = 1; } return r; } static float read_float(dem_block* block) { long l = read_long(block); return *(float*)&l; } static char* read_string(dem_block* block) { int i = 0; char* r; while (i < 0x7FF && block->data[block->offset + i]) { i++; if (block->offset + i >= block->size) { block->error = 1; return NULL; } } r = malloc(i+1); if (!r) { PyErr_NoMemory(); block->error = 1; return NULL; } memcpy(r, &block->data[block->offset], i+1); block->offset += i + 1; return r; } static char* read_stringlist(dem_block* block) { int i = 0, j = 0; char* r; do { i = 0; while (i < 255 && block->data[block->offset + j + i]) { i++; if (block->offset + i + j >= block->size) { block->error = 1; return NULL; } } j += i + 1; } while (block->data[block->offset + j]); r = malloc(j+1); if (!r) { PyErr_NoMemory(); block->error = 1; return NULL; } memcpy(r, &block->data[block->offset], j+1); block->offset += j + 1; return r; } static char* write_byte(char* p, long v) { *p++ = v & 0xFF; return p; } static char* write_short(char* p, long v) { *p++ = v & 0xFF; *p++ = (v & 0xFF00) >> 8; return p; } static char* write_long(char* p, long v) { *p++ = v & 0xFF; *p++ = (v & 0xFF00) >> 8; *p++ = (v & 0xFF0000) >> 16; *p++ = (v & 0xFF000000) >> 24; return p; } static char* write_float(char* p, float v) { return write_long(p, *(long*)&v); } static char* write_string(char* p, char* v) { strcpy(p, v); return p + strlen(v) + 1; } static char* write_stringlist(char* p, char* v) { while (*v) { strcpy(p, v); p += strlen(v) + 1; v += strlen(v) + 1; } return p + 1; } %(structs)s %(typeobjects)s %(readers)s static PyTypeObject type_FilteredBlock; typedef struct filtered_block { PyObject_HEAD dem_block* block; long bits1; long bits2; } filtered_block; static PyObject* block_iternext(dem_block* block); static PyObject* fblock_iternext(filtered_block* fblock) { PyObject* r; msg_Nop* m; while (1) { r = block_iternext(fblock->block); if (r == NULL) return NULL; m = (msg_Nop*)r; if (m->opcode < 32) { if (fblock->bits1 & (1<opcode)) return r; else { Py_DECREF(r); continue; } } else if (m->opcode < 34) { if (fblock->bits2 & (1<<(m->opcode-32))) return r; else { Py_DECREF(r); continue; } } else if (m->ob_type == &typeobj_UpdateEntity) { if (fblock->bits2 & (1<<31)) return r; else { Py_DECREF(r); continue; } } } return NULL; } static void fblock_del(filtered_block* fb) { Py_DECREF(fb->block); } static PyTypeObject type_FilteredBlock = { PyObject_HEAD_INIT(NULL) 0, "FilteredBlock", sizeof(filtered_block), 0, (destructor)fblock_del, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, // PyObject_GenericGetAttr, /* tp_getattro */ 0, // PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, // PyObject_SelfIter, /* tp_iter */ (iternextfunc)fblock_iternext, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; static PyObject* block_filtered(dem_block* self, PyObject* codeiter) { PyObject* seq = PySequence_Fast(codeiter, "a sequence is required"); filtered_block* r; int i, l, b; if (seq == NULL) return NULL; r = PyObject_New(filtered_block, &type_FilteredBlock); if (r == NULL) { Py_DECREF(seq); return NULL; } Py_INCREF(self); r->block = self; r->bits1 = 0; r->bits2 = 0; l = PySequence_Fast_GET_SIZE(seq); for (i = 0; i < l; i++) { b = PyInt_AsLong(PySequence_Fast_GET_ITEM(seq, i)); if (b == -1 && PyErr_Occurred()) goto err; if (b < 0 || b > 63) { PyErr_SetString(PyExc_ValueError, ""); goto err; } if (b < 32) r->bits1 |= 1<bits2 |= 1<<(b-32); } Py_DECREF(seq); return (PyObject*)r; err: Py_DECREF(seq); Py_DECREF(r); return NULL; } static PyMethodDef block_methods[] = { {"filtered", (PyCFunction)block_filtered, METH_O, ""}, {NULL, NULL} }; static PyObject* block_angles_get(PyObject* self, void* context) { dem_block* block = (dem_block*)self; return Py_BuildValue("(fff)", block->angles[0], block->angles[1], block->angles[2]); } static PyObject* block_blocktime_get(PyObject* self, void* context) { dem_block* block = (dem_block*)self; return Py_BuildValue("f", block->blocktime); } static PyGetSetDef block_getsets[] = { {"angles", block_angles_get, NULL, "angles"}, {"blocktime", block_blocktime_get, NULL, "blocktime"}, {NULL, NULL} }; %(block_iternext)s static PyTypeObject type_Block; static PyObject * block_new(PyTypeObject *type, PyObject *args, PyObject *kw) { dem_block *obj; char *s; int len; if (!PyArg_ParseTuple(args, "s#", &s, &len)) return NULL; obj = PyObject_New(dem_block, &type_Block); if (obj == NULL) return NULL; obj->size = len; obj->offset = 0; obj->blocktime = -1.0f; obj->data = malloc(len); obj->error = 0; memcpy(obj->data, s, len); obj->angles[0] = read_float(obj); obj->angles[1] = read_float(obj); obj->angles[2] = read_float(obj); return (PyObject *) obj; } static void block_del(dem_block* block) { free(block->data); PyObject_Del(block); } static PyTypeObject type_Block = { PyObject_HEAD_INIT(NULL) 0, "Block", sizeof(dem_block), 0, (destructor)block_del, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, // PyObject_GenericGetAttr, /* tp_getattro */ 0, // PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, // PyObject_SelfIter, /* tp_iter */ (iternextfunc)block_iternext, /* tp_iternext */ block_methods, /* tp_methods */ 0, /* tp_members */ block_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ block_new, /* tp_new */ }; %(initfunc)s ''' initfunc = ''' PyMODINIT_FUNC initdemparse(void) { PyObject *m, *d; m = Py_InitModule("demparse", NULL); d = PyModule_GetDict(m); if (PyType_Ready(&type_Block) < 0) return; type_Block.tp_getattro = PyObject_GenericGetAttr; type_Block.tp_setattro = PyObject_GenericSetAttr; type_Block.tp_iter = PyObject_SelfIter; if (PyType_Ready(&type_FilteredBlock) < 0) return; type_FilteredBlock.tp_getattro = PyObject_GenericGetAttr; type_FilteredBlock.tp_setattro = PyObject_GenericSetAttr; type_FilteredBlock.tp_iter = PyObject_SelfIter; if (PyDict_SetItemString(d, "Block", (PyObject*)&type_Block) < 0) return ; %s } ''' block_iternext_tmpl = ''' static PyObject* block_iternext(dem_block* block) { PyObject *r; int oo; if (block->error || block->offset >= block->size) return NULL; oo = block->offset; switch (block->data[block->offset]) { %(cases)s default: if (block->data[block->offset] >= 0x80) r = read_UpdateEntity(block); else { PyErr_Format(PyExc_ValueError, "corrupt data - %%d", (int)block->data[block->offset]); return NULL; } break; } if (r == NULL) return NULL; if (block->error || block->offset > block->size) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_ValueError, "corrupt data"); Py_DECREF(r); return NULL; } #if DEBUGGING { PyObject* s = PyObject_CallMethod(r, "serialize", ""); int d = (block->offset - oo) - (int)PyString_Size(s); if (d) printf("- %%s %%d -\\n", r->ob_type->tp_name, d); Py_DECREF(s); } #endif return r; }''' def driver(classes): t = '''\tcase %s: r = read_%s(block); break; ''' cases = [] for c in classes: cases.append(t%(c.code, c.__name__)) return block_iternext_tmpl%dict(cases='\n'.join(cases)) @return_output def make_initfunc(classes): @return_output def _(): for c in classes: print ''' if (PyType_Ready(&typeobj_%s) < 0) return; typeobj_%s.tp_getattro = PyObject_GenericGetAttr; typeobj_%s.tp_setattro = PyObject_GenericSetAttr;'''%(c.__name__, c.__name__, c.__name__) print for c in classes: print '''\ if (PyDict_SetItemString(typeobj_%s.tp_dict, "code", PyInt_FromLong(%s)) < 0) return;'''%(c.__name__, getattr(c, 'code', 63)) print for c in classes: print ''' if (PyDict_SetItemString(d, "%s", (PyObject*)&typeobj_%s) < 0) return;'''%(c.__name__, c.__name__) print initfunc%_() def main(): from message import Message, TempEntity cs = Message.__subclasses__() cs.sort(key=lambda x:getattr(x, 'code', 1000)) # cs.remove(TempEntity) structcode = [] typecode = [] readcode = [] for c in cs: structcode.append(struct(c)) typecode.append(typeobject(c)) readcode.append(read_code(c)) print sourcecode_tmpl%dict(structs='\n'.join(structcode), typeobjects='\n'.join(typecode), readers='\n'.join(readcode), block_iternext=driver(cs[:-1]), initfunc=make_initfunc(cs)) if __name__ == '__main__': sys.stdout = open('demparse.c', 'w') main()