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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/thuban/libraries/pyshapelib/dbflib.i revision 1761 by bh, Mon Sep 29 10:52:22 2003 UTC branches/WIP-pyshapelib-bramz/libraries/pyshapelib/dbflibmodule.c revision 2754 by bramz, Wed Apr 11 19:04:12 2007 UTC
# Line 1  Line 1 
1  /* SWIG (www.swig.org) interface file for the dbf interface of shapelib  /* Copyright (c) 2001, 2002, 2007 by Intevation GmbH
2     * Authors:
3     * Bram de Greve <[email protected]>
4     * Bernhard Herzog <[email protected]>
5   *   *
6   * At the moment (Dec 2000) this file is only useful to generate Python   * This program is free software under the GPL (>=v2)
7   * bindings. Invoke swig as follows:   * Read the file COPYING coming with Thuban for details.
8     */
9    
10    #include "pyshapelib_common.h"
11    
12    /* UNICODE & LANGUAGE DRIVER SUPPORT FOR DBFLIB
13   *   *
14   *      swig -python -shadow dbflib.i   * When writing Unicode objects to a dbflib database, the unicode has to be
15     * encoded in 8-bit characters using a code page.  This code page is indentified
16     * by the Language Driver ID (LDID) field in the database header.
17   *   *
18   * to generate dbflib_wrap.c and dbflib.py. dbflib_wrap.c defines a   * At this moment, this need unofficial modifications of the maptools shapelib
19   * bunch of Python-functions that wrap the appripriate dbflib functions   * library because they do not read the LDID.  No patch has been submitted yet,
20   * and dbflib.py contains an object oriented wrapper around   * but the version contained in the Thuban source tree incorporates the required
21   * dbflib_wrap.c.   * modifications.
22   *   *
23   * This module defines one object type: DBFFile.   * pyshapelib is designed to compile with either the patched or unpatched shapelib
24     * by defining HAVE_LANGUAGE_DRIVER as true or false respectively.  In the latter
25     * case, a Windows ANSI code page (cp1252) is assumed
26   */   */
27     #if HAVE_LANGUAGE_DRIVER
28    
29    #define PYSHAPELIB_NUM_LANGUAGE_DRIVERS 256
30    
31    #define PYSHAPELIB_ADD_LANGUAGE_DRIVER(ldid, codec, name)\
32            codecs[ldid] = codec;\
33            drivers[ldid] = "LDID_" name;\
34            PyModule_AddIntConstant(module, "LDID_" name, ldid)
35    
36    static char* codecs[PYSHAPELIB_NUM_LANGUAGE_DRIVERS];
37    static char* drivers[PYSHAPELIB_NUM_LANGUAGE_DRIVERS];
38    
39    #endif
40    
41    
 /* this is the dbflib module */  
 %module dbflib  
42    
43  /* first a %{,%} block. These blocks are copied verbatim to the  /** Determine name of Python's built-in codec
  * dbflib_wrap.c file and are not parsed by SWIG. This is the place to  
  * import headerfiles and define helper-functions that are needed by the  
  * automatically generated wrappers.  
44   */   */
45    static char* get_codec(DBFHandle handle)
46    {
47    #if HAVE_LANGUAGE_DRIVER
48            if (!codecs[handle->nLanguageDriver])
49            {
50                    PyErr_Format(PyExc_ValueError, "Language Driver ID %d not recognized", handle->nLanguageDriver);
51            }
52            return codecs[handle->nLanguageDriver];
53    #else
54            return "cp1252";
55    #endif
56    }
57    
 %{  
 #include "shapefil.h"  
58    
59  /* the read_record method. Return the record record as a dictionary with  
60   * whose keys are the names of the fields, and their values as the  /** decode to unicode object
  * appropriate Python type.  
  *  
  * In case of error, set a python exception and return NULL. Since that  
  * value will be returned to the python interpreter as is, the  
  * interpreter should recognize the exception.  
61   */   */
62    static PyObject* decode_string(DBFHandle handle, const char* string)
63    {
64            char* codec = get_codec(handle);
65            if (!codec) return NULL;
66            return PyUnicode_Decode(string, strlen(string), codec, NULL);
67    }
68    
69  static PyObject *  /** encode unicode object to normal Python string object
70  DBFInfo_read_record(DBFInfo * handle, int record)   */
71    static PyObject* encode_string(DBFHandle handle, PyObject* string)
72  {  {
73      int num_fields;          char* codec = get_codec(handle);
74      int i;          if (!codec) return NULL;
75      int type, width;  
76      char name[12];          if (PyString_Check(string))
77      PyObject *dict;          {
78      PyObject *value;                  return PyString_AsEncodedObject(string, codec, NULL);
79            }
80      if (record < 0 || record >= DBFGetRecordCount(handle))          if (PyUnicode_Check(string))
81      {          {
82          PyErr_Format(PyExc_ValueError,                  return PyUnicode_AsEncodedString(string, codec, NULL);
83                       "record index %d out of bounds (record count: %d)",          }
                      record, DBFGetRecordCount(handle));  
         return NULL;  
     }  
84    
85      dict = PyDict_New();          PyErr_SetString(PyExc_TypeError, "value is neither a string or unicode object");
     if (!dict)  
86          return NULL;          return NULL;
87    }
88    
89    
90    
91    /* --- DBFFile ------------------------------------------------------------------------------------------------------- */
92    
93    typedef struct {
94            PyObject_HEAD
95            DBFHandle handle;
96    } DBFFileObject;
97    
98    
99    
100    /* allocator
101    */
102    static PyObject* dbffile_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
103    {
104            DBFFileObject* self;    
105            self = (DBFFileObject*) type->tp_alloc(type, 0);
106            self->handle = NULL;
107            return (PyObject*) self;
108    }
109    
110    
111    
112    /* deallocator
113    */
114    static void dbffile_dealloc(DBFFileObject* self)
115    {
116            DBFClose(self->handle);
117            self->handle = NULL;
118            self->ob_type->tp_free((PyObject*)self);
119    }
120    
121    
122    
123    /* constructor
124    */
125    static int dbffile_init(DBFFileObject* self, PyObject* args, PyObject* kwds)
126    {
127            char* file = NULL;
128            char* mode = "rb";
129            static char *kwlist[] = {"name", "mode", NULL};
130    
131            DBFClose(self->handle);
132            self->handle = NULL;
133    
134    #if defined(SHPAPI_HAS_WIDE) && defined(Py_WIN_WIDE_FILENAMES)
135            if (GetVersion() < 0x80000000) {    /* On NT, so wide API available */
136                    PyObject *wfile;
137                    if (PyArg_ParseTupleAndKeywords(args, kwds, "U|s:DBFFile", kwlist, &wfile, &mode))
138                    {
139                            PyObject *wmode = PyUnicode_DecodeASCII(mode, strlen(mode), NULL);
140                            if (!wmode) return -1;
141                            self->handle = DBFOpenW(PyUnicode_AS_UNICODE(wfile), PyUnicode_AS_UNICODE(wmode));
142                            Py_DECREF(wmode);
143                            if (!self->handle)
144                            {
145                                    PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, wfile);
146                                    return -1;
147                            }
148                    }
149                    else
150                    {
151                            /* Drop the argument parsing error as narrow
152                               strings are also valid. */
153                            PyErr_Clear();
154                    }
155            }
156    #endif
157    
158            if (!self->handle)
159            {
160                    if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|s:DBFFile", kwlist,
161                            Py_FileSystemDefaultEncoding, &file, &mode)) return -1;
162                    self->handle = DBFOpen(file, mode);
163    
164                    if (!self->handle)
165                    {
166                            PyErr_SetFromErrnoWithFilename(PyExc_IOError, file);
167                            PyMem_Free(file);
168                            return -1;
169                    }
170    
171                    PyMem_Free(file);
172            }
173    
174            return 0;
175    }
176    
177    
178    
179    static PyObject* dbffile_close(DBFFileObject* self)
180    {
181            DBFClose(self->handle);
182            self->handle = NULL;
183            Py_RETURN_NONE;
184    }
185    
186    
187    
188    static PyObject* dbffile_field_count(DBFFileObject* self)
189    {
190            return PyInt_FromLong((long)DBFGetFieldCount(self->handle));
191    }
192    
193    
194    
195    static PyObject* dbffile_record_count(DBFFileObject* self)
196    {
197            return PyInt_FromLong((long)DBFGetRecordCount(self->handle));
198    }
199    
200    
201    
202    static PyObject* dbffile_field_info(DBFFileObject* self, PyObject* args)
203    {
204            char field_name[12];
205            int field, width = 0, decimals = 0, field_type;
206            PyObject* name_object = NULL;
207            
208            if (!PyArg_ParseTuple(args, "i:field_info", &field)) return NULL;
209            
210            field_name[0] = '\0';
211            field_type = DBFGetFieldInfo(self->handle, field, field_name, &width, &decimals);
212            name_object = decode_string(self->handle, field_name);
213            
214            return Py_BuildValue("iOii", field_type, name_object, width, decimals);
215    }
216    
217    
218    
219    static PyObject* dbffile_add_field(DBFFileObject* self, PyObject* args)
220    {
221            PyObject *oname = NULL, *name = NULL;
222            int type, width, decimals;
223            int field;
224            
225            if (!PyArg_ParseTuple(args, "Uiii:add_field", &oname, &type, &width, &decimals))
226            {
227                    PyErr_Clear();
228                    if (!PyArg_ParseTuple(args, "Siii:add_field", &oname, &type, &width, &decimals)) return NULL;
229            }
230            
231            name = encode_string(self->handle, oname);
232            if (!name) return NULL;
233    
234            field = DBFAddField(self->handle, PyString_AsString(name), (DBFFieldType)type, width, decimals);
235            Py_DECREF(name);
236            
237            if (field < 0)
238            {
239                    PyErr_SetString(PyExc_ValueError, "Failed to add field due to inappropriate field definition");
240                    return NULL;
241            }
242            return PyInt_FromLong((long)field);
243    }
244    
245    
246    
247    /* Read one attribute from the dbf handle and return it as a new python object
248    *
249    * If an error occurs, set the appropriate Python exception and return
250    * NULL.
251    *
252    * Assume that the values of the record and field arguments are valid.
253    * The name argument will be passed to DBFGetFieldInfo as is and should
254    * thus be either NULL or a pointer to an array of at least 12 chars
255    */
256    static PyObject* do_read_attribute(DBFHandle handle, int record, int field, char * name)
257    {
258            int type, width;
259            const char* string;
260            type = DBFGetFieldInfo(handle, field, name, &width, NULL);
261                    
     num_fields = DBFGetFieldCount(handle);  
     for (i = 0; i < num_fields; i++)  
     {  
         type = DBFGetFieldInfo(handle, i, name, &width, NULL);  
262          /* For strings NULL and the empty string are indistinguishable          /* For strings NULL and the empty string are indistinguishable
263           * in DBF files. We prefer empty strings instead for backwards          * in DBF files. We prefer empty strings instead for backwards
264           * compatibility reasons because older wrapper versions returned          * compatibility reasons because older wrapper versions returned
265           * emtpy strings as empty strings.          * emtpy strings as empty strings.
266           */          */
267          if (type != FTString && DBFIsAttributeNULL(handle, record, i))          if (type != FTString && DBFIsAttributeNULL(handle, record, field))
268          {          {
269              value = Py_None;                  Py_RETURN_NONE;
             Py_INCREF(value);  
270          }          }
271          else          else
272          {          {
273              switch (type)                  switch (type)
             {  
             case FTString:  
             {  
                 const char * temp = DBFReadStringAttribute(handle, record, i);  
                 if (temp)  
274                  {                  {
275                      value = PyString_FromString(temp);                  case FTString:
276                            string = DBFReadStringAttribute(handle, record, field);
277                            if (string) return decode_string(handle, string);
278    
279                    case FTInteger:
280                            return PyInt_FromLong((long)DBFReadIntegerAttribute(handle, record, field));
281    
282                    case FTDouble:
283                            return PyFloat_FromDouble(DBFReadDoubleAttribute(handle, record, field));
284                            
285                    case FTLogical:
286                            string = DBFReadLogicalAttribute(handle, record, field);
287                            if (string)
288                            {
289                                    switch (string[0])
290                                    {
291                                    case 'F':
292                                    case 'N':
293                                            Py_RETURN_FALSE;
294                                    case 'T':
295                                    case 'Y':
296                                            Py_RETURN_TRUE;
297                                    }
298                            }
299                            break;
300    
301                    default:
302                            PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
303                            return NULL;
304                  }                  }
                 else  
                 {  
                     PyErr_Format(PyExc_IOError,  
                                  "Can't read value for row %d column %d",  
                                  record, i);  
                     value = NULL;  
                 }  
                 break;  
             }  
             case FTInteger:  
                 value = PyInt_FromLong(DBFReadIntegerAttribute(handle, record,  
                                                                i));  
                 break;  
             case FTDouble:  
                 value = PyFloat_FromDouble(DBFReadDoubleAttribute(handle,  
                                                                   record, i));  
                 break;  
             default:  
                 PyErr_Format(PyExc_TypeError, "Invalid field data type %d",  
                              type);  
                 value = NULL;  
             }  
305          }          }
306          if (!value)          
307              goto fail;          PyErr_Format(PyExc_IOError,     "Can't read value for row %d column %d", record, field);
308          PyDict_SetItemString(dict, name, value);          return NULL;
309          Py_DECREF(value);  }    
310      }  
311    
312      return dict;  
313   fail:  /* the read_attribute method. Return the value of the given record and
314      Py_XDECREF(dict);  * field as a python object of the appropriate type.
315      return NULL;  */
316    static PyObject* dbffile_read_attribute(DBFFileObject* self, PyObject* args)
317    {
318            int record, field;
319    
320            if (!PyArg_ParseTuple(args, "ii:read_field", &record, &field)) return NULL;
321            
322            if (record < 0 || record >= DBFGetRecordCount(self->handle))
323            {
324                    PyErr_Format(PyExc_ValueError,
325                                    "record index %d out of bounds (record count: %d)",
326                                    record, DBFGetRecordCount(self->handle));
327                    return NULL;
328            }
329    
330            if (field < 0 || field >= DBFGetFieldCount(self->handle))
331            {
332                    PyErr_Format(PyExc_ValueError,
333                                    "field index %d out of bounds (field count: %d)",
334                                    field, DBFGetFieldCount(self->handle));
335                    return NULL;
336            }
337    
338            return do_read_attribute(self->handle, record, field, NULL);
339  }  }
340    
 /* the write_record method. Write the record record given wither as a  
  * dictionary or a sequence (i.e. a list or a tuple).  
  *  
  * If it's a dictionary the keys must be the names of the fields and  
  * their value must have a suitable type. Only the fields actually  
  * contained in the dictionary are written. Fields for which there's no  
  * item in the dict are not modified.  
  *  
  * If it's a sequence, all fields must be present in the right order.  
  *  
  * In case of error, set a python exception and return NULL. Since that  
  * value will be returned to the python interpreter as is, the  
  * interpreter should recognize the exception.  
  *  
  * The method is implemented with two c-functions, write_field to write  
  * a single field and DBFInfo_write_record as the front-end.  
  */  
341    
342    
343  /* write a single field of a record. */  /* the read_record method. Return the record record as a dictionary with
344  static int  * whose keys are the names of the fields, and their values as the
345  write_field(DBFHandle handle, int record, int field, int type,  * appropriate Python type.
346              PyObject * value)  */
347  {  static PyObject* dbffile_read_record(DBFFileObject* self, PyObject* args)
348      char * string_value;  {
349      int int_value;          int record;
350      double double_value;          int num_fields;
351            int i;
352      if (value == Py_None)          char name[12];
353      {          PyObject *dict;
354          if (!DBFWriteNULLAttribute(handle, record, field))          PyObject *value = NULL;
355          {  
356              PyErr_Format(PyExc_IOError,          if (!PyArg_ParseTuple(args, "i:read_record", &record)) return NULL;
357                           "can't write NULL field %d of record %d",  
358                           field, record);          if (record < 0 || record >= DBFGetRecordCount(self->handle))
             return 0;  
         }  
     }  
     else  
     {  
         switch (type)  
         {  
         case FTString:  
             string_value = PyString_AsString(value);  
             if (!string_value)  
                 return 0;  
             if (!DBFWriteStringAttribute(handle, record, field, string_value))  
             {  
                 PyErr_Format(PyExc_IOError,  
                              "can't write field %d of record %d",  
                              field, record);  
                 return 0;  
             }  
             break;  
   
         case FTInteger:  
             int_value = PyInt_AsLong(value);  
             if (int_value == -1 && PyErr_Occurred())  
                 return 0;  
             if (!DBFWriteIntegerAttribute(handle, record, field, int_value))  
             {  
                 PyErr_Format(PyExc_IOError,  
                              "can't write field %d of record %d",  
                              field, record);  
                 return 0;  
             }  
             break;  
   
         case FTDouble:  
             double_value = PyFloat_AsDouble(value);  
             if (double_value == -1 && PyErr_Occurred())  
                 return 0;  
             if (!DBFWriteDoubleAttribute(handle, record, field, double_value))  
             {  
                 PyErr_Format(PyExc_IOError,  
                              "can't write field %d of record %d",  
                              field, record);  
                 return 0;  
             }  
             break;  
   
         default:  
             PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);  
             return 0;  
         }  
     }  
   
     return 1;  
 }  
   
 static  
 PyObject *  
 DBFInfo_write_record(DBFHandle handle, int record, PyObject *record_object)  
 {  
     int num_fields;  
     int i, length;  
     int type, width;  
     char name[12];  
     PyObject * value = NULL;  
   
     num_fields = DBFGetFieldCount(handle);  
   
     /* We used to use PyMapping_Check to test whether record_object is a  
      * dictionary like object instead of PySequence_Check to test  
      * whether it's a sequence. Unfortunately in Python 2.3  
      * PyMapping_Check returns true for lists and tuples too so the old  
      * approach doesn't work anymore.  
      */  
     if (PySequence_Check(record_object))  
     {  
         /* It's a sequence object. Iterate through all items in the  
          * sequence and write them to the appropriate field.  
          */  
         length = PySequence_Length(record_object);  
         if (length != num_fields)  
359          {          {
360              PyErr_SetString(PyExc_TypeError,                  PyErr_Format(PyExc_ValueError,
361                              "record must have one item for each field");                          "record index %d out of bounds (record count: %d)",
362              goto fail;                          record, DBFGetRecordCount(self->handle));
363          }                  return NULL;
364          for (i = 0; i < length; i++)          }
365          {  
366              type = DBFGetFieldInfo(handle, i, name, &width, NULL);          dict = PyDict_New();
367              value = PySequence_GetItem(record_object, i);          if (!dict) return NULL;
368              if (value)          
369              {          num_fields = DBFGetFieldCount(self->handle);
                 if (!write_field(handle, record, i, type, value))  
                     goto fail;  
                 Py_DECREF(value);  
             }  
             else  
             {  
                 goto fail;  
             }  
         }  
     }  
     else  
     {  
         /* It's a dictionary-like object. Iterate over the names of the  
          * known fields and write the corresponding item  
          */  
370          for (i = 0; i < num_fields; i++)          for (i = 0; i < num_fields; i++)
371          {          {
372              type = DBFGetFieldInfo(handle, i, name, &width, NULL);                  value = do_read_attribute(self->handle, record, i, name);
373                    if (!value || PyDict_SetItemString(dict, name, value) < 0) goto fail;
             /* if the dictionary has the key name write that object to  
              * the appropriate field, other wise just clear the python  
              * exception and do nothing.  
              */  
             value = PyMapping_GetItemString(record_object, name);  
             if (value)  
             {  
                 if (!write_field(handle, record, i, type, value))  
                     goto fail;  
374                  Py_DECREF(value);                  Py_DECREF(value);
375              }                  value = NULL;
             else  
             {  
                 PyErr_Clear();  
             }  
376          }          }
     }  
377    
378      Py_INCREF(Py_None);          return dict;
     return Py_None;  
379    
380   fail:  fail:
381      Py_XDECREF(value);          Py_XDECREF(value);
382      return NULL;          Py_DECREF(dict);
383            return NULL;
384  }  }
 %}  
385    
386    
 /*  
  * The SWIG Interface definition.  
  */  
387    
388  /* include some common SWIG type definitions and standard exception  /* write a single field of a record. */
389     handling code */  static int do_write_attribute(DBFHandle handle, int record, int field, int type, PyObject* value)
390  %include typemaps.i  {
391  %include exception.i          PyObject* string_value = NULL;
392            int int_value;
393  /* As for ShapeFile in shapelib.i, We define a new C-struct that holds          double double_value;
394   * the DBFHandle. This is mainly done so we can separate the close()          int logical_value;
  * method from the destructor but it also helps with exception handling.  
  *  
  * After the DBFFile has been opened or created the handle is not NULL.  
  * The close() method closes the file and sets handle to NULL as an  
  * indicator that the file has been closed.  
  */  
395    
396  %{          if (value == Py_None)
397      typedef struct {          {
398          DBFHandle handle;                  if (DBFWriteNULLAttribute(handle, record, field)) return 1;
399      } DBFFile;          }
400  %}          else
401            {
402                    switch (type)
403                    {
404                    case FTString:
405                            string_value = encode_string(handle, value);
406                            if (!string_value) return 0;
407                            if (DBFWriteStringAttribute(handle, record, field, PyString_AsString(string_value)))
408                            {
409                                    Py_DECREF(string_value);
410                                    return 1;
411                            }
412                            Py_DECREF(string_value);
413                            break;
414    
415                    case FTInteger:
416                            int_value = PyInt_AsLong(value);
417                            if (int_value == -1 && PyErr_Occurred()) return 0;
418                            if (DBFWriteIntegerAttribute(handle, record, field, int_value)) return 1;
419                            break;
420    
421                    case FTDouble:
422                            double_value = PyFloat_AsDouble(value);
423                            if (double_value == -1 && PyErr_Occurred()) return 0;
424                            if (DBFWriteDoubleAttribute(handle, record, field, double_value)) return 1;
425                            break;
426                            
427                    case FTLogical:
428                            logical_value = PyObject_IsTrue(value);
429                            if (logical_value == -1) return 0;
430                            if (DBFWriteLogicalAttribute(handle, record, field, logical_value ? 'T' : 'F')) return 1;
431                            break;
432    
433                    default:
434                            PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
435                            return 0;
436                    }
437            }
438    
439            PyErr_Format(PyExc_IOError,     "can't write field %d of record %d", field, record);
440            return 0;
441    }
442    
 /* The first argument to the DBFFile methods is a DBFFile pointer.  
  * We have to check whether handle is not NULL in most methods but not  
  * all. In the destructor and the close method, it's OK for handle to be  
  * NULL. We achieve this by checking whether the preprocessor macro  
  * NOCHECK_$name is defined. SWIG replaces $name with the name of the  
  * function for which the code is inserted. In the %{,%}-block below we  
  * define the macros for the destructor and the close() method.  
  */  
443    
444  %typemap(python,check) DBFFile *{  
445  %#ifndef NOCHECK_$name  static PyObject* dbffile_write_attribute(DBFFileObject* self, PyObject* args)
446      if (!$target || !$target->handle)  {
447          SWIG_exception(SWIG_TypeError, "dbffile already closed");          int record, field;
448  %#endif          PyObject* value;
449            int type;
450    
451            if (!PyArg_ParseTuple(args, "iiO:write_attribute", &record, &field, &value)) return NULL;
452            
453            if (field < 0 || field >= DBFGetFieldCount(self->handle))
454            {
455                    PyErr_Format(PyExc_ValueError,
456                                    "field index %d out of bounds (field count: %d)",
457                                    field, DBFGetFieldCount(self->handle));
458                    return NULL;
459            }
460    
461            type = DBFGetFieldInfo(self->handle, field, NULL, NULL, NULL);
462            if (!do_write_attribute(self->handle, record, field, type, value)) return NULL;
463            Py_RETURN_NONE;
464  }  }
465    
 %{  
 #define NOCHECK_delete_DBFFile  
 #define NOCHECK_DBFFile_close  
 %}  
466    
467    
468  /* An exception handle for the constructor and the module level open()  static PyObject* dbffile_write_record(DBFFileObject* self, PyObject* args)
469   * and create() functions.  {
470   *          int record;
471   * Annoyingly, we *have* to put braces around the SWIG_exception()          PyObject* record_object;
472   * calls, at least in the python case, because of the way the macro is          int i, num_fields;
473   * written. Of course, always putting braces around the branches of an          
474   * if-statement is often considered good practice.          int type;
475   */          char name[12];
476  %typemap(python,except) DBFFile * {          PyObject* value = NULL;
477      $function;          
478      if (!$source)          if (!PyArg_ParseTuple(args, "iO:write_record", &record, &record_object)) return NULL;
479      {          
480          SWIG_exception(SWIG_MemoryError, "no memory");          num_fields = DBFGetFieldCount(self->handle);
481      }          
482      else if (!$source->handle)          /* mimic ShapeFile functionality where id = -1 means appending */
483      {          if (record == -1)
484          SWIG_exception(SWIG_IOError, "$name failed");          {
485      }                  record = num_fields;
486  }          }
487    
488  /* Exception handler for the add_field method */          if (PySequence_Check(record_object))
489  %typemap(python,except) int DBFFile_add_field {          {
490      $function;                  /* It's a sequence object. Iterate through all items in the
491      if ($source < 0)                  * sequence and write them to the appropriate field.
492      {                  */
493          SWIG_exception(SWIG_RuntimeError, "add_field failed");                  if (PySequence_Length(record_object) != num_fields)
494      }                  {
495  }                          PyErr_SetString(PyExc_TypeError, "record must have one item for each field");
496                            return NULL;
497  /* define and use some typemaps for the field_info() method whose                  }
498   * C-implementation has three output parameters that are returned                  for (i = 0; i < num_fields; ++i)
499   * through pointers passed into the function. SWIG already has                  {
500   * definitions for common types such as int* and we can use those for                          type = DBFGetFieldInfo(self->handle, i, NULL, NULL, NULL);
501   * the last two parameters:                          value = PySequence_GetItem(record_object, i);
502   */                          if (!value) return NULL;
503                            if (!do_write_attribute(self->handle, record, i, type, value))
504                            {
505                                    Py_DECREF(value);
506                                    return NULL;
507                            }
508                            Py_DECREF(value);
509                    }
510            }
511            else
512            {
513                    /* It's a dictionary-like object. Iterate over the names of the
514                    * known fields and write the corresponding item
515                    */
516                    for (i = 0; i < num_fields; ++i)
517                    {
518                            name[0] = '\0';
519                            type = DBFGetFieldInfo(self->handle, i, name, NULL, NULL);
520                            value = PyDict_GetItemString(record_object, name);
521                            if (value && !do_write_attribute(self->handle, record, i, type, value)) return NULL;
522                    }
523            }
524            
525            return PyInt_FromLong((long)record);
526    }
527    
528    
 %apply int * OUTPUT { int * output_width }  
 %apply int * OUTPUT { int * output_decimals }  
529    
530  /* the fieldname has to be defined manually: */  static PyObject* dbffile_repr(DBFFileObject* self)
531  %typemap(python,ignore) char *fieldname_out(char temp[12]) {  {
532      $target = temp;          /* TODO: it would be nice to do something like "dbflib.DBFFile(filename, mode)" instead */
533            return PyString_FromFormat("<dbflib.DBFFile object at %p>", self->handle);
534  }  }
535    
536  %typemap(python,argout) char *fieldname_out() {  
537      PyObject * string = PyString_FromString($source);  
538      $target = t_output_helper($target,string);  /* The commit method implementation
539    *
540    * The method relies on the DBFUpdateHeader method which is not
541    * available in shapelib <= 1.2.10.  setup.py defines
542    * HAVE_UPDATE_HEADER's value depending on whether the function is
543    * available in the shapelib version the code is compiled with.
544    */
545    #if HAVE_UPDATE_HEADER
546    static PyObject* dbffile_commit(DBFFileObject* self)
547    {
548            DBFUpdateHeader(self->handle);
549            Py_RETURN_NONE;
550  }  }
551    #endif
552    
553    
554    #if HAVE_LANGUAGE_DRIVER
555    
556  /*  static PyObject* dbffile_language_driver(DBFFileObject* self, void* closure)
557   * The SWIG-version of the DBFFile struct  {
558   */          return PyInt_FromLong((long)self->handle->nLanguageDriver);
559    }
560    
561    #endif
562    
563  typedef struct  
564    static struct PyMethodDef dbffile_methods[] =
565  {  {
566      %addmethods {          {"close", (PyCFunction)dbffile_close, METH_NOARGS,
567          DBFFile(const char *file, const char * mode = "rb") {                  "close() -> None\n\n"
568              DBFFile * self = malloc(sizeof(DBFFile));                  "closes DBFFile"},
569              if (self)          {"field_count", (PyCFunction)dbffile_field_count, METH_NOARGS,
570                  self->handle = DBFOpen(file, mode);                  "field_count() -> integer\n\n"
571              return self;                  "returns number of fields currently defined"},
572          }          {"record_count", (PyCFunction)dbffile_record_count, METH_NOARGS,
573                                "record_count() -> integer\n\n"
574          ~DBFFile() {                  "returns number of records that currently exist"},
575              if (self->handle)          {"field_info", (PyCFunction)dbffile_field_info, METH_VARARGS,
576                  DBFClose(self->handle);                  "field_info(field_index) -> (type, name, width, decimals)\n\n"
577              free(self);                  "returns info of a field as a tuple with:\n"
578          }                  "- type: the type of the field corresponding to the integer value of one "
579                    " of the constants FTString, FTInteger, ...\n"
580                    "- name: the name of the field as a string\n"
581                    "- width: the width of the field as a number of characters\n"
582                    "- decimals: the number of decimal digits" },
583            {"add_field", (PyCFunction)dbffile_add_field, METH_VARARGS,
584                    "add_field(type, name, width, decimals) -> field_index\n\n"
585                    "adds a new field and returns field index if successful\n"
586                    "- type: the type of the field corresponding to the integer value of one "
587                    " of the constants FTString, FTInteger, ...\n"
588                    "- name: the name of the field as a string\n"
589                    "- width: the width of the field as a number of characters\n"
590                    "- decimals: the number of decimal digits" },
591            {"read_attribute", (PyCFunction)dbffile_read_attribute, METH_VARARGS,
592                    "read_attribute(record_index, field_index) -> value\n\n"
593                    "returns the value of one field of a record"},
594            {"read_record", (PyCFunction)dbffile_read_record, METH_VARARGS,
595                    "read_record(record_index) -> dict\n\n"
596                    "returns an entire record as a dictionary of field names and values"},
597            {"write_attribute", (PyCFunction)dbffile_write_attribute, METH_VARARGS,
598                    "write_attribute(record_index, field_index, new_value)\n"
599                    "writes a single field of a record"},
600            {"write_record", (PyCFunction)dbffile_write_record, METH_VARARGS,
601                    "write_record(record_index, record) -> record_index\n\n"
602                    "Writes an entire record as a dict or a sequence, and return index of record\n"
603                    "Record can either be a dictionary in which case the keys are used as field names, "
604                    "or a sequence that must have an item for every field (length = field_count())"},
605    #if HAVE_UPDATE_HEADER
606            {"commit", (PyCFunction)dbffile_commit, METH_NOARGS,
607                    "commit() -> None"},
608    #endif
609            {NULL}
610    };
611    
         void close() {  
             if (self->handle)  
                 DBFClose(self->handle);  
             self->handle = NULL;  
         }  
612    
         int field_count() {  
             return DBFGetFieldCount(self->handle);  
         }  
613    
614          int record_count() {  static struct PyGetSetDef dbffile_getsetters[] =
615              return DBFGetRecordCount(self->handle);  {
616          }  #if HAVE_LANGUAGE_DRIVER
617            {"language_driver", (getter)dbffile_language_driver, NULL, "Language Driver ID (read-only)" },
618    #endif
619            {NULL}
620    };
621    
622    
623    
624    static PyTypeObject DBFFileType = PYSHAPELIB_DEFINE_TYPE(DBFFileObject, dbffile, "shapelib.DBFFile", 0);
625    
626    
627    
628          int field_info(int iField, char * fieldname_out,  /* --- dbflib -------------------------------------------------------------------------------------------------------- */
629                         int * output_width, int * output_decimals) {  
630              return DBFGetFieldInfo(self->handle, iField, fieldname_out,  static PyObject* dbflib_open(PyObject* module, PyObject* args)
631                                     output_width, output_decimals);  {
632            return PyObject_CallObject((PyObject*)&DBFFileType, args);
633    }
634    
635    
636    
637    static PyObject* dbflib_create(PyObject* module, PyObject* args)
638    {
639            char* file;
640            DBFFileObject* result;
641            DBFHandle handle = NULL;
642            int wideargument = 0;
643    
644    #if defined(SHPAPI_HAS_WIDE) && defined(Py_WIN_WIDE_FILENAMES)
645            if (GetVersion() < 0x80000000) {    /* On NT, so wide API available */
646                    PyObject *wfile;
647                    if (PyArg_ParseTuple(args, "U:create", &wfile))
648                    {
649                            wideargument = 1;
650                            handle = DBFCreateW(PyUnicode_AS_UNICODE(wfile));
651                            if (!handle)
652                            {
653                                    PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, wfile);
654                                    return NULL;
655                            }
656                    }
657                    else
658                    {
659                            /* Drop the argument parsing error as narrow
660                               strings are also valid. */
661                            PyErr_Clear();
662                    }
663          }          }
664                #endif
665          PyObject * read_record(int record) {          
666              return DBFInfo_read_record(self->handle, record);          if (!handle)
667            {
668                    if (!PyArg_ParseTuple(args, "et:create", Py_FileSystemDefaultEncoding, &file)) return NULL;
669                    handle = DBFCreate(file);
670                    if (!handle)
671                    {
672                                    PyErr_SetFromErrnoWithFilename(PyExc_IOError, file);
673                                    PyMem_Free(file);
674                                    return NULL;
675                    }
676                    PyMem_Free(file);
677          }          }
678    
679          int add_field(const char * pszFieldName, DBFFieldType eType,          result = PyObject_New(DBFFileObject, &DBFFileType);
680                        int nWidth, int nDecimals) {          if (!result)
681              return DBFAddField(self->handle, pszFieldName, eType, nWidth,          {
682                                 nDecimals);                  DBFClose(handle);
683                    return PyErr_NoMemory();
684          }          }
685            
686            result->handle = handle;
687            return (PyObject*) result;
688    }
689    
690    
691    
692          PyObject *write_record(int record, PyObject *dict_or_sequence) {  #if HAVE_LANGUAGE_DRIVER
693              return DBFInfo_write_record(self->handle, record,  
694                                          dict_or_sequence);  /** translate a numeric Language Driver ID to the name of Python's codec.
695     */
696    static PyObject* dbflib_language_driver_codec(PyObject* module, PyObject* args)
697    {
698            int ldid;
699            if (!PyArg_ParseTuple(args, "i:language_driver_name", &ldid)) return NULL;
700            if (ldid < 0 || ldid >= PYSHAPELIB_NUM_LANGUAGE_DRIVERS || !codecs[ldid])
701            {
702                    PyErr_SetString(PyExc_ValueError, "invalid driver id");
703                    return NULL;
704          }          }
705            return PyString_FromString(codecs[ldid]);
706    }
707    
708          int commit() {  /** translate a numeric Language Driver ID to a string represting its constant.
709              return DBFCommit(self->handle);   */
710    static PyObject* dbflib_language_driver_name(PyObject* module, PyObject* args)
711    {
712            int ldid;
713            if (!PyArg_ParseTuple(args, "i:language_driver_name", &ldid)) return NULL;
714            if (ldid < 0 || ldid >= PYSHAPELIB_NUM_LANGUAGE_DRIVERS || !drivers[ldid])
715            {
716                    PyErr_SetString(PyExc_ValueError, "invalid driver id");
717                    return NULL;
718          }          }
719            return PyString_FromString(drivers[ldid]);
720    }
721    
722      }  #endif
 } DBFFile;  
723    
724    
 /*  
  * Two module level functions, open() and create() that correspond to  
  * DBFOpen and DBFCreate respectively. open() is equivalent to the  
  * DBFFile constructor.  
  */  
725    
726    static struct PyMethodDef dbflib_methods[] =
727    {
728            {"open", (PyCFunction)dbflib_open, METH_VARARGS,
729                    "open(name [, mode]) -> DBFFile\n\n"
730                    "opens a DBFFile" },
731            {"create", (PyCFunction)dbflib_create, METH_VARARGS,
732                    "create(name [, language_driver]) -> DBFFile\n\n"
733                    "create a DBFFile " },
734    #if HAVE_LANGUAGE_DRIVER
735            {"language_driver_codec", (PyCFunction)dbflib_language_driver_codec, METH_VARARGS,
736                    "language_driver_codec(driver_id) -> string\n\n"
737                    "translate language driver id into the name of the Python's codec used as code page." },
738            {"language_driver_name", (PyCFunction)dbflib_language_driver_name, METH_VARARGS,
739                    "language_driver_name(driver_id) -> string\n\n"
740                    "translate language driver id into a string." },
741    #endif
742            {NULL}
743    };
744    
 %{  
     DBFFile * open_DBFFile(const char * file, const char * mode)  
     {  
         DBFFile * self = malloc(sizeof(DBFFile));  
         if (self)  
             self->handle = DBFOpen(file, mode);  
         return self;  
     }  
 %}  
   
 %name(open) %new DBFFile * open_DBFFile(const char * file,  
                                         const char * mode = "rb");  
   
 %{  
     DBFFile * create_DBFFile(const char * file)  
     {  
         DBFFile * self = malloc(sizeof(DBFFile));  
         if (self)  
             self->handle = DBFCreate(file);  
         return self;  
     }  
 %}  
 %name(create) %new DBFFile * create_DBFFile(const char * file);  
745    
746    PyMODINIT_FUNC initdbflib(void)
747    {
748            int i;
749    
750            PyObject* module = Py_InitModule("dbflib", dbflib_methods);
751            if (!module) return;
752            
753            PYSHAPELIB_ADD_TYPE(DBFFileType, "DBFFile");
754            
755            PYSHAPELIB_ADD_CONSTANT(FTString);
756            PYSHAPELIB_ADD_CONSTANT(FTInteger);
757            PYSHAPELIB_ADD_CONSTANT(FTDouble);
758            PYSHAPELIB_ADD_CONSTANT(FTLogical);
759            PYSHAPELIB_ADD_CONSTANT(FTInvalid);
760            PyModule_AddIntConstant(module, "_have_commit", HAVE_UPDATE_HEADER);
761    
762    #if HAVE_LANGUAGE_DRIVER
763            /* table compiled from these resources:
764             * http://www.clicketyclick.dk/databases/xbase/format/dbf.html
765             * http://www.esrinl.com/content/file.asp?id=307
766             * http://msdn2.microsoft.com/en-us/library/aa975345(VS.71).aspx
767             */
768            for (i = 0; i < PYSHAPELIB_NUM_LANGUAGE_DRIVERS; ++i)
769            {
770                    codecs[i] = NULL;
771                    drivers[i] = NULL;
772            }
773            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x00, "cp1252", "NOT_SET");
774            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x01, "cp437", "DOS_USA");
775            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x02, "cp850", "DOS_INTERNATIONAL");
776            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x03, "cp1252", "WINDOWS_ANSI");
777            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x04, "mac_roman", "STANDARD_MACINTOSH");
778            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x08, "cp865", "DANISH_OEM");
779            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x09, "cp437", "DUTCH_OEM");
780            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0a, "cp850", "DUTCH_OEM_2");
781            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0b, "cp437", "FINNISH_OEM");
782            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0d, "cp437", "FRENCH_OEM");
783            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0e, "cp850", "FRENCH_OEM_2");
784            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0f, "cp437", "GERMAN_OEM");
785            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x10, "cp850", "GERMAN_OEM_2");
786            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x11, "cp437", "ITALIAN_OEM");
787            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x12, "cp850", "ITALIAN_OEM_2");
788            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x13, "cp932", "JAPANESE_SHIFT_JIS");
789            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x14, "cp850", "SPANISH_OEM_2");
790            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x15, "cp437", "SWEDISH_OEM");
791            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x16, "cp850", "SWEDISH_OEM_2");
792            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x17, "cp865", "NORWEGIAN_OEM");
793            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x18, "cp437", "SPANISH_OEM");
794            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x19, "cp437", "ENGLISH_BRITAIN_OEM");
795            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x1a, "cp850", "ENGLISH_BRITAIN_OEM_2");
796            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x0b, "cp437", "ENGLISH_US_OEM");
797            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x1c, "cp863", "FRENCH_CANADA_OEM");
798            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x1d, "cp850", "FRENCH_OEM_2");
799            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x1f, "cp852", "CZECH_OEM");
800            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x22, "cp852", "HUNGARIAN_OEM");
801            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x23, "cp852", "POLISH_OEM");
802            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x24, "cp860", "PORTUGUESE_OEM");
803            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x25, "cp850", "PORTUGUESE_OEM_2");
804            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x26, "cp866", "RUSSIAN_OEM");
805            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x37, "cp850", "ENGLISH_US_OEM_2");
806            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x40, "cp852", "ROMANIAN_OEM");
807            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x4d, "cp936", "CHINESE_GBK_PRC");
808            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x4e, "cp949", "KOREAN_ANSI_OEM);");
809            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x4f, "cp950", "CHINESE_BIG5_TAIWAN");
810            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x50, "cp874", "THAI_ANSI_OEM");
811            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x57, "cp1252", "ESRI_ANSI");
812            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x58, "cp1252", "WESTERN_EUROPEAN_ANSI");
813            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x59, "cp1252", "SPANISH_ANSI");
814            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x64, "cp852", "EASTERN_EUROPEAN_MSDOS");
815            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x65, "cp866", "RUSSIAN_MSDOS");
816            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x66, "cp865", "NORDIC_MSDOS");
817            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x67, "cp861", "ICELANDIC_MSDOS");
818            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x68, "cp895", "CZECH_MSDOS");
819            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x69, "cp620", "POLISH_MSDOS");
820            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x6a, "cp737", "GREEK_MSDOS");
821            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x6b, "cp857", "TURKISH_MSDOS");
822            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x6c, "cp863", "FRENCH_CANADA_MSDOS");
823            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x78, "cp950", "TAIWAN_BIG5");
824            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x79, "cp949", "HANGUL_WANSUG");
825            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x7a, "cp936", "PRC_GBK");
826            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x7b, "cp932", "JAPANESE_SHIFT_JIS");
827            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x7c, "cp874", "THAI_WINDOWS_MSDOS");
828            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x7d, "cp1255", "HEBREW_WINDOWS");
829            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x7e, "cp1256", "ARABIC_WINDOWS");
830            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x86, "cp737", "GREEK_OEM");
831            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x87, "cp852", "SLOVENIAN_OEM");
832            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x88, "cp857", "TURKISH_OEM");
833            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x96, "mac_cyrillic", "RUSSIAN_MACINTOSH");
834            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x97, "mac_latin2", "EASTERN_EUROPEAN_MACINTOSH");
835            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0x98, "mac_greek", "GREEK_MACINTOSH");
836            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0xc8, "cp1250", "EASTERN_EUROPEAN_WINDOWS");
837            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0xc9, "cp1251", "RUSSIAN_WINDOWS");
838            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0xca, "cp1254", "TURKISH_WINDOWS");
839            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0xcb, "cp1253", "GREEK_WINDOWS");
840            PYSHAPELIB_ADD_LANGUAGE_DRIVER(0xcc, "cp1257", "BALTIC_WINDOWS");
841    #endif
842    
843  /* constant definitions copied from shapefil.h */  }
 typedef enum {  
   FTString,  
   FTInteger,  
   FTDouble,  
   FTInvalid  
 } DBFFieldType;  

Legend:
Removed from v.1761  
changed lines
  Added in v.2754

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26