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 |
|
|
|
360 |
|
|
/* define and use some typemaps for the field_info() method whose |
361 |
|
|
* C-implementation has three output parameters that are returned |
362 |
|
|
* through pointers passed into the function. SWIG already has |
363 |
|
|
* definitions for common types such as int* and we can use those for |
364 |
|
|
* the last two parameters: |
365 |
|
|
*/ |
366 |
|
|
|
367 |
|
|
%apply int * OUTPUT { int * output_width } |
368 |
|
|
%apply int * OUTPUT { int * output_decimals } |
369 |
|
|
|
370 |
|
|
/* the fieldname has to be defined manually: */ |
371 |
|
|
%typemap(python,ignore) char *fieldname_out(char temp[12]) { |
372 |
|
|
$target = temp; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
%typemap(python,argout) char *fieldname_out() { |
376 |
|
|
PyObject * string = PyString_FromString($source); |
377 |
|
|
$target = t_output_helper($target,string); |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
|
381 |
|
|
|
382 |
|
|
/* |
383 |
|
|
* The SWIG-version of the DBFFile struct |
384 |
|
|
*/ |
385 |
|
|
|
386 |
|
|
typedef struct |
387 |
|
|
{ |
388 |
|
|
%addmethods { |
389 |
|
|
DBFFile(const char *file, const char * mode = "rb") { |
390 |
|
|
DBFFile * self = malloc(sizeof(DBFFile)); |
391 |
|
|
if (self) |
392 |
|
|
self->handle = DBFOpen(file, mode); |
393 |
|
|
return self; |
394 |
|
|
} |
395 |
|
|
|
396 |
|
|
~DBFFile() { |
397 |
|
|
if (self->handle) |
398 |
|
|
DBFClose(self->handle); |
399 |
|
|
free(self); |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
void close() { |
403 |
|
|
if (self->handle) |
404 |
|
|
DBFClose(self->handle); |
405 |
|
|
self->handle = NULL; |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
int field_count() { |
409 |
|
|
return DBFGetFieldCount(self->handle); |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
int record_count() { |
413 |
|
|
return DBFGetRecordCount(self->handle); |
414 |
|
|
} |
415 |
|
|
|
416 |
|
|
int field_info(int iField, char * fieldname_out, |
417 |
|
|
int * output_width, int * output_decimals) { |
418 |
|
|
return DBFGetFieldInfo(self->handle, iField, fieldname_out, |
419 |
|
|
output_width, output_decimals); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
PyObject * read_record(int record) { |
423 |
|
|
return DBFInfo_read_record(self->handle, record); |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
int add_field(const char * pszFieldName, DBFFieldType eType, |
427 |
|
|
int nWidth, int nDecimals) { |
428 |
|
|
return DBFAddField(self->handle, pszFieldName, eType, nWidth, |
429 |
|
|
nDecimals); |
430 |
|
|
} |
431 |
|
|
|
432 |
|
|
PyObject *write_record(int record, PyObject *dict_or_sequence) { |
433 |
|
|
return DBFInfo_write_record(self->handle, record, |
434 |
|
|
dict_or_sequence); |
435 |
|
|
} |
436 |
|
|
|
437 |
|
|
int commit() { |
438 |
|
|
return DBFCommit(self->handle); |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
} |
442 |
|
|
} DBFFile; |
443 |
|
|
|
444 |
|
|
|
445 |
|
|
/* |
446 |
|
|
* Two module level functions, open() and create() that correspond to |
447 |
|
|
* DBFOpen and DBFCreate respectively. open() is equivalent to the |
448 |
|
|
* DBFFile constructor. |
449 |
|
|
*/ |
450 |
|
|
|
451 |
|
|
|
452 |
|
|
%{ |
453 |
|
|
DBFFile * open_DBFFile(const char * file, const char * mode) |
454 |
|
|
{ |
455 |
|
|
DBFFile * self = malloc(sizeof(DBFFile)); |
456 |
|
|
if (self) |
457 |
|
|
self->handle = DBFOpen(file, mode); |
458 |
|
|
return self; |
459 |
|
|
} |
460 |
|
|
%} |
461 |
|
|
|
462 |
|
|
%name(open) %new DBFFile * open_DBFFile(const char * file, |
463 |
|
|
const char * mode = "rb"); |
464 |
|
|
|
465 |
|
|
%{ |
466 |
|
|
DBFFile * create_DBFFile(const char * file) |
467 |
|
|
{ |
468 |
|
|
DBFFile * self = malloc(sizeof(DBFFile)); |
469 |
|
|
if (self) |
470 |
|
|
self->handle = DBFCreate(file); |
471 |
|
|
return self; |
472 |
|
|
} |
473 |
|
|
%} |
474 |
|
|
%name(create) %new DBFFile * create_DBFFile(const char * file); |
475 |
|
|
|
476 |
|
|
|
477 |
|
|
|
478 |
|
|
/* constant definitions copied from shapefil.h */ |
479 |
|
|
typedef enum { |
480 |
|
|
FTString, |
481 |
|
|
FTInteger, |
482 |
|
|
FTDouble, |
483 |
|
|
FTInvalid |
484 |
|
|
} DBFFieldType; |