/*
* Twisted, the Framework of Your Internet
* Copyright (C) 2001-2002 Matthew W. Lefkowitz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* cBanana.c */
#ifdef WIN32
# include <windows.h>
# define EXTERN_API __declspec(dllexport)
# define snprintf _snprintf
#else
# define EXTERN_API
#endif
#ifdef __GNUC__
# define TM_INLINE inline
#else
# define TM_INLINE /* */
#endif
#include <Python.h>
/* Python module initialization */
PyObject* cBanana_module;
PyObject* cBanana_dict;
/* Python accessible */
/* Initialization */
EXTERN_API void initcBanana(void);
/* Encoding */
extern EXTERN_API PyObject *cBanana_encode( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBanana_dataReceived( PyObject *self, PyObject *args );
/* State Object */
extern EXTERN_API PyObject *cBananaState_new( PyObject *self, PyObject *args );
extern EXTERN_API void cBananaState_dealloc(PyObject* self);
/* Buffer Object */
extern EXTERN_API PyObject *cBananaBuf_new( PyObject *self, PyObject *args );
extern EXTERN_API void cBananaBuf_dealloc(PyObject* self);
extern EXTERN_API PyObject *cBananaBuf_getattr(PyObject* self, char* attrname);
extern EXTERN_API PyObject *cBananaBuf_write( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBananaBuf_get( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBananaBuf_clear( PyObject *self, PyObject *args );
/* function table passed into Python by initcBanana() */
static PyMethodDef cBanana__methods__[] =
{
{ "dataReceived", cBanana_dataReceived, METH_VARARGS },
{ "encode", cBanana_encode, METH_VARARGS },
{ "newState", cBananaState_new, METH_VARARGS },
{ "newBuf", cBananaBuf_new, METH_VARARGS },
{ NULL, NULL } /* Sentinel */
};
static PyMethodDef cBananaBuf__methods__[] =
{
{ "write", cBananaBuf_write, METH_VARARGS },
{ "clear", cBananaBuf_clear, METH_VARARGS },
{ "get", cBananaBuf_get, METH_VARARGS },
{ NULL, NULL } /* Sentinel */
};
static PyObject *BananaError;
#define HIGH_BIT_SET 0x80
#define LIST 0x80
#define INT 0x81
#define STRING 0x82
#define NEG 0x83
#define FLOAT 0x84
#define LONGINT 0x85
#define LONGNEG 0x86
#define VOCAB 0x87
#define NUM_VOCABS 31
struct listItem
{
struct listItem *lastList;
PyObject *thisList;
int currentIndex;
int size;
};
/*
* This struct represents state that's carried between calls.
*/
typedef struct {
PyObject_HEAD
struct listItem *currentList;
} cBananaState;
static PyTypeObject cBananaStateType = {
PyObject_HEAD_INIT(NULL)
0,
"cBananaState",
sizeof(cBananaState),
0,
cBananaState_dealloc, /* dealloc */
0, /* print */
0, /* getattr */
0, /* setattr */
0, /* compare */
0, /* repr */
0, /* as_number */
0, /* as_sequence */
0, /* as_mapping */
0, /* hash */
};
typedef struct {
PyObject_HEAD
char* contents;
unsigned int available;
unsigned int size;
} cBananaBuf;
static PyTypeObject cBananaBufType = {
PyObject_HEAD_INIT(NULL)
0,
"cBananaBuf",
sizeof(cBananaBuf),
0,
cBananaBuf_dealloc, /* dealloc */
0, /* print */
cBananaBuf_getattr, /* getattr */
0, /* setattr */
0, /* compare */
0, /* repr */
0, /* as_number */
0, /* as_sequence */
0, /* as_mapping */
0, /* hash */
0, /* call */
};
#define INITIAL_BUF_SZ 1024
extern EXTERN_API PyObject*
cBananaBuf_new(PyObject *self, PyObject *args) {
cBananaBuf* buf;
if (!PyArg_ParseTuple(args, ":newState")){
return NULL;
}
buf = PyObject_New(cBananaBuf, &cBananaBufType);
buf->contents = malloc(INITIAL_BUF_SZ);
buf->size = INITIAL_BUF_SZ;
buf->available = INITIAL_BUF_SZ;
return (PyObject*) buf;
}
extern EXTERN_API void
cBananaBuf_dealloc(PyObject *self) {
cBananaBuf* buf;
buf = (cBananaBuf*) self;
if (buf->contents) {
free(buf->contents);
}
buf->contents = 0;
buf->available = 0;
buf->size = 0;
PyObject_Del(self);
}
extern EXTERN_API PyObject*
cBananaBuf_getattr(PyObject *self, char* attrname) {
return Py_FindMethod(cBananaBuf__methods__, self, attrname);
}
static void cBananaBuf_write_internal(cBananaBuf* me, const char* src, unsigned int len) {
unsigned int index;
while (len > (me -> available)) {
unsigned int newsize;
newsize = me->size * 2;
me->contents = realloc(me->contents, newsize);
me->available += me->size;
me->size = newsize;
}
index = me->size - me->available;
memcpy((me->contents)+index, src, len);
me->available -= len;
}
#define cBananaBuf_append_byte(me, byte) \
do { \
if (me->available >= 1) { \
me->contents[me->size - me->available] = byte; \
me->available--; \
} else { \
cBananaBuf_write_internal(me, &byte, 1); \
} \
} while (0)
extern EXTERN_API PyObject*
cBananaBuf_write(PyObject *self, PyObject *args) {
cBananaBuf* me;
char* src;
int len;
me = (cBananaBuf*) self;
if (!PyArg_ParseTuple(args, "s#:write", &src, &len)) {
return NULL;
}
cBananaBuf_write_internal(me, src, len);
Py_INCREF(Py_None);
return Py_None;
}
static void cBananaBuf_clear_internal(cBananaBuf* me) {
me->available = me->size;
}
extern EXTERN_API PyObject*
cBananaBuf_clear(PyObject *self, PyObject *args) {
cBananaBuf* me;
me = (cBananaBuf*) self;
if (!PyArg_ParseTuple(args, ":clear")) {
return NULL;
}
cBananaBuf_clear_internal(me);
Py_INCREF(Py_None);
return Py_None;
}
extern EXTERN_API PyObject*
cBananaBuf_get(PyObject *self, PyObject *args) {
cBananaBuf* me;
me = (cBananaBuf*) self;
if (PyArg_ParseTuple(args, ":get")) {
return PyString_FromStringAndSize(me->contents, me->size - me->available);
}
return NULL;
}
extern EXTERN_API PyObject*
cBananaState_new(PyObject *self, PyObject *args) {
cBananaState* state;
if (!PyArg_ParseTuple(args, ":newState")){
return NULL;
}
state = PyObject_New(cBananaState, &cBananaStateType);
state->currentList = NULL;
return (PyObject*) state;
}
extern EXTERN_API void
cBananaState_dealloc(PyObject* self)
{
struct listItem* thatList;
struct listItem* thisList;
thisList = ((cBananaState*)self) -> currentList;
while (thisList) {
thatList = thisList->lastList;
Py_DECREF(thisList->thisList);
free(thisList);
thisList = thatList;
}
PyObject_Del(self);
}
static const char *vocab[] = {
/* Filler so we start at 1 not 0 */
"Dummy", /* 0 */
/* Jelly Data Types */
"None", /* 1 */
"class", /* 2 */
"dereference", /* 3 */
"reference", /* 4 */
"dictionary", /* 5 */
"function",/* 6 */
"instance",/* 7 */
"list", /* 8 */
"module",/* 9 */
"persistent",/* 10 */
"tuple",/* 11 */
"unpersistable",/* 12 */
/* PB Data Types */
"copy",/* 13 */
"cache",/* 14 */
"cached",/* 15 */
"remote",/* 16 */
"local",/* 17 */
"lcache",/* 18 */
/* PB Protocol messages */
"version",/* 19 */
"login",/* 20 */
"password",/* 21 */
"challenge",/* 22 */
"perspective",/* 23 */
"inperspective",/* 24 */
"cachemessage",/* 25 */
"message",/* 26 */
"answer",/* 27 */
"error",/* 28 */
"decref",/* 29 */
"decache",/* 30 */
"uncache"/* 31 */
};
static const char *findVocab(int offset)
{
if (offset < 0 || offset > NUM_VOCABS) {
return NULL;
}
return vocab[offset];
}
static void int2b128(long integer, cBananaBuf* writeobj) {
char typeByte;
if (integer == 0) {
typeByte = 0;
cBananaBuf_append_byte(writeobj, typeByte);
return;
}
while (integer) {
typeByte = (char) integer & 0x7f;
cBananaBuf_append_byte(writeobj, typeByte);
integer >>= 7;
}
}
PyObject* cBanana_encode_internal(PyObject* encodeobj, cBananaBuf* writeobj) {
char typeByte;
if (PyList_Check(encodeobj)) {
int counter;
int2b128(PyList_Size(encodeobj), writeobj);
typeByte = LIST;
cBananaBuf_append_byte(writeobj, typeByte);
for (counter=0; counter < PyList_Size(encodeobj); counter ++) {
if (!cBanana_encode_internal(PyList_GetItem(encodeobj, counter), writeobj)) {
return NULL;
}
}
} else if (PyTuple_Check(encodeobj)) {
int counter;
int2b128(PyTuple_Size(encodeobj), writeobj);
typeByte = LIST;
cBananaBuf_append_byte(writeobj, typeByte);
for (counter=0; counter < PyTuple_Size(encodeobj); counter ++) {
if (!cBanana_encode_internal(PyTuple_GetItem(encodeobj, counter), writeobj)) {
return NULL;
}
}
} else if (PyInt_Check(encodeobj)) {
long integer = PyInt_AsLong(encodeobj);
if (integer >= 0) {
int2b128(integer, writeobj);
typeByte = INT;
cBananaBuf_append_byte(writeobj, typeByte);
} else {
int2b128(-integer, writeobj);
typeByte = NEG;
cBananaBuf_append_byte(writeobj, typeByte);
}
} else if (PyLong_Check(encodeobj)) {
PyObject* result;
PyObject* argtup;
argtup = PyTuple_New(2);
Py_INCREF(encodeobj);
if (PyObject_Compare(encodeobj, PyLong_FromDouble(0.0)) == -1) {
typeByte = LONGNEG;
PyTuple_SetItem(argtup, 0, PyNumber_Negative(encodeobj));
} else {
typeByte = LONGINT;
PyTuple_SetItem(argtup, 0, encodeobj);
}
/* Py_INCREF(writeobj); */
PyTuple_SetItem(argtup, 1, PyObject_GetAttrString((PyObject*) writeobj, "write"));
result = PyObject_CallObject(PyObject_GetAttrString(cBanana_module, "pyint2b128"), argtup);
Py_DECREF(argtup);
if (!result) {
return NULL;
}
Py_DECREF(result);
cBananaBuf_append_byte(writeobj, typeByte);
} else if (PyFloat_Check(encodeobj)) {
double x;
int s;
int e;
double f;
long fhi, flo;
char floatbuf[8];
x = PyFloat_AS_DOUBLE(encodeobj);
if (x < 0) {
s = 1;
x = -x;
}
else
s = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
}
else if (f == 0.0) {
e = 0;
}
else {
PyErr_SetString(PyExc_SystemError,
"frexp() result out of range");
return NULL;
}
if (e >= 1024) {
/* XXX 1024 itself is reserved for Inf/NaN */
PyErr_SetString(PyExc_OverflowError,
"float too large to pack with d format");
return NULL;
}
else if (e < -1022) {
/* Gradual underflow */
f = ldexp(f, 1022 + e);
e = 0;
}
else if (!(e == 0 && f == 0.0)) {
e += 1023;
f -= 1.0; /* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f *= 268435456.0; /* 2**28 */
fhi = (long) floor(f); /* Truncate */
f -= (double)fhi;
f *= 16777216.0; /* 2**24 */
flo = (long) floor(f + 0.5); /* Round */
/* This is hard-coded to be encoded big-endian */
floatbuf[0] = (s<<7) | (e>>4);
floatbuf[1] = (char) (((e&0xF)<<4) | (fhi>>24));
floatbuf[2] = (fhi>>16) & 0xFF;
floatbuf[3] = (fhi>>8) & 0xFF;
floatbuf[4] = fhi & 0xFF;
floatbuf[5] = (flo>>16) & 0xFF;
floatbuf[6] = (flo>>8) & 0xFF;
floatbuf[7] = flo & 0xFF;
typeByte = FLOAT;
cBananaBuf_append_byte(writeobj, typeByte);
/* it's CALLING PYTHON FUNCTIONS FOR FUN AND PROFIT!!! */
cBananaBuf_write_internal(writeobj, floatbuf, sizeof(floatbuf));
} else if (PyString_Check(encodeobj)) {
int len;
char* src;
PyString_AsStringAndSize(encodeobj, &src, &len);
int2b128(len, writeobj);
typeByte = STRING;
cBananaBuf_append_byte(writeobj, typeByte);
cBananaBuf_write_internal(writeobj, src, len);
} else {
char errmsg[256];
snprintf(errmsg, 256, "Unknown Python Type: %s", encodeobj->ob_type->tp_name);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
extern EXTERN_API
PyObject* cBanana_encode(PyObject* self, PyObject *args) {
PyObject* encodeobj;
PyObject* writeobj;
if (!PyArg_ParseTuple(args, "OO", &encodeobj, &writeobj)) {
return NULL;
}
if (writeobj->ob_type != &cBananaBufType) {
PyErr_SetString(BananaError, "Encoding only accepts BananaBufs");
return NULL;
}
return cBanana_encode_internal(encodeobj, (cBananaBuf*) writeobj);
}
/* TODO: change the API to return a failure if the encoded value won't fit.
Current implementation just folds oversized values. */
static long b1282int(unsigned char *str, int begin, int end) {
long result = 0;
long place = 0;
int count;
for (count=begin; count < end; count++) {
unsigned char num = str[count];
if (place) {
result = result + (num << (7 * place)); /* (num * (128 ^ place)); */
} else {
result = result + num;
}
place++;
}
return result;
}
/**************
** invokes the python callback if required
** Arguments:
** "object" argument must be a new reference -- I steal a reference to it.
**************/
static TM_INLINE int gotPythonItem(PyObject *object, struct listItem *currentList, PyObject *expressionReceived)
{
if (currentList) {
PyList_SET_ITEM(currentList->thisList, currentList->currentIndex, object);
currentList->currentIndex++;
return 1;
}
else {
PyObject *result;
PyObject *args;
args = PyTuple_New(1);
PyTuple_SetItem(args, 0, object);
result = PyObject_CallObject(expressionReceived, args);
if (result) {
Py_DECREF(result);
}
Py_DECREF(args);
return (int) result;
}
}
/**************
** Helper function to add a float
**************/
static TM_INLINE int gotItemFloat(double value, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object = PyFloat_FromDouble(value);
return gotPythonItem(object, currentList, expressionReceived);
}
/**************
** Helper function to add an int
**************/
static TM_INLINE int gotItemInt(int value, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object = PyInt_FromLong(value) ;
return gotPythonItem(object, currentList, expressionReceived);
}
/**************
** Helper function to add a string
**************/
static TM_INLINE int gotItemString(const char *value, int len, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object;
object = PyString_FromStringAndSize(value, len);
return gotPythonItem(object, currentList, expressionReceived);
}
/**************
** Helper function to add a list
**************/
static TM_INLINE int gotItemList(PyObject *listObject, struct listItem *currentList, PyObject *expressionReceived)
{
return gotPythonItem(listObject, currentList, expressionReceived);
}
/****************************************
** cBanana_dataReceived
**
**
** Inputs:
** newChunk - the new data to decode
** expressionReceived - the python callable to invoke for each expression
**
** Output:
** number of bytes processed
*****************************************/
extern EXTERN_API PyObject *cBanana_dataReceived( PyObject *self, PyObject *args )
{
PyObject *newChunk; /* pointer to new chunk */
PyObject *expressionReceived; /* callback */
PyObject *stateobj; /* state object */
cBananaState *state; /* state */
unsigned char *buffer; /* buffer to work from */
char **bufptr; /* for python funcs that want *buffer */
int bufferSize; /* size of the remaining portion */
int pos;
int nBeginPos;
int nEndPos;
unsigned char typeByte;
bufptr = (char**) &buffer;
if( !PyArg_ParseTuple( args, "OOO", &stateobj, &newChunk, &expressionReceived) )
return NULL;
if (!PyCallable_Check(expressionReceived) ) {
/* ERROR - must be a callback we can use */
Py_INCREF(Py_None);
return Py_None;
}
if (!PyString_Check(newChunk)) {
printf("Second arg was not a string\n");
Py_INCREF(Py_None);
return Py_None;
}
if ((stateobj == NULL) || ((stateobj->ob_type) != (&cBananaStateType))) {
printf("state object wasn't\n");
Py_INCREF(Py_None);
return Py_None;
}
state = (cBananaState*) stateobj;
PyString_AsStringAndSize(newChunk, bufptr, &bufferSize);
pos = 0;
while (pos < bufferSize) {
/* printf("beginning at %d\n", pos); */
nBeginPos = pos; /* beginning of number, also, 'consumed so far' */
while (buffer[pos] < HIGH_BIT_SET) {
/* printf("Got character %c (%d) at %d\n", current[pos], current[pos], pos ); */
pos++;
if ((pos-nBeginPos) > 64) {
/* ERROR: "Security precaution: more than 64 bytes of prefix" */
PyErr_SetString(PyExc_SystemError,
"Security precaution: more than 64 bytes of prefix (this should raise an exception).\n");
return NULL;
} else if (pos == bufferSize) {
/* boundary condition -- not enough bytes to finish the number */
return PyInt_FromLong(nBeginPos);
}
}
/* extract the type byte */
nEndPos = pos;
typeByte = buffer[pos];
pos++;
switch (typeByte) {
case LIST: {
int num = b1282int(buffer, nBeginPos, nEndPos);
if (num > 640*1024) {
PyErr_SetString(BananaError,
"Security precaution: List too long.\n");
return NULL;
}
if (!state->currentList) {
state->currentList = (struct listItem *)malloc(sizeof(struct listItem));
if (!state->currentList)
return PyErr_NoMemory();
state->currentList->lastList = NULL;
state->currentList->currentIndex = 0;
state->currentList->size = num;
state->currentList->thisList = PyList_New(num);
if (!state->currentList->thisList) {
/* PyList_New sets PyErr_NoMemory for us */
free(state->currentList); state->currentList = NULL;
return NULL;
}
} else {
struct listItem *newList = (struct listItem *) malloc(sizeof(struct listItem));
if (!newList)
return PyErr_NoMemory();
newList->size = num;
newList->thisList = PyList_New(num);
if (!newList->thisList) {
free(newList);
return NULL;
}
newList->currentIndex = 0;
newList->lastList = state->currentList;
state->currentList = newList;
}
}
break;
case INT: {
int num = b1282int(buffer, nBeginPos, nEndPos);
if (!gotItemInt(num, state->currentList, expressionReceived)){
return NULL;
}
}
break;
case NEG: {
int num = -b1282int(buffer, nBeginPos, nEndPos);
if (!gotItemInt(num, state->currentList, expressionReceived)){
return NULL;
}
}
break;
case LONGINT: {
PyObject* argtup;
PyObject* rval;
PyObject* pyb1282int;
argtup = PyTuple_New(1);
PyTuple_SetItem(argtup, 0,
PyString_FromStringAndSize(buffer + nBeginPos,
nEndPos - nBeginPos));
pyb1282int = PyObject_GetAttrString(cBanana_module, "pyb1282int");
if (!pyb1282int) { return NULL; }
rval = PyObject_CallObject(pyb1282int, argtup);
Py_DECREF(argtup);
Py_DECREF(pyb1282int);
if (!rval) { return NULL; }
if (!gotPythonItem(rval, state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case LONGNEG: {
PyObject* argtup;
PyObject* rval;
PyObject* negval;
PyObject* pyb1282int;
argtup = PyTuple_New(1);
PyTuple_SetItem(argtup, 0,
PyString_FromStringAndSize(buffer + nBeginPos,
nEndPos - nBeginPos));
pyb1282int = PyObject_GetAttrString(cBanana_module, "pyb1282int");
if (!pyb1282int) { return NULL; }
rval = PyObject_CallObject(pyb1282int, argtup);
Py_DECREF(argtup);
Py_DECREF(pyb1282int);
if (!rval) {
return NULL;
}
negval = PyNumber_Negative(rval);
if (!negval) {
return NULL;
}
Py_DECREF(rval);
if (!gotPythonItem(negval, state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case STRING: {
int len = b1282int(buffer, nBeginPos, nEndPos);
if (len > 640 * 1024) {
PyErr_SetString(BananaError,
"Security precaution: String too long.\n");
return NULL;
}
if (len > (bufferSize - pos) ) {
/* boundary condition; not enough bytes to complete string */
return PyInt_FromLong(nBeginPos);
}
if (!gotItemString(buffer+pos, len, state->currentList, expressionReceived)) {
return NULL;
}
pos += len;
}
break;
case VOCAB: {
int num = b1282int(buffer, nBeginPos, nEndPos);
const char *vocabString = findVocab(num);
if (vocabString == NULL) {
char errmsg[256];
snprintf(errmsg, 256, "Vocab String Not Found: %d", num);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
if (!gotItemString(vocabString, strlen(vocabString),
state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case FLOAT: {
double num;
/* the following snippet thanks to structmodule.c */
/* new moon tonight. be careful! */
int sign_bit;
int exponent;
long fhi, flo;
char* p;
if (8 > (bufferSize - pos) ) {
/* printf("\nWARNING: buffer size %d pos %d\n", bufferSize, pos); */
/* boundary condition; not enough bytes to complete string */
return PyInt_FromLong(nBeginPos);
}
p = (char*) (buffer + pos);
sign_bit = (*p>>7) & 1; /* First byte */
exponent = (*p & 0x7F) << 4;
p ++;
exponent |= (*p>>4) & 0xF; /* Second byte */
fhi = (*p & 0xF) << 24;
p ++;
fhi |= (*p & 0xFF) << 16; /* Third byte */
p ++;
fhi |= (*p & 0xFF) << 8; /* Fourth byte */
p ++;
fhi |= (*p & 0xFF); /* Fifth byte */
p ++;
flo = (*p & 0xFF) << 16; /* Sixth byte */
p ++;
flo |= (*p & 0xFF) << 8; /* Seventh byte */
p ++;
flo |= (*p & 0xFF); /* Eighth byte */
p ++;
num = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
num /= 268435456.0; /* 2**28 */
/* XXX This sadly ignores Inf/NaN */
if (exponent == 0)
exponent = -1022;
else {
num += 1.0;
exponent -= 1023;
}
num = ldexp(num, exponent);
if (sign_bit)
num = -num;
/* Would you like your posessions identified? */
/* printf("float number: %f\n", num); */
gotItemFloat(num, state->currentList, expressionReceived);
/* doubles are 8 bytes long */
pos += 8;
}
break;
default: {
char errmsg[256];
snprintf(errmsg, 256, "Invalid Type Byte: %hhd", typeByte);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
}
/* If there is a list, check if it is full */
if (state->currentList) {
/* printf("bufferSize: %d listSize: %d\n", PyList_Size(state->currentList->thisList), state->currentList->size); */
while (state->currentList && (state->currentList->currentIndex == state->currentList->size)){
PyObject *list;
struct listItem *tmp;
list = state->currentList->thisList;
tmp = state->currentList->lastList;
free(state->currentList);
state->currentList = tmp;
if (!gotItemList(list, state->currentList, expressionReceived)) {
return NULL;
}
}
}
}
/* printf(full); */
return PyInt_FromLong(pos);
}
/* Do the equivalent of:
* from foo.bar import baz
* where "foo.bar" is 'name' and "baz" is 'from_item'
* Stolen from cReactorUtil.c
*/
static PyObject *util_FromImport(const char *name, const char *from_item)
{
PyObject *from_list;
PyObject *module;
PyObject *item;
/* Make the from list. */
from_list = PyList_New(1);
PyList_SetItem(from_list, 0, PyString_FromString(from_item));
/* Attempt the import, with const correctness removed. */
module = PyImport_ImportModuleEx((char *)name, NULL, NULL, from_list);
Py_DECREF(from_list);
if (!module)
{
return NULL;
}
/* Get the from_item from the module. */
item = PyObject_GetAttrString(module, (char *)from_item);
Py_DECREF(module);
return item;
}
/* module's initialization function for Python */
extern EXTERN_API void initcBanana(void)
{
cBananaStateType.ob_type = &PyType_Type;
cBananaBufType.ob_type = &PyType_Type;
cBanana_module = Py_InitModule("cBanana", cBanana__methods__);
cBanana_dict = PyModule_GetDict(cBanana_module);
BananaError = util_FromImport("twisted.spread.banana", "BananaError");
if (!BananaError) {
PyErr_Print();
/* this means we'll have our own exception type, not shared with
banana.py */
BananaError = PyErr_NewException("BananaError", NULL, NULL);
}
PyDict_SetItemString(cBanana_dict, "BananaError", BananaError);
}
syntax highlighted by Code2HTML, v. 0.9.1