/[thuban]/branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflibmodule.c
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflibmodule.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2734 - (show annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
Original Path: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflib.i
File size: 15212 byte(s)
made a copy
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
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 /* 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 value = do_read_attribute(handle, record, i, name);
161 if (!value)
162 goto fail;
163
164 PyDict_SetItemString(dict, name, value);
165 Py_DECREF(value);
166 }
167
168 return dict;
169
170 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 /* 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 /*
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 /* 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
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 PyObject * read_attribute(int record, int field) {
510 return DBFInfo_read_attribute(self->handle, record, field);
511 }
512
513 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 void commit() {
525 DBFInfo_commit(self->handle);
526 }
527 /* 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
532 /* The __del__ method generated by the old SWIG version we're
533 * tries to access self.thisown which may not be set at all when
534 * there was an exception during construction. Therefore we
535 * override it with our own version.
536 * FIXME: It would be better to upgrade to a newer SWIG version
537 * or to get rid of SWIG entirely.
538 */
539 %pragma(python) addtoclass = "
540 def __del__(self,dbflibc=dbflibc):
541 if getattr(self, 'thisown', 0):
542 dbflibc.delete_DBFFile(self)
543 "
544
545
546 }
547 } DBFFile;
548
549
550 /*
551 * Two module level functions, open() and create() that correspond to
552 * DBFOpen and DBFCreate respectively. open() is equivalent to the
553 * DBFFile constructor.
554 */
555
556
557 %{
558 DBFFile * open_DBFFile(const char * file, const char * mode)
559 {
560 DBFFile * self = malloc(sizeof(DBFFile));
561 if (self)
562 self->handle = DBFOpen(file, mode);
563 return self;
564 }
565 %}
566
567 %name(open) %new DBFFile * open_DBFFile(const char * file,
568 const char * mode = "rb");
569
570 %{
571 DBFFile * create_DBFFile(const char * file)
572 {
573 DBFFile * self = malloc(sizeof(DBFFile));
574 if (self)
575 self->handle = DBFCreate(file);
576 return self;
577 }
578 %}
579 %name(create) %new DBFFile * create_DBFFile(const char * file);
580
581
582
583 /* constant definitions copied from shapefil.h */
584 typedef enum {
585 FTString,
586 FTInteger,
587 FTDouble,
588 FTInvalid
589 } DBFFieldType;
590
591
592 /* Put the value of the HAVE_UPDATE_HEADER preprocessor macro into the
593 * wrapper so that the __class__ pragma above knows when to remove the
594 * commit method
595 */
596 const int _have_commit = HAVE_UPDATE_HEADER;
597

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26