/[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 2212 - (hide annotations)
Mon May 17 15:47:57 2004 UTC (20 years, 9 months ago) by bh
Original Path: trunk/thuban/libraries/pyshapelib/dbflib.i
File size: 14717 byte(s)
Update to newest shapelib and get rid of Thuban specific extensions,
i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge

* libraries/shapelib/shpopen.c: Update to version from current
shapelib CVS.

* libraries/shapelib/shapefil.h: Update to version from current
shapelib CVS.

* libraries/shapelib/dbfopen.c: Update to version from current
shapelib CVS.
(DBFCommit): Effectively removed since shapelib itself has
DBFUpdateHeader now which is better for what DBFCommit wanted to
achieve.
We're now using an unmodified version of dbfopen.

* libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
Update from dbflib.i

* libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
the commit method.  This new indirection is necessary because we use the
DBFUpdateHeader function now which is not available in shapelib <=
1.2.10
(DBFFile::commit): Use DBFInfo_commit as implementation
(pragma __class__): New. Kludge to remove the commit method when
the DBFUpdateHeader function isn't available
(_have_commit): New. Helper for the pragma kludge.

* libraries/pyshapelib/setup.py (dbf_macros): New. Return the
preprocessor macros needed to compile the dbflib wrapper.  Determine
whether DBFUpdateHeader is available and define the right value of
HAVE_UPDATE_HEADER
(extensions): Use dbf_macros for the dbflibc extension

* setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
value '1' to the Lib.dbflibc extension.  This simply reflects the
shapelib and pyshapelib updates

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26