432 lines
12 KiB
C
432 lines
12 KiB
C
/* swi
|
|
|
|
RISC OS swi functions
|
|
|
|
1.00 Chris Stretch
|
|
|
|
|
|
1.01 12 May 1999 Laurence Tratt
|
|
|
|
* Changed swi.error to be a class based exception rather than string based
|
|
* Added swi.ArgError which is generated for errors when the user passes invalid arguments to
|
|
functions etc
|
|
* Added "errnum" attribute to swi.error, so one can now check to see what the error number was
|
|
*/
|
|
|
|
#include "h.os"
|
|
#include "h.kernel"
|
|
#include "Python.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#define PyBlock_Check(op) ((op)->ob_type == &PyBlockType)
|
|
|
|
|
|
static PyObject *SwiError; /* Exception swi.error */
|
|
static PyObject *ArgError; /* Exception swi.ArgError */
|
|
static os_error *e;
|
|
|
|
static PyObject *swi_oserror(void)
|
|
{ PyErr_SetString(SwiError,e->errmess);
|
|
PyObject_SetAttrString(PyErr_Occurred(), "errnum", PyInt_FromLong(e->errnum));
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *swi_error(char *s)
|
|
{ PyErr_SetString(ArgError,s);
|
|
return 0;
|
|
}
|
|
|
|
typedef struct
|
|
{ PyObject_HEAD
|
|
void *block;
|
|
int length; /*length in bytes*/
|
|
int heap;
|
|
} PyBlockObject;
|
|
|
|
static PyTypeObject PyBlockType;
|
|
|
|
/* block commands */
|
|
|
|
static PyObject *PyBlock_New(PyObject *self,PyObject *args)
|
|
{ int size;
|
|
PyBlockObject *b;
|
|
PyObject *init=0;
|
|
if(!PyArg_ParseTuple(args,"i|O",&size,&init)) return NULL;
|
|
if(size<1) size=1;
|
|
b=PyObject_NEW(PyBlockObject,&PyBlockType);
|
|
if(!b) return NULL;
|
|
b->block=malloc(4*size);
|
|
if(!b->block)
|
|
{ Py_DECREF(b);
|
|
return PyErr_NoMemory();
|
|
}
|
|
b->length=4*size;
|
|
b->heap=1;
|
|
if(init)
|
|
{ if(PyString_Check(init))
|
|
{ int n=PyString_Size(init);
|
|
if (n>4*size) n=4*size;
|
|
memcpy(b->block,PyString_AsString(init),n);
|
|
memset((char*)b->block+n,0,4*size-n);
|
|
}
|
|
else
|
|
{ int n,k;
|
|
long *p=(long*)b->block;
|
|
if(!PyList_Check(init)) goto fail;
|
|
n=PyList_Size(init);
|
|
if (n>size) n=size;
|
|
for(k=0;k<n;k++)
|
|
{ PyObject *q=PyList_GetItem(init,k);
|
|
if(!PyInt_Check(q)) goto fail;
|
|
p[k]=PyInt_AsLong(q);
|
|
}
|
|
for(;k<size;k++) p[k]=0;
|
|
}
|
|
}
|
|
return (PyObject *)b;
|
|
fail:PyErr_SetString(PyExc_TypeError,
|
|
"block initialiser must be string or list of integers");
|
|
Py_DECREF(b);
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *PyRegister(PyObject *self,PyObject *args)
|
|
{ int size,ptr;
|
|
PyBlockObject *b;
|
|
if(!PyArg_ParseTuple(args,"ii",&size,&ptr)) return NULL;
|
|
if(size<1) size=1;
|
|
b=PyObject_NEW(PyBlockObject,&PyBlockType);
|
|
if(!b) return NULL;
|
|
b->block=(void*)ptr;
|
|
b->length=4*size;
|
|
b->heap=0;
|
|
return (PyObject *)b;
|
|
}
|
|
|
|
static PyObject *PyBlock_ToString(PyBlockObject *self,PyObject *arg)
|
|
{ int s=0,e=self->length;
|
|
if(!PyArg_ParseTuple(arg,"|ii",&s,&e)) return NULL;
|
|
if(s<0||e>self->length||s>e)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
return PyString_FromStringAndSize((char*)self->block+s,e-s);
|
|
}
|
|
|
|
static PyObject *PyBlock_NullString(PyBlockObject *self,PyObject *arg)
|
|
{ int s=0,e=self->length,i;
|
|
char *p=(char*)self->block;
|
|
if(!PyArg_ParseTuple(arg,"|ii",&s,&e)) return NULL;
|
|
if(s<0||e>self->length||s>e)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
for(i=s;i<e;i++) if(p[i]==0) break;
|
|
return PyString_FromStringAndSize((char*)self->block+s,i-s);
|
|
}
|
|
|
|
static PyObject *PyBlock_CtrlString(PyBlockObject *self,PyObject *arg)
|
|
{ int s=0,e=self->length,i;
|
|
char *p=(char*)self->block;
|
|
if(!PyArg_ParseTuple(arg,"|ii",&s,&e)) return NULL;
|
|
if(s<0||e>self->length||s>e)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
for(i=s;i<e;i++) if(p[i]<32) break;
|
|
return PyString_FromStringAndSize((char*)self->block+s,i-s);
|
|
}
|
|
|
|
static PyObject *PyBlock_PadString(PyBlockObject *self,PyObject *arg)
|
|
{ int s=0,e=self->length,n,m;
|
|
char *str;
|
|
char c;
|
|
char *p=(char*)self->block;
|
|
if(!PyArg_ParseTuple(arg,"s#c|ii",&str,&n,&c,&s,&e)) return NULL;
|
|
if(s<0||e>self->length||s>e)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
m=e-s;
|
|
if(n>m) n=m;
|
|
memcpy(p+s,str,n);memset(p+s+n,c,m-n);
|
|
Py_INCREF(Py_None);return Py_None;
|
|
}
|
|
|
|
static PyObject *PyBlock_BitSet(PyBlockObject *self,PyObject *arg)
|
|
{ int i,x,y;
|
|
int *p=(int*)self->block;
|
|
if(!PyArg_ParseTuple(arg,"iii",&i,&x,&y)) return NULL;
|
|
if(i<0||i>=self->length/4)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
p[i]=(p[i]&y)^x;
|
|
Py_INCREF(Py_None);return Py_None;
|
|
}
|
|
|
|
static PyObject *PyBlock_Resize(PyBlockObject *self,PyObject *arg)
|
|
{ int n;
|
|
if(!PyArg_ParseTuple(arg,"i",&n)) return NULL;
|
|
if(n<1) n=1;
|
|
if(self->heap)
|
|
{ void *v=realloc(self->block,4*n);
|
|
if (!v) return PyErr_NoMemory();
|
|
self->block=v;
|
|
}
|
|
self->length=4*n;
|
|
Py_INCREF(Py_None);return Py_None;
|
|
}
|
|
|
|
static PyObject *PyBlock_ToFile(PyBlockObject *self,PyObject *arg)
|
|
{ int s=0,e=self->length/4;
|
|
PyObject *f;
|
|
FILE *fp;
|
|
if(!PyArg_ParseTuple(arg,"O|ii",&f,&s,&e)) return NULL;
|
|
fp=PyFile_AsFile(f);
|
|
if (!fp)
|
|
{ PyErr_SetString(PyExc_TypeError, "arg must be open file");
|
|
return NULL;
|
|
}
|
|
fwrite((int*)(self->block)+s,4,e-s,fp);
|
|
Py_INCREF(Py_None);return Py_None;
|
|
}
|
|
|
|
static struct PyMethodDef PyBlock_Methods[]=
|
|
{ { "tostring",(PyCFunction)PyBlock_ToString,1},
|
|
{ "padstring",(PyCFunction)PyBlock_PadString,1},
|
|
{ "nullstring",(PyCFunction)PyBlock_NullString,1},
|
|
{ "ctrlstring",(PyCFunction)PyBlock_CtrlString,1},
|
|
{ "bitset",(PyCFunction)PyBlock_BitSet,1},
|
|
{ "resize",(PyCFunction)PyBlock_Resize,1},
|
|
{ "tofile",(PyCFunction)PyBlock_ToFile,1},
|
|
{ NULL,NULL} /* sentinel */
|
|
};
|
|
|
|
static int block_len(PyBlockObject *b)
|
|
{ return b->length/4;
|
|
}
|
|
|
|
static PyObject *block_concat(PyBlockObject *b,PyBlockObject *c)
|
|
{ PyErr_SetString(PyExc_IndexError,"block concatenation not implemented");
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *block_repeat(PyBlockObject *b,int i)
|
|
{ PyErr_SetString(PyExc_IndexError,"block repetition not implemented");
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *block_item(PyBlockObject *b,int i)
|
|
{ if(i<0||4*i>=b->length)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
return PyInt_FromLong(((long*)(b->block))[i]);
|
|
}
|
|
|
|
static PyObject *block_slice(PyBlockObject *b,int i,int j)
|
|
{ int n,k;
|
|
long *p=b->block;
|
|
PyObject *result;
|
|
if(j>b->length/4) j=b->length/4;
|
|
if(i<0||i>j)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return NULL;
|
|
}
|
|
n=j-i;
|
|
result=PyList_New(n);
|
|
for(k=0;k<n;k++) PyList_SetItem(result,k,PyInt_FromLong(p[i+k]));
|
|
return result;
|
|
}
|
|
|
|
static int block_ass_item(PyBlockObject *b,int i,PyObject *v)
|
|
{ if(i<0||i>=b->length/4)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return -1;
|
|
}
|
|
if(!PyInt_Check(v))
|
|
{ PyErr_SetString(PyExc_TypeError,"block item must be integer");
|
|
return -1;
|
|
}
|
|
((long*)(b->block))[i]=PyInt_AsLong(v);
|
|
return 0;
|
|
}
|
|
|
|
static int block_ass_slice(PyBlockObject *b,int i,int j,PyObject *v)
|
|
{ int n,k;
|
|
long *p=b->block;
|
|
if(j>b->length/4) j=b->length/4;
|
|
if(i<0||i>j)
|
|
{ PyErr_SetString(PyExc_IndexError,"block index out of range");
|
|
return -1;
|
|
}
|
|
if(!PyList_Check(v)) goto fail;
|
|
n=PyList_Size(v);
|
|
if(n>j-i) n=j-i;
|
|
for(k=0;k<n;k++)
|
|
{ PyObject *q=PyList_GetItem(v,k);
|
|
if(!PyInt_Check(q)) goto fail;
|
|
p[i+k]=PyInt_AsLong(q);
|
|
}
|
|
for(;k<j-i;k++) p[i+k]=0;
|
|
return 0;
|
|
fail:PyErr_SetString(PyExc_TypeError,"block slice must be integer list");
|
|
return -1;
|
|
}
|
|
|
|
static PySequenceMethods block_as_sequence=
|
|
{ (inquiry)block_len, /*sq_length*/
|
|
(binaryfunc)block_concat, /*sq_concat*/
|
|
(intargfunc)block_repeat, /*sq_repeat*/
|
|
(intargfunc)block_item, /*sq_item*/
|
|
(intintargfunc)block_slice, /*sq_slice*/
|
|
(intobjargproc)block_ass_item, /*sq_ass_item*/
|
|
(intintobjargproc)block_ass_slice, /*sq_ass_slice*/
|
|
};
|
|
|
|
static PyObject *PyBlock_GetAttr(PyBlockObject *s,char *name)
|
|
{
|
|
if (!strcmp(name, "length")) return PyInt_FromLong((long)s->length);
|
|
if (!strcmp(name, "start")) return PyInt_FromLong((long)s->block);
|
|
if (!strcmp(name,"end")) return PyInt_FromLong(((long)(s->block)+s->length));
|
|
if (!strcmp(name, "__members__"))
|
|
{ PyObject *list = PyList_New(3);
|
|
if (list)
|
|
{ PyList_SetItem(list, 0, PyString_FromString("length"));
|
|
PyList_SetItem(list, 1, PyString_FromString("start"));
|
|
PyList_SetItem(list, 2, PyString_FromString("end"));
|
|
if (PyErr_Occurred()) { Py_DECREF(list);list = NULL;}
|
|
}
|
|
return list;
|
|
}
|
|
return Py_FindMethod(PyBlock_Methods, (PyObject*) s,name);
|
|
}
|
|
|
|
static void PyBlock_Dealloc(PyBlockObject *b)
|
|
{
|
|
if(b->heap) {
|
|
if (b->heap)
|
|
;
|
|
else
|
|
PyMem_DEL(b->block);
|
|
}
|
|
PyMem_DEL(b);
|
|
}
|
|
|
|
static PyTypeObject PyBlockType=
|
|
{ PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /*ob_size*/
|
|
"block", /*tp_name*/
|
|
sizeof(PyBlockObject), /*tp_size*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)PyBlock_Dealloc, /*tp_dealloc*/
|
|
0, /*tp_print*/
|
|
(getattrfunc)PyBlock_GetAttr, /*tp_getattr*/
|
|
0, /*tp_setattr*/
|
|
0, /*tp_compare*/
|
|
0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
&block_as_sequence, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
0, /*tp_hash*/
|
|
};
|
|
|
|
/* swi commands */
|
|
|
|
static PyObject *swi_swi(PyObject *self,PyObject *args)
|
|
{ PyObject *name,*format,*result,*v;
|
|
int swino,carry,rno=0,j,n;
|
|
char *swiname,*fmt,*outfmt;
|
|
_kernel_swi_regs r;
|
|
PyBlockObject *ao;
|
|
if(args==NULL||!PyTuple_Check(args)||(n=PyTuple_Size(args))<2)
|
|
{ PyErr_BadArgument(); return NULL;}
|
|
name=PyTuple_GetItem(args,0);
|
|
if(!PyArg_Parse(name,"i",&swino))
|
|
{ PyErr_Clear();
|
|
if(!PyArg_Parse(name,"s",&swiname)) return NULL;
|
|
e=xos_swi_number_from_string(swiname,&swino);
|
|
if(e) return swi_oserror();
|
|
}
|
|
format=PyTuple_GetItem(args,1);
|
|
if(!PyArg_Parse(format,"s",&fmt)) return NULL;
|
|
j=2;
|
|
for(;;fmt++)
|
|
{ switch(*fmt)
|
|
{ case '.': rno++;continue;
|
|
case ';':case 0: goto swicall;
|
|
case '0':case '1':case '2':case '3':case '4':
|
|
case '5':case '6':case '7':case '8':case '9':
|
|
r.r[rno++]=*fmt-'0';continue;
|
|
case '-':r.r[rno++]=-1;continue;
|
|
}
|
|
if(j>=n) return swi_error("Too few arguments");
|
|
v=PyTuple_GetItem(args,j++);
|
|
switch(*fmt)
|
|
{ case 'i':if(!PyArg_Parse(v,"i",&r.r[rno])) return NULL;
|
|
break;
|
|
case 's':if(!PyArg_Parse(v,"s",(char**)(&r.r[rno]))) return NULL;
|
|
break;
|
|
case 'b':if(!PyArg_Parse(v,"O",(PyObject**)&ao)) return NULL;
|
|
if(!PyBlock_Check(v)) return swi_error("Not a block");
|
|
r.r[rno]=(int)(ao->block);
|
|
break;
|
|
case 'e':if(!PyArg_Parse(v,"O",(PyObject**)&ao)) return NULL;
|
|
if(!PyBlock_Check(v)) return swi_error("Not a block");
|
|
r.r[rno]=(int)(ao->block)+ao->length;
|
|
break;
|
|
default:return swi_error("Odd format character");
|
|
}
|
|
rno++;
|
|
}
|
|
swicall:e=(os_error*)_kernel_swi_c(swino,&r,&r,&carry);
|
|
if(e) return swi_oserror();
|
|
if(*fmt==0) { Py_INCREF(Py_None);return Py_None;}
|
|
n=0;
|
|
for(outfmt=++fmt;*outfmt;outfmt++) switch(*outfmt)
|
|
{ case 'i':case 's':case '*':n++;break;
|
|
case '.':break;
|
|
default:return swi_error("Odd format character");
|
|
}
|
|
if(n==0) { Py_INCREF(Py_None);return Py_None;}
|
|
if(n!=1)
|
|
{ result=PyTuple_New(n);
|
|
if(!result) return NULL;
|
|
}
|
|
rno=0;j=0;
|
|
for(;*fmt;fmt++)
|
|
{ switch(*fmt)
|
|
{ case 'i':v=PyInt_FromLong((long)r.r[rno++]); break;
|
|
case 's':v=PyString_FromString((char*)(r.r[rno++])); break;
|
|
case '.':rno++; continue;
|
|
case '*':v=PyInt_FromLong((long)carry); break;
|
|
}
|
|
if(!v) goto fail;
|
|
if(n==1) return v;
|
|
PyTuple_SetItem(result,j,v);
|
|
j++;
|
|
}
|
|
return result;
|
|
fail:Py_DECREF(result);return 0;
|
|
}
|
|
|
|
static PyMethodDef SwiMethods[]=
|
|
{ { "swi",swi_swi,1},
|
|
{ "block",PyBlock_New,1},
|
|
{ "register",PyRegister,1},
|
|
{ NULL,NULL} /* Sentinel */
|
|
};
|
|
|
|
void initswi()
|
|
{ PyObject *m, *d;
|
|
m = Py_InitModule("swi", SwiMethods);
|
|
d = PyModule_GetDict(m);
|
|
SwiError=PyErr_NewException("swi.error", NULL, NULL);
|
|
PyDict_SetItemString(d,"error",SwiError);
|
|
ArgError=PyErr_NewException("swi.ArgError", NULL, NULL);
|
|
PyDict_SetItemString(d,"ArgError",ArgError);
|
|
}
|