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