1// PyRowRef.cpp -- 2// $Id: PyRowRef.cpp 1230 2007-03-09 15:58:53Z jcw $ 3// This is part of MetaKit, the homepage is http://www.equi4.com/metakit.html 4// Copyright (C) 1999-2004 Gordon McMillan and Jean-Claude Wippler. 5// 6// RowRef class implementation 7 8#include <PWOSequence.h> 9#include <PWONumber.h> 10#include "PyRowRef.h" 11#include "PyView.h" 12 13#if defined(PY_LONG_LONG) && !defined(LONG_LONG) 14#define LONG_LONG PY_LONG_LONG 15#endif 16 17static PyMethodDef RowRefMethods[] = { 18 { 19 0, 0, 0, 0 20 } 21}; 22 23static void PyRowRef_dealloc(PyRowRef *o) { 24 //o->~PyRowRef(); 25 delete o; 26} 27 28static int PyRowRef_print(PyRowRef *o, FILE *f, int) { 29 fprintf(f, "<PyRowRef object at %p>", (void*)o); 30 return 0; 31} 32 33static int PyRORowRef_print(PyRowRef *o, FILE *f, int) { 34 fprintf(f, "<PyRORowRef object at %p>", (void*)o); 35 return 0; 36} 37 38static PyObject *PyRowRef_getattr(PyRowRef *o, char *nm) { 39 try { 40 if (nm[0] == '_' && nm[1] == '_') { 41 if (strcmp(nm, "__attrs__") == 0) { 42 c4_View parent = o->Container(); 43 int nprops = parent.NumProperties(); 44 PyObject *out = PyList_New(nprops); 45 for (int i = 0; i < nprops; i++) { 46 PyList_SetItem(out, i, new PyProperty(parent.NthProperty(i))); 47 } 48 return out; 49 } else if (strcmp(nm, "__view__") == 0) { 50 return new PyView(o->Container()); 51 } else if (strcmp(nm, "__index__") == 0) { 52 return PyInt_FromLong((&(*o))._index); 53 } 54 } 55 56 PyObject *attr = o->getPropertyValue(nm); 57 if (attr) 58 return attr; 59 PyErr_Clear(); 60 return Py_FindMethod(RowRefMethods, (PyObject*)o, nm); 61 } catch (...) { 62 return NULL; 63 } 64} 65 66static int PyRowRef_setattr(PyRowRef *o, char *nm, PyObject *v) { 67 try { 68 PyProperty *p = o->getProperty(nm); 69 if (p) { 70 if (v) 71 PyRowRef::setFromPython(*o, *p, v); 72 else 73 PyRowRef::setDefault(*o, *p); 74 Py_DECREF(p); 75 return 0; 76 } 77 PyErr_SetString(PyExc_AttributeError, "delete of nonexistent attribute"); 78 return - 1; 79 } catch (...) { 80 return - 1; 81 } 82} 83 84PyTypeObject PyRowReftype = { 85 PyObject_HEAD_INIT(&PyType_Type)0, "PyRowRef", sizeof(PyRowRef), 0, 86 (destructor)PyRowRef_dealloc, /*tp_dealloc*/ 87 (printfunc)PyRowRef_print, /*tp_print*/ 88 (getattrfunc)PyRowRef_getattr, /*tp_getattr*/ 89 (setattrfunc)PyRowRef_setattr, /*tp_setattr*/ 90 (cmpfunc)0, /*tp_compare*/ 91 (reprfunc)0, /*tp_repr*/ 92 0, /*tp_as_number*/ 93 0, /*tp_as_sequence*/ 94 0, /*tp_as_mapping*/ 95}; 96PyTypeObject PyRORowReftype = { 97 PyObject_HEAD_INIT(&PyType_Type)0, "PyRORowRef", sizeof(PyRowRef), 0, 98 (destructor)PyRowRef_dealloc, /*tp_dealloc*/ 99 (printfunc)PyRORowRef_print, /*tp_print*/ 100 (getattrfunc)PyRowRef_getattr, /*tp_getattr*/ 101 (setattrfunc)0, /*tp_setattr*/ 102 (cmpfunc)0, /*tp_compare*/ 103 (reprfunc)0, /*tp_repr*/ 104 0, /*tp_as_number*/ 105 0, /*tp_as_sequence*/ 106 0, /*tp_as_mapping*/ 107}; 108 109 110PyRowRef::PyRowRef(const c4_RowRef &o, int immutable): PyHead(PyRowReftype), 111 c4_RowRef(o) { 112 if (immutable) 113 ob_type = &PyRORowReftype; 114 c4_Cursor c = &(*(c4_RowRef*)this); 115 c._seq->IncRef(); 116} 117 118// with thanks to Niki Spahiev for improving conversions and error checks 119void PyRowRef::setFromPython(const c4_RowRef &row, const c4_Property &prop, 120 PyObject *attr) { 121 switch (prop.Type()) { 122 case 'I': 123 if (PyInt_Check(attr)) { 124 long number = PyInt_AsLong(attr); 125 if (number == - 1 && PyErr_Occurred() != NULL) 126 Fail(PyExc_ValueError, "int too large to convert to C long"); 127 ((const c4_IntProp &)prop)(row) = number; 128 } 129 else if (attr != Py_None) { 130 PWONumber number(attr); 131 ((const c4_IntProp &)prop)(row) = (long)number; 132 } 133 break; 134#ifdef HAVE_LONG_LONG 135 case 'L': 136 if (PyLong_Check(attr)) { 137 LONG_LONG number = PyLong_AsLongLong(attr); 138 if (number == - 1 && PyErr_Occurred() != NULL) 139 Fail(PyExc_ValueError, "long int too large to convert to C long long") 140 ; 141 ((const c4_LongProp &)prop)(row) = number; 142 } 143 else if (PyInt_Check(attr)) { 144 long number = PyInt_AsLong(attr); 145 if (number == - 1 && PyErr_Occurred() != NULL) 146 Fail(PyExc_ValueError, "int too large to convert to C long"); 147 ((const c4_LongProp &)prop)(row) = number; 148 } 149 else if (attr != Py_None) { 150 PWONumber number(attr); 151 ((const c4_LongProp &)prop)(row) = (LONG_LONG)number; 152 } 153 break; 154#endif 155 case 'F': 156 if (PyFloat_Check(attr)) 157 ((const c4_FloatProp &)prop)(row) = PyFloat_AS_DOUBLE(attr); 158 else if (attr != Py_None) { 159 PWONumber number(attr); 160 ((const c4_FloatProp &)prop)(row) = (double)number; 161 } 162 break; 163 case 'D': 164 if (PyFloat_Check(attr)) 165 ((const c4_DoubleProp &)prop)(row) = PyFloat_AS_DOUBLE(attr); 166 else if (attr != Py_None) { 167 PWONumber number(attr); 168 ((const c4_DoubleProp &)prop)(row) = (double)number; 169 } 170 break; 171 case 'S': 172 if (attr != Py_None) { 173#ifdef HAVE_UNICODEOBJECT_H 174 bool is_unicode = PyUnicode_Check(attr); 175 if (is_unicode) 176 attr = PyUnicode_AsUTF8String(attr); 177#else 178 const bool is_unicode = false; 179#endif 180 PWOString string(attr); 181 if (is_unicode) 182 Py_DECREF(attr); 183 184 size_t size = string.size(); 185 const char *cstring = string; 186 if (size != strlen(cstring)) 187 Fail(PyExc_ValueError, "string contains embedded nulls; try 'B' type") 188 ; 189 c4_Bytes temp(cstring, size + 1, false); 190 prop(row).SetData(temp); 191 } 192 break; 193 case 'V': 194 if (PyView_Check(attr)) { 195 PyView *obj = (PyView*)attr; 196 ((const c4_ViewProp &)prop)(row) = *obj; 197 } 198 else { 199 //((const c4_ViewProp&) prop) (row) = c4_View (); 200 PyView tmp(((const c4_ViewProp &)prop)(row)); 201 PWOSequence lst(attr); 202 tmp.SetSize(lst.len()); 203 for (int i = 0; i < lst.len(); i++) { 204 PyObject *entry = lst[i]; 205 tmp.setItem(i, entry); 206 Py_DECREF(entry); 207 } 208 } 209 break; 210 case 'B': 211 case 'M': 212 if (PyString_Check(attr)) { 213 c4_Bytes temp(PyString_AS_STRING(attr), PyString_GET_SIZE(attr), false); 214 prop(row).SetData(temp); 215 } 216 else if (attr != Py_None) 217 Fail(PyExc_TypeError, "wrong type for ByteProp"); 218 break; 219 default: 220 PyErr_Format(PyExc_TypeError, "unknown property type '%c'", prop.Type()); 221 throw PWDPyException; 222 } 223} 224 225void PyRowRef::setDefault(const c4_RowRef &row, const c4_Property &prop) { 226 switch (prop.Type()) { 227 case 'I': 228 ((const c4_IntProp &)prop)(row) = 0; 229 break; 230#ifdef HAVE_LONG_LONG 231 case 'L': 232 ((const c4_LongProp &)prop)(row) = 0; 233 break; 234#endif 235 case 'F': 236 ((const c4_FloatProp &)prop)(row) = 0.0; 237 break; 238 case 'D': 239 ((const c4_DoubleProp &)prop)(row) = 0.0; 240 break; 241 case 'S': 242 ((const c4_StringProp &)prop)(row) = ""; 243 break; 244 case 'V': 245 ((const c4_ViewProp &)prop)(row) = c4_View(); 246 break; 247 case 'B': 248 case 'M': 249 { 250 c4_Bytes temp; 251 prop(row).SetData(temp); 252 } 253 break; 254 default: 255 PyErr_Format(PyExc_TypeError, "unknown property type '%c'", prop.Type()); 256 throw PWDPyException; 257 } 258} 259 260PyObject *PyRowRef::asPython(const c4_Property &prop) { 261 switch (prop.Type()) { 262 case 'I': 263 { 264 PWONumber rslt(((const c4_IntProp &)prop)(*this)); 265 return rslt.disOwn(); 266 } 267#ifdef HAVE_LONG_LONG 268 case 'L': 269 { 270 return PyLong_FromLongLong((LONG_LONG)((const c4_LongProp &)prop)(*this) 271 ); 272 } 273#endif 274 case 'F': 275 { 276 PWONumber rslt(((const c4_FloatProp &)prop)(*this)); 277 return rslt.disOwn(); 278 } 279 case 'D': 280 { 281 PWONumber rslt(((const c4_DoubleProp &)prop)(*this)); 282 return rslt.disOwn(); 283 } 284 case 'S': 285 { 286 PWOString rslt(((c4_StringProp &)prop).Get(*this)); 287 return rslt.disOwn(); 288 } 289 case 'V': 290 { 291 return new PyView(((const c4_ViewProp &)prop)(*this)); 292 } 293 case 'B': 294 case 'M': 295 { 296 c4_Bytes temp; 297 prop(*this).GetData(temp); 298 PWOString rslt((const char*)temp.Contents(), temp.Size()); 299 return rslt.disOwn(); 300 } 301 default: 302 return PyErr_Format(PyExc_TypeError, "unknown property type '%c'", 303 prop.Type()); 304 } 305} 306