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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26