/[thuban]/branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflibmodule.c
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflibmodule.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2745 - (hide annotations)
Thu Mar 15 22:27:02 2007 UTC (17 years, 11 months ago) by bramz
File MIME type: text/plain
File size: 13946 byte(s)
Added FTLogical support to dbflib.  Accept None as no-data for M values.  Added name and mode keywords to mimic Python's file behaviour where appropriate.  Added unpack_vertex() to lift some load of shpobject_init().
1 bramz 2742 #include "pyshapelib_common.h"
2 jan 1611
3 bramz 2742 /* --- DBFFile ------------------------------------------------------------------------------------------------------- */
4 jan 1611
5 bramz 2742 typedef struct {
6     PyObject_HEAD
7     DBFHandle handle;
8     } DBFFileObject;
9 jan 1611
10    
11 bh 1917
12 bramz 2742 /* allocator
13     */
14     static PyObject* dbffile_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
15 bh 1917 {
16 bramz 2742 DBFFileObject* self;
17     self = (DBFFileObject*) type->tp_alloc(type, 0);
18     self->handle = NULL;
19     return (PyObject*) self;
20     }
21 bh 1917
22 bramz 2742
23    
24     /* deallocator
25     */
26     static void dbffile_dealloc(DBFFileObject* self)
27     {
28     DBFClose(self->handle);
29     self->handle = NULL;
30     self->ob_type->tp_free((PyObject*)self);
31     }
32    
33    
34    
35     /* constructor
36     */
37     static int dbffile_init(DBFFileObject* self, PyObject* args, PyObject* kwds)
38     {
39     char* file;
40     char* mode = "rb";
41 bramz 2745 static char *kwlist[] = {"name", "mode", NULL};
42     if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|s:__init__", kwlist,
43     Py_FileSystemDefaultEncoding, &file, &mode)) return -1;
44 bramz 2742
45     self->handle = DBFOpen(file, mode);
46 bramz 2744 PyMem_Free(file);
47    
48 bramz 2742 return self->handle ? 0 : -1;
49     }
50 bh 1917
51    
52    
53 bramz 2742 static PyObject* dbffile_close(DBFFileObject* self)
54 bh 1917 {
55 bramz 2742 DBFClose(self->handle);
56     self->handle = NULL;
57     Py_RETURN_NONE;
58     }
59 bh 1917
60    
61 bramz 2742
62     static PyObject* dbffile_field_count(DBFFileObject* self)
63     {
64     return PyInt_FromLong((long)DBFGetFieldCount(self->handle));
65 bh 1917 }
66    
67 jan 1611
68 bramz 2742
69     static PyObject* dbffile_record_count(DBFFileObject* self)
70 jan 1611 {
71 bramz 2742 return PyInt_FromLong((long)DBFGetRecordCount(self->handle));
72     }
73 jan 1611
74    
75 bramz 2742
76     static PyObject* dbffile_field_info(DBFFileObject* self, PyObject* args)
77     {
78     char field_name[12];
79     int field, width = 0, decimals = 0, field_type;
80 jan 1611
81 bramz 2744 if (!PyArg_ParseTuple(args, "i:field_info", &field)) return NULL;
82 bramz 2742
83     field_name[0] = '\0';
84     field_type = DBFGetFieldInfo(self->handle, field, field_name, &width, &decimals);
85    
86     return Py_BuildValue("isii", field_type, field_name, width, decimals);
87     }
88 bh 1917
89 jan 1611
90 bh 1917
91 bramz 2742 static PyObject* dbffile_add_field(DBFFileObject* self, PyObject* args)
92     {
93     char* name;
94     int type, width, decimals;
95     int field;
96    
97 bramz 2744 if (!PyArg_ParseTuple(args, "siii:add_field", &name, &type, &width, &decimals)) return NULL;
98 bramz 2742
99     field = DBFAddField(self->handle, name, (DBFFieldType)type, width, decimals);
100    
101     if (field < 0)
102     {
103     PyErr_SetString(PyExc_ValueError, "Failed to add field due to inappropriate field definition");
104     return NULL;
105     }
106     return PyInt_FromLong((long)field);
107 jan 1611 }
108    
109    
110    
111 bramz 2742 /* Read one attribute from the dbf handle and return it as a new python object
112     *
113     * If an error occurs, set the appropriate Python exception and return
114     * NULL.
115     *
116     * Assume that the values of the record and field arguments are valid.
117     * The name argument will be passed to DBFGetFieldInfo as is and should
118     * thus be either NULL or a pointer to an array of at least 12 chars
119     */
120     static PyObject* do_read_attribute(DBFHandle handle, int record, int field, char * name)
121 jan 1611 {
122 bramz 2742 int type, width;
123     const char* temp;
124     type = DBFGetFieldInfo(handle, field, name, &width, NULL);
125    
126     /* For strings NULL and the empty string are indistinguishable
127     * in DBF files. We prefer empty strings instead for backwards
128     * compatibility reasons because older wrapper versions returned
129     * emtpy strings as empty strings.
130     */
131     if (type != FTString && DBFIsAttributeNULL(handle, record, field))
132 jan 1611 {
133 bramz 2742 Py_RETURN_NONE;
134 jan 1611 }
135 bramz 2742 else
136 jan 1611 {
137 bramz 2742 switch (type)
138     {
139     case FTString:
140     temp = DBFReadStringAttribute(handle, record, field);
141 bramz 2745 if (temp) return PyString_FromString(temp);
142 jan 1611
143 bramz 2742 case FTInteger:
144     return PyInt_FromLong((long)DBFReadIntegerAttribute(handle, record, field));
145 jan 1611
146 bramz 2742 case FTDouble:
147     return PyFloat_FromDouble(DBFReadDoubleAttribute(handle, record, field));
148 bramz 2745
149     case FTLogical:
150     temp = DBFReadLogicalAttribute(handle, record, field);
151     if (temp)
152     {
153     switch (temp[0])
154     {
155     case 'F':
156     case 'N':
157     Py_RETURN_FALSE;
158     case 'T':
159     case 'Y':
160     Py_RETURN_TRUE;
161     }
162     }
163     break;
164 jan 1611
165 bramz 2742 default:
166     PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
167     return NULL;
168     }
169 jan 1611 }
170 bramz 2745
171     PyErr_Format(PyExc_IOError, "Can't read value for row %d column %d", record, field);
172     return NULL;
173 bramz 2742 }
174 jan 1611
175    
176 bramz 2742
177     /* the read_attribute method. Return the value of the given record and
178     * field as a python object of the appropriate type.
179     */
180     static PyObject* dbffile_read_attribute(DBFFileObject* self, PyObject* args)
181 jan 1611 {
182 bramz 2742 int record, field;
183 jan 1611
184 bramz 2744 if (!PyArg_ParseTuple(args, "ii:read_field", &record, &field)) return NULL;
185 bramz 2742
186     if (record < 0 || record >= DBFGetRecordCount(self->handle))
187     {
188     PyErr_Format(PyExc_ValueError,
189     "record index %d out of bounds (record count: %d)",
190     record, DBFGetRecordCount(self->handle));
191     return NULL;
192     }
193 jan 1611
194 bramz 2742 if (field < 0 || field >= DBFGetFieldCount(self->handle))
195 jan 1611 {
196 bramz 2742 PyErr_Format(PyExc_ValueError,
197     "field index %d out of bounds (field count: %d)",
198     field, DBFGetFieldCount(self->handle));
199     return NULL;
200 jan 1611 }
201 bramz 2742
202     return do_read_attribute(self->handle, record, field, NULL);
203     }
204    
205    
206    
207     /* the read_record method. Return the record record as a dictionary with
208     * whose keys are the names of the fields, and their values as the
209     * appropriate Python type.
210     */
211     static PyObject* dbffile_read_record(DBFFileObject* self, PyObject* args)
212     {
213     int record;
214     int num_fields;
215     int i;
216     char name[12];
217     PyObject *dict;
218     PyObject *value = NULL;
219    
220 bramz 2744 if (!PyArg_ParseTuple(args, "i:read_record", &record)) return NULL;
221 bramz 2742
222     if (record < 0 || record >= DBFGetRecordCount(self->handle))
223 jan 1611 {
224 bramz 2742 PyErr_Format(PyExc_ValueError,
225     "record index %d out of bounds (record count: %d)",
226     record, DBFGetRecordCount(self->handle));
227     return NULL;
228 jan 1611 }
229 bramz 2742
230     dict = PyDict_New();
231     if (!dict) return NULL;
232    
233     num_fields = DBFGetFieldCount(self->handle);
234 jan 1611 for (i = 0; i < num_fields; i++)
235     {
236 bramz 2742 value = do_read_attribute(self->handle, record, i, name);
237     if (!value || PyDict_SetItemString(dict, name, value) < 0) goto fail;
238 jan 1611 Py_DECREF(value);
239 bramz 2742 value = NULL;
240 jan 1611 }
241    
242 bramz 2742 return dict;
243 jan 1611
244 bramz 2742 fail:
245     Py_XDECREF(value);
246     Py_DECREF(dict);
247     return NULL;
248 jan 1611 }
249    
250    
251 bramz 2742
252     /* write a single field of a record. */
253     static int do_write_field(DBFHandle handle, int record, int field, int type, PyObject* value)
254 bh 2212 {
255 bramz 2742 char * string_value;
256     int int_value;
257     double double_value;
258 bramz 2745 int logical_value;
259 bh 2212
260 bramz 2742 if (value == Py_None)
261     {
262 bramz 2745 if (DBFWriteNULLAttribute(handle, record, field)) return 1;
263 bramz 2742 }
264     else
265     {
266     switch (type)
267     {
268     case FTString:
269     string_value = PyString_AsString(value);
270     if (!string_value) return 0;
271 bramz 2745 if (DBFWriteStringAttribute(handle, record, field, string_value)) return 1;
272 bramz 2742 break;
273 bh 2212
274 bramz 2742 case FTInteger:
275     int_value = PyInt_AsLong(value);
276     if (int_value == -1 && PyErr_Occurred()) return 0;
277 bramz 2745 if (DBFWriteIntegerAttribute(handle, record, field, int_value)) return 1;
278 bramz 2742 break;
279 jan 1611
280 bramz 2742 case FTDouble:
281     double_value = PyFloat_AsDouble(value);
282     if (double_value == -1 && PyErr_Occurred()) return 0;
283 bramz 2745 if (DBFWriteDoubleAttribute(handle, record, field, double_value)) return 1;
284 bramz 2742 break;
285 bramz 2745
286     case FTLogical:
287     logical_value = PyObject_IsTrue(value);
288     if (logical_value == -1) return 0;
289     if (DBFWriteLogicalAttribute(handle, record, field, logical_value ? 'T' : 'F')) return 1;
290     break;
291 jan 1611
292 bramz 2742 default:
293     PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
294     return 0;
295     }
296     }
297 jan 1611
298 bramz 2745 PyErr_Format(PyExc_IOError, "can't write field %d of record %d", field, record);
299     return 0;
300 bramz 2742 }
301 jan 1611
302    
303    
304 bramz 2742 static PyObject* dbffile_write_field(DBFFileObject* self, PyObject* args)
305     {
306     int record, field;
307     PyObject* value;
308     int type;
309    
310 bramz 2744 if (!PyArg_ParseTuple(args, "iiO:write_field", &record, &field, &value)) return NULL;
311 bramz 2742
312     if (field < 0 || field >= DBFGetFieldCount(self->handle))
313     {
314     PyErr_Format(PyExc_ValueError,
315     "field index %d out of bounds (field count: %d)",
316     field, DBFGetFieldCount(self->handle));
317     return NULL;
318     }
319    
320     type = DBFGetFieldInfo(self->handle, field, NULL, NULL, NULL);
321     if (!do_write_field(self->handle, record, field, type, value)) return NULL;
322     Py_RETURN_NONE;
323 jan 1611 }
324    
325    
326    
327 bramz 2742 static PyObject* dbffile_write_record(DBFFileObject* self, PyObject* args)
328     {
329     int record;
330     PyObject* record_object;
331     int i, num_fields;
332    
333     int type;
334     char name[12];
335     PyObject* value = NULL;
336    
337 bramz 2744 if (!PyArg_ParseTuple(args, "iO:write_record", &record, &record_object)) return NULL;
338 bramz 2742
339     num_fields = DBFGetFieldCount(self->handle);
340    
341     /* mimic ShapeFile functionality where id = -1 means appending */
342     if (record == -1)
343     {
344     record = num_fields;
345     }
346 jan 1611
347 bramz 2742 if (PySequence_Check(record_object))
348     {
349     /* It's a sequence object. Iterate through all items in the
350     * sequence and write them to the appropriate field.
351     */
352     if (PySequence_Length(record_object) != num_fields)
353     {
354     PyErr_SetString(PyExc_TypeError, "record must have one item for each field");
355     return NULL;
356     }
357     for (i = 0; i < num_fields; ++i)
358     {
359     type = DBFGetFieldInfo(self->handle, i, NULL, NULL, NULL);
360     value = PySequence_GetItem(record_object, i);
361     if (!value) return NULL;
362     if (!do_write_field(self->handle, record, i, type, value))
363     {
364     Py_DECREF(value);
365     return NULL;
366     }
367     Py_DECREF(value);
368     }
369     }
370     else
371     {
372     /* It's a dictionary-like object. Iterate over the names of the
373     * known fields and write the corresponding item
374     */
375     for (i = 0; i < num_fields; ++i)
376     {
377     name[0] = '\0';
378     type = DBFGetFieldInfo(self->handle, i, name, NULL, NULL);
379     value = PyDict_GetItemString(record_object, name);
380     if (value && !do_write_field(self->handle, record, i, type, value)) return NULL;
381     }
382     }
383    
384     return PyInt_FromLong((long)record);
385 bh 1761 }
386 jan 1611
387    
388    
389 bramz 2742 static PyObject* dbffile_repr(DBFFileObject* self)
390     {
391     /* TODO: it would be nice to do something like "dbflib.DBFFile(filename, mode)" instead */
392     return PyString_FromFormat("<dbflib.DBFFile object at %p>", self->handle);
393 jan 1611 }
394    
395    
396    
397 bramz 2742 /* The commit method implementation
398     *
399     * The method relies on the DBFUpdateHeader method which is not
400     * available in shapelib <= 1.2.10. setup.py defines
401     * HAVE_UPDATE_HEADER's value depending on whether the function is
402     * available in the shapelib version the code is compiled with.
403     */
404     #if HAVE_UPDATE_HEADER
405     static PyObject* dbffile_commit(DBFFileObject* self)
406 jan 1611 {
407 bramz 2742 DBFUpdateHeader(self->handle);
408     Py_RETURN_NONE;
409     }
410     #endif
411 jan 1611
412    
413    
414 bramz 2742 static struct PyMethodDef dbffile_methods[] =
415     {
416 bramz 2744 {"close", (PyCFunction)dbffile_close, METH_NOARGS,
417 bramz 2745 "close() -> None\n\n"
418     "closes DBFFile"},
419 bramz 2744 {"field_count", (PyCFunction)dbffile_field_count, METH_NOARGS,
420 bramz 2745 "field_count() -> integer\n\n"
421 bramz 2744 "returns number of fields currently defined"},
422     {"record_count", (PyCFunction)dbffile_record_count, METH_NOARGS,
423 bramz 2745 "record_count() -> integer\n\n"
424 bramz 2744 "returns number of records that currently exist"},
425     {"field_info", (PyCFunction)dbffile_field_info, METH_VARARGS,
426 bramz 2745 "field_info(field_index) -> (type, name, width, decimals)\n\n"
427     "returns info of a field as a tuple with:\n"
428     "- type: the type of the field corresponding to the integer value of one "
429     " of the constants FTString, FTInteger, ...\n"
430     "- name: the name of the field as a string\n"
431     "- width: the width of the field as a number of characters\n"
432     "- decimals: the number of decimal digits" },
433 bramz 2742 {"add_field", (PyCFunction)dbffile_add_field, METH_VARARGS,
434 bramz 2745 "add_field(type, name, width, decimals) -> field_index\n\n"
435 bramz 2742 "adds a new field and returns field index if successful\n"
436 bramz 2745 "- type: the type of the field corresponding to the integer value of one "
437     " of the constants FTString, FTInteger, ...\n"
438     "- name: the name of the field as a string\n"
439     "- width: the width of the field as a number of characters\n"
440     "- decimals: the number of decimal digits" },
441 bramz 2744 {"read_attribute", (PyCFunction)dbffile_read_attribute, METH_VARARGS,
442 bramz 2745 "read_attribute(record_index, field_index) -> value\n\n"
443     "returns the value of one field of a record"},
444 bramz 2744 {"read_record", (PyCFunction)dbffile_read_record, METH_VARARGS,
445 bramz 2745 "read_record(record_index) -> dict\n\n"
446     "returns an entire record as a dictionary of field names and values"},
447 bramz 2744 {"write_field", (PyCFunction)dbffile_write_field, METH_VARARGS,
448     "write_field(record_index, field_index, new_value)\n"
449 bramz 2745 "writes a single field of a record"},
450 bramz 2744 {"write_record", (PyCFunction)dbffile_write_record, METH_VARARGS,
451 bramz 2745 "write_record(record_index, record) -> record_index\n\n"
452     "Writes an entire record as a dict or a sequence, and return index of record\n"
453     "Record can either be a dictionary in which case the keys are used as field names, "
454 bramz 2744 "or a sequence that must have an item for every field (length = field_count())"},
455 bramz 2742 #if HAVE_UPDATE_HEADER
456 bramz 2744 {"commit", (PyCFunction)dbffile_read_record, METH_NOARGS,
457 bramz 2745 "commit() -> None"},
458 bramz 2742 #endif
459     {NULL}
460     };
461 jan 1611
462    
463 bh 1917
464 bramz 2742 static struct PyGetSetDef dbffile_getsetters[] =
465     {
466     {NULL}
467     };
468 jan 1611
469    
470    
471 bramz 2742 static PyTypeObject DBFFileType = PYSHAPELIB_DEFINE_TYPE(DBFFileObject, dbffile, "shapelib.DBFFile", 0);
472 bh 2453
473    
474 jan 1611
475 bramz 2742 /* --- dbflib -------------------------------------------------------------------------------------------------------- */
476 jan 1611
477 bramz 2742 static PyObject* dbflib_open(PyObject* module, PyObject* args)
478     {
479     return PyObject_CallObject((PyObject*)&DBFFileType, args);
480     }
481 jan 1611
482    
483    
484 bramz 2742 static PyObject* dbflib_create(PyObject* module, PyObject* args)
485     {
486     char* file;
487     DBFFileObject* result;
488    
489 bramz 2744 if (!PyArg_ParseTuple(args, "et:create", Py_FileSystemDefaultEncoding, &file)) return NULL;
490 bramz 2742
491     result = PyObject_New(DBFFileObject, &DBFFileType);
492     if (!result)
493     {
494     return PyErr_NoMemory();
495     }
496    
497     result->handle = DBFCreate(file);
498     if (!result->handle)
499     {
500     PyObject_Del((PyObject*)result);
501     PyErr_SetString(PyExc_RuntimeError, "Failed to create DBFFile");
502     return NULL;
503     }
504    
505     return (PyObject*) result;
506     }
507 jan 1611
508    
509    
510 bramz 2742 static struct PyMethodDef dbflib_methods[] =
511     {
512 bramz 2744 {"open", (PyCFunction)dbflib_open, METH_VARARGS,
513 bramz 2745 "open(name [, mode]) -> DBFFile\n\n"
514     "opens a DBFFile" },
515 bramz 2744 {"create", (PyCFunction)dbflib_create, METH_VARARGS,
516 bramz 2745 "create(name) -> DBFFile\n\n"
517 bramz 2744 "create a DBFFile" },
518 bramz 2742 {NULL}
519     };
520 jan 1611
521 bh 2212
522    
523 bramz 2742 PyMODINIT_FUNC initdbflib(void)
524     {
525     PyObject* module = Py_InitModule("dbflib", dbflib_methods);
526     if (!module) return;
527    
528     PYSHAPELIB_ADD_TYPE(DBFFileType, "DBFFile");
529    
530     PYSHAPELIB_ADD_CONSTANT(FTString);
531     PYSHAPELIB_ADD_CONSTANT(FTInteger);
532     PYSHAPELIB_ADD_CONSTANT(FTDouble);
533 bramz 2745 PYSHAPELIB_ADD_CONSTANT(FTLogical);
534 bramz 2742 PYSHAPELIB_ADD_CONSTANT(FTInvalid);
535     PyModule_AddIntConstant(module, "_have_commit", HAVE_UPDATE_HEADER);
536     }

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26