/[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 1761 - (hide annotations)
Mon Sep 29 10:52:22 2003 UTC (21 years, 5 months ago) by bh
Original Path: trunk/thuban/libraries/pyshapelib/dbflib.i
File size: 12227 byte(s)
* dbflib.i: Add exception typemap for the add_field method. Fixes
Thuban bug RT#1842

* dbflib_wrap.c: Update from dbflib.i

1 jan 1611 /* SWIG (www.swig.org) interface file for the dbf interface of shapelib
2     *
3     * At the moment (Dec 2000) this file is only useful to generate Python
4     * bindings. Invoke swig as follows:
5     *
6     * swig -python -shadow dbflib.i
7     *
8     * to generate dbflib_wrap.c and dbflib.py. dbflib_wrap.c defines a
9     * bunch of Python-functions that wrap the appripriate dbflib functions
10     * and dbflib.py contains an object oriented wrapper around
11     * dbflib_wrap.c.
12     *
13     * This module defines one object type: DBFFile.
14     */
15    
16     /* this is the dbflib module */
17     %module dbflib
18    
19     /* first a %{,%} block. These blocks are copied verbatim to the
20     * dbflib_wrap.c file and are not parsed by SWIG. This is the place to
21     * import headerfiles and define helper-functions that are needed by the
22     * automatically generated wrappers.
23     */
24    
25     %{
26     #include "shapefil.h"
27    
28     /* the read_record method. Return the record record as a dictionary with
29     * whose keys are the names of the fields, and their values as the
30     * appropriate Python type.
31     *
32     * In case of error, set a python exception and return NULL. Since that
33     * value will be returned to the python interpreter as is, the
34     * interpreter should recognize the exception.
35     */
36    
37     static PyObject *
38     DBFInfo_read_record(DBFInfo * handle, int record)
39     {
40     int num_fields;
41     int i;
42     int type, width;
43     char name[12];
44     PyObject *dict;
45     PyObject *value;
46    
47     if (record < 0 || record >= DBFGetRecordCount(handle))
48     {
49     PyErr_Format(PyExc_ValueError,
50     "record index %d out of bounds (record count: %d)",
51     record, DBFGetRecordCount(handle));
52     return NULL;
53     }
54    
55     dict = PyDict_New();
56     if (!dict)
57     return NULL;
58    
59     num_fields = DBFGetFieldCount(handle);
60     for (i = 0; i < num_fields; i++)
61     {
62     type = DBFGetFieldInfo(handle, i, name, &width, NULL);
63     /* For strings NULL and the empty string are indistinguishable
64     * in DBF files. We prefer empty strings instead for backwards
65     * compatibility reasons because older wrapper versions returned
66     * emtpy strings as empty strings.
67     */
68     if (type != FTString && DBFIsAttributeNULL(handle, record, i))
69     {
70     value = Py_None;
71     Py_INCREF(value);
72     }
73     else
74     {
75     switch (type)
76     {
77     case FTString:
78     {
79     const char * temp = DBFReadStringAttribute(handle, record, i);
80     if (temp)
81     {
82     value = PyString_FromString(temp);
83     }
84     else
85     {
86     PyErr_Format(PyExc_IOError,
87     "Can't read value for row %d column %d",
88     record, i);
89     value = NULL;
90     }
91     break;
92     }
93     case FTInteger:
94     value = PyInt_FromLong(DBFReadIntegerAttribute(handle, record,
95     i));
96     break;
97     case FTDouble:
98     value = PyFloat_FromDouble(DBFReadDoubleAttribute(handle,
99     record, i));
100     break;
101     default:
102     PyErr_Format(PyExc_TypeError, "Invalid field data type %d",
103     type);
104     value = NULL;
105     }
106     }
107     if (!value)
108     goto fail;
109     PyDict_SetItemString(dict, name, value);
110     Py_DECREF(value);
111     }
112    
113     return dict;
114     fail:
115     Py_XDECREF(dict);
116     return NULL;
117     }
118    
119     /* the write_record method. Write the record record given wither as a
120     * dictionary or a sequence (i.e. a list or a tuple).
121     *
122     * If it's a dictionary the keys must be the names of the fields and
123     * their value must have a suitable type. Only the fields actually
124     * contained in the dictionary are written. Fields for which there's no
125     * item in the dict are not modified.
126     *
127     * If it's a sequence, all fields must be present in the right order.
128     *
129     * In case of error, set a python exception and return NULL. Since that
130     * value will be returned to the python interpreter as is, the
131     * interpreter should recognize the exception.
132     *
133     * The method is implemented with two c-functions, write_field to write
134     * a single field and DBFInfo_write_record as the front-end.
135     */
136    
137    
138     /* write a single field of a record. */
139     static int
140     write_field(DBFHandle handle, int record, int field, int type,
141     PyObject * value)
142     {
143     char * string_value;
144     int int_value;
145     double double_value;
146    
147     if (value == Py_None)
148     {
149     if (!DBFWriteNULLAttribute(handle, record, field))
150     {
151     PyErr_Format(PyExc_IOError,
152     "can't write NULL field %d of record %d",
153     field, record);
154     return 0;
155     }
156     }
157     else
158     {
159     switch (type)
160     {
161     case FTString:
162     string_value = PyString_AsString(value);
163     if (!string_value)
164     return 0;
165     if (!DBFWriteStringAttribute(handle, record, field, string_value))
166     {
167     PyErr_Format(PyExc_IOError,
168     "can't write field %d of record %d",
169     field, record);
170     return 0;
171     }
172     break;
173    
174     case FTInteger:
175     int_value = PyInt_AsLong(value);
176     if (int_value == -1 && PyErr_Occurred())
177     return 0;
178     if (!DBFWriteIntegerAttribute(handle, record, field, int_value))
179     {
180     PyErr_Format(PyExc_IOError,
181     "can't write field %d of record %d",
182     field, record);
183     return 0;
184     }
185     break;
186    
187     case FTDouble:
188     double_value = PyFloat_AsDouble(value);
189     if (double_value == -1 && PyErr_Occurred())
190     return 0;
191     if (!DBFWriteDoubleAttribute(handle, record, field, double_value))
192     {
193     PyErr_Format(PyExc_IOError,
194     "can't write field %d of record %d",
195     field, record);
196     return 0;
197     }
198     break;
199    
200     default:
201     PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
202     return 0;
203     }
204     }
205    
206     return 1;
207     }
208    
209     static
210     PyObject *
211     DBFInfo_write_record(DBFHandle handle, int record, PyObject *record_object)
212     {
213     int num_fields;
214     int i, length;
215     int type, width;
216     char name[12];
217     PyObject * value = NULL;
218    
219     num_fields = DBFGetFieldCount(handle);
220    
221     /* We used to use PyMapping_Check to test whether record_object is a
222     * dictionary like object instead of PySequence_Check to test
223     * whether it's a sequence. Unfortunately in Python 2.3
224     * PyMapping_Check returns true for lists and tuples too so the old
225     * approach doesn't work anymore.
226     */
227     if (PySequence_Check(record_object))
228     {
229     /* It's a sequence object. Iterate through all items in the
230     * sequence and write them to the appropriate field.
231     */
232     length = PySequence_Length(record_object);
233     if (length != num_fields)
234     {
235     PyErr_SetString(PyExc_TypeError,
236     "record must have one item for each field");
237     goto fail;
238     }
239     for (i = 0; i < length; i++)
240     {
241     type = DBFGetFieldInfo(handle, i, name, &width, NULL);
242     value = PySequence_GetItem(record_object, i);
243     if (value)
244     {
245     if (!write_field(handle, record, i, type, value))
246     goto fail;
247     Py_DECREF(value);
248     }
249     else
250     {
251     goto fail;
252     }
253     }
254     }
255     else
256     {
257     /* It's a dictionary-like object. Iterate over the names of the
258     * known fields and write the corresponding item
259     */
260     for (i = 0; i < num_fields; i++)
261     {
262     type = DBFGetFieldInfo(handle, i, name, &width, NULL);
263    
264     /* if the dictionary has the key name write that object to
265     * the appropriate field, other wise just clear the python
266     * exception and do nothing.
267     */
268     value = PyMapping_GetItemString(record_object, name);
269     if (value)
270     {
271     if (!write_field(handle, record, i, type, value))
272     goto fail;
273     Py_DECREF(value);
274     }
275     else
276     {
277     PyErr_Clear();
278     }
279     }
280     }
281    
282     Py_INCREF(Py_None);
283     return Py_None;
284    
285     fail:
286     Py_XDECREF(value);
287     return NULL;
288     }
289     %}
290    
291    
292     /*
293     * The SWIG Interface definition.
294     */
295    
296     /* include some common SWIG type definitions and standard exception
297     handling code */
298     %include typemaps.i
299     %include exception.i
300    
301     /* As for ShapeFile in shapelib.i, We define a new C-struct that holds
302     * the DBFHandle. This is mainly done so we can separate the close()
303     * method from the destructor but it also helps with exception handling.
304     *
305     * After the DBFFile has been opened or created the handle is not NULL.
306     * The close() method closes the file and sets handle to NULL as an
307     * indicator that the file has been closed.
308     */
309    
310     %{
311     typedef struct {
312     DBFHandle handle;
313     } DBFFile;
314     %}
315    
316    
317     /* The first argument to the DBFFile methods is a DBFFile pointer.
318     * We have to check whether handle is not NULL in most methods but not
319     * all. In the destructor and the close method, it's OK for handle to be
320     * NULL. We achieve this by checking whether the preprocessor macro
321     * NOCHECK_$name is defined. SWIG replaces $name with the name of the
322     * function for which the code is inserted. In the %{,%}-block below we
323     * define the macros for the destructor and the close() method.
324     */
325    
326     %typemap(python,check) DBFFile *{
327     %#ifndef NOCHECK_$name
328     if (!$target || !$target->handle)
329     SWIG_exception(SWIG_TypeError, "dbffile already closed");
330     %#endif
331     }
332    
333     %{
334     #define NOCHECK_delete_DBFFile
335     #define NOCHECK_DBFFile_close
336     %}
337    
338    
339     /* An exception handle for the constructor and the module level open()
340     * and create() functions.
341     *
342     * Annoyingly, we *have* to put braces around the SWIG_exception()
343     * calls, at least in the python case, because of the way the macro is
344     * written. Of course, always putting braces around the branches of an
345     * if-statement is often considered good practice.
346     */
347     %typemap(python,except) DBFFile * {
348     $function;
349     if (!$source)
350     {
351     SWIG_exception(SWIG_MemoryError, "no memory");
352     }
353     else if (!$source->handle)
354     {
355     SWIG_exception(SWIG_IOError, "$name failed");
356     }
357     }
358    
359 bh 1761 /* Exception handler for the add_field method */
360     %typemap(python,except) int DBFFile_add_field {
361     $function;
362     if ($source < 0)
363     {
364     SWIG_exception(SWIG_RuntimeError, "add_field failed");
365     }
366     }
367 jan 1611
368     /* define and use some typemaps for the field_info() method whose
369     * C-implementation has three output parameters that are returned
370     * through pointers passed into the function. SWIG already has
371     * definitions for common types such as int* and we can use those for
372     * the last two parameters:
373     */
374    
375     %apply int * OUTPUT { int * output_width }
376     %apply int * OUTPUT { int * output_decimals }
377    
378     /* the fieldname has to be defined manually: */
379     %typemap(python,ignore) char *fieldname_out(char temp[12]) {
380     $target = temp;
381     }
382    
383     %typemap(python,argout) char *fieldname_out() {
384     PyObject * string = PyString_FromString($source);
385     $target = t_output_helper($target,string);
386     }
387    
388    
389    
390     /*
391     * The SWIG-version of the DBFFile struct
392     */
393    
394     typedef struct
395     {
396     %addmethods {
397     DBFFile(const char *file, const char * mode = "rb") {
398     DBFFile * self = malloc(sizeof(DBFFile));
399     if (self)
400     self->handle = DBFOpen(file, mode);
401     return self;
402     }
403    
404     ~DBFFile() {
405     if (self->handle)
406     DBFClose(self->handle);
407     free(self);
408     }
409    
410     void close() {
411     if (self->handle)
412     DBFClose(self->handle);
413     self->handle = NULL;
414     }
415    
416     int field_count() {
417     return DBFGetFieldCount(self->handle);
418     }
419    
420     int record_count() {
421     return DBFGetRecordCount(self->handle);
422     }
423    
424     int field_info(int iField, char * fieldname_out,
425     int * output_width, int * output_decimals) {
426     return DBFGetFieldInfo(self->handle, iField, fieldname_out,
427     output_width, output_decimals);
428     }
429    
430     PyObject * read_record(int record) {
431     return DBFInfo_read_record(self->handle, record);
432     }
433    
434     int add_field(const char * pszFieldName, DBFFieldType eType,
435     int nWidth, int nDecimals) {
436     return DBFAddField(self->handle, pszFieldName, eType, nWidth,
437     nDecimals);
438     }
439    
440     PyObject *write_record(int record, PyObject *dict_or_sequence) {
441     return DBFInfo_write_record(self->handle, record,
442     dict_or_sequence);
443     }
444    
445     int commit() {
446     return DBFCommit(self->handle);
447     }
448    
449     }
450     } DBFFile;
451    
452    
453     /*
454     * Two module level functions, open() and create() that correspond to
455     * DBFOpen and DBFCreate respectively. open() is equivalent to the
456     * DBFFile constructor.
457     */
458    
459    
460     %{
461     DBFFile * open_DBFFile(const char * file, const char * mode)
462     {
463     DBFFile * self = malloc(sizeof(DBFFile));
464     if (self)
465     self->handle = DBFOpen(file, mode);
466     return self;
467     }
468     %}
469    
470     %name(open) %new DBFFile * open_DBFFile(const char * file,
471     const char * mode = "rb");
472    
473     %{
474     DBFFile * create_DBFFile(const char * file)
475     {
476     DBFFile * self = malloc(sizeof(DBFFile));
477     if (self)
478     self->handle = DBFCreate(file);
479     return self;
480     }
481     %}
482     %name(create) %new DBFFile * create_DBFFile(const char * file);
483    
484    
485    
486     /* constant definitions copied from shapefil.h */
487     typedef enum {
488     FTString,
489     FTInteger,
490     FTDouble,
491     FTInvalid
492     } DBFFieldType;

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26