/[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 1917 - (show annotations)
Mon Nov 3 17:31:11 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/libraries/pyshapelib/dbflib.i
File size: 13922 byte(s)
* dbflib.i (do_read_attribute): New helper function for reading
one attribute as a python object
(DBFInfo_read_attribute): New. Implement the read_attribute method
(DBFInfo_read_record): Use do_read_attribute to read the
individual values
(struct DBFFile): Add the read_attribute method.

* dbflib_wrap.c, dbflib.py: Update from dbflib.i.

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 /*
349 * The SWIG Interface definition.
350 */
351
352 /* include some common SWIG type definitions and standard exception
353 handling code */
354 %include typemaps.i
355 %include exception.i
356
357 /* As for ShapeFile in shapelib.i, We define a new C-struct that holds
358 * the DBFHandle. This is mainly done so we can separate the close()
359 * method from the destructor but it also helps with exception handling.
360 *
361 * After the DBFFile has been opened or created the handle is not NULL.
362 * The close() method closes the file and sets handle to NULL as an
363 * indicator that the file has been closed.
364 */
365
366 %{
367 typedef struct {
368 DBFHandle handle;
369 } DBFFile;
370 %}
371
372
373 /* The first argument to the DBFFile methods is a DBFFile pointer.
374 * We have to check whether handle is not NULL in most methods but not
375 * all. In the destructor and the close method, it's OK for handle to be
376 * NULL. We achieve this by checking whether the preprocessor macro
377 * NOCHECK_$name is defined. SWIG replaces $name with the name of the
378 * function for which the code is inserted. In the %{,%}-block below we
379 * define the macros for the destructor and the close() method.
380 */
381
382 %typemap(python,check) DBFFile *{
383 %#ifndef NOCHECK_$name
384 if (!$target || !$target->handle)
385 SWIG_exception(SWIG_TypeError, "dbffile already closed");
386 %#endif
387 }
388
389 %{
390 #define NOCHECK_delete_DBFFile
391 #define NOCHECK_DBFFile_close
392 %}
393
394
395 /* An exception handle for the constructor and the module level open()
396 * and create() functions.
397 *
398 * Annoyingly, we *have* to put braces around the SWIG_exception()
399 * calls, at least in the python case, because of the way the macro is
400 * written. Of course, always putting braces around the branches of an
401 * if-statement is often considered good practice.
402 */
403 %typemap(python,except) DBFFile * {
404 $function;
405 if (!$source)
406 {
407 SWIG_exception(SWIG_MemoryError, "no memory");
408 }
409 else if (!$source->handle)
410 {
411 SWIG_exception(SWIG_IOError, "$name failed");
412 }
413 }
414
415 /* Exception handler for the add_field method */
416 %typemap(python,except) int DBFFile_add_field {
417 $function;
418 if ($source < 0)
419 {
420 SWIG_exception(SWIG_RuntimeError, "add_field failed");
421 }
422 }
423
424 /* define and use some typemaps for the field_info() method whose
425 * C-implementation has three output parameters that are returned
426 * through pointers passed into the function. SWIG already has
427 * definitions for common types such as int* and we can use those for
428 * the last two parameters:
429 */
430
431 %apply int * OUTPUT { int * output_width }
432 %apply int * OUTPUT { int * output_decimals }
433
434 /* the fieldname has to be defined manually: */
435 %typemap(python,ignore) char *fieldname_out(char temp[12]) {
436 $target = temp;
437 }
438
439 %typemap(python,argout) char *fieldname_out() {
440 PyObject * string = PyString_FromString($source);
441 $target = t_output_helper($target,string);
442 }
443
444
445
446 /*
447 * The SWIG-version of the DBFFile struct
448 */
449
450 typedef struct
451 {
452 %addmethods {
453 DBFFile(const char *file, const char * mode = "rb") {
454 DBFFile * self = malloc(sizeof(DBFFile));
455 if (self)
456 self->handle = DBFOpen(file, mode);
457 return self;
458 }
459
460 ~DBFFile() {
461 if (self->handle)
462 DBFClose(self->handle);
463 free(self);
464 }
465
466 void close() {
467 if (self->handle)
468 DBFClose(self->handle);
469 self->handle = NULL;
470 }
471
472 int field_count() {
473 return DBFGetFieldCount(self->handle);
474 }
475
476 int record_count() {
477 return DBFGetRecordCount(self->handle);
478 }
479
480 int field_info(int iField, char * fieldname_out,
481 int * output_width, int * output_decimals) {
482 return DBFGetFieldInfo(self->handle, iField, fieldname_out,
483 output_width, output_decimals);
484 }
485
486 PyObject * read_record(int record) {
487 return DBFInfo_read_record(self->handle, record);
488 }
489
490 PyObject * read_attribute(int record, int field) {
491 return DBFInfo_read_attribute(self->handle, record, field);
492 }
493
494 int add_field(const char * pszFieldName, DBFFieldType eType,
495 int nWidth, int nDecimals) {
496 return DBFAddField(self->handle, pszFieldName, eType, nWidth,
497 nDecimals);
498 }
499
500 PyObject *write_record(int record, PyObject *dict_or_sequence) {
501 return DBFInfo_write_record(self->handle, record,
502 dict_or_sequence);
503 }
504
505 int commit() {
506 return DBFCommit(self->handle);
507 }
508
509 }
510 } DBFFile;
511
512
513 /*
514 * Two module level functions, open() and create() that correspond to
515 * DBFOpen and DBFCreate respectively. open() is equivalent to the
516 * DBFFile constructor.
517 */
518
519
520 %{
521 DBFFile * open_DBFFile(const char * file, const char * mode)
522 {
523 DBFFile * self = malloc(sizeof(DBFFile));
524 if (self)
525 self->handle = DBFOpen(file, mode);
526 return self;
527 }
528 %}
529
530 %name(open) %new DBFFile * open_DBFFile(const char * file,
531 const char * mode = "rb");
532
533 %{
534 DBFFile * create_DBFFile(const char * file)
535 {
536 DBFFile * self = malloc(sizeof(DBFFile));
537 if (self)
538 self->handle = DBFCreate(file);
539 return self;
540 }
541 %}
542 %name(create) %new DBFFile * create_DBFFile(const char * file);
543
544
545
546 /* constant definitions copied from shapefil.h */
547 typedef enum {
548 FTString,
549 FTInteger,
550 FTDouble,
551 FTInvalid
552 } DBFFieldType;

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26