1 |
/* 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 |
/* 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 |
|
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; |