geo_coder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +32 -0
  3. data/History.txt +6 -0
  4. data/Makefile +13 -0
  5. data/Manifest.txt +18 -0
  6. data/README.rdoc +197 -0
  7. data/Rakefile +53 -0
  8. data/TODO.txt +8 -0
  9. data/VERSION +1 -0
  10. data/bin/build_indexes +8 -0
  11. data/bin/rebuild_cluster +22 -0
  12. data/bin/rebuild_metaphones +23 -0
  13. data/bin/tiger_import +59 -0
  14. data/demos/demo/app/ext/geocodewrap.rb +84 -0
  15. data/demos/demo/app/views/index.builder +13 -0
  16. data/demos/demo/app/views/index.erb +71 -0
  17. data/demos/demo/config.ru +12 -0
  18. data/demos/demo/config/bootstraps.rb +130 -0
  19. data/demos/demo/config/geoenvironment.rb +25 -0
  20. data/demos/demo/geocoder_helper.rb +12 -0
  21. data/demos/demo/geocom_geocode.rb +10 -0
  22. data/demos/demo/main.rb +3 -0
  23. data/demos/demo/rakefile.rb +17 -0
  24. data/demos/demo/tmp/restart.txt +0 -0
  25. data/demos/simpledemo/views/index.builder +13 -0
  26. data/demos/simpledemo/views/index.erb +69 -0
  27. data/demos/simpledemo/ws.rb +83 -0
  28. data/doc/Makefile +7 -0
  29. data/doc/html4css1.css +279 -0
  30. data/doc/lookup.rst +193 -0
  31. data/doc/parsing.rst +125 -0
  32. data/doc/voidspace.css +147 -0
  33. data/geo_coder.gemspec +172 -0
  34. data/lib/geocoder/us.rb +21 -0
  35. data/lib/geocoder/us/address.rb +290 -0
  36. data/lib/geocoder/us/constants.rb +670 -0
  37. data/lib/geocoder/us/database.rb +745 -0
  38. data/lib/geocoder/us/import.rb +181 -0
  39. data/lib/geocoder/us/import/tiger.rb +13 -0
  40. data/lib/geocoder/us/numbers.rb +58 -0
  41. data/navteq/README +4 -0
  42. data/navteq/convert.sql +37 -0
  43. data/navteq/navteq_import +39 -0
  44. data/navteq/prepare.sql +92 -0
  45. data/sql/cluster.sql +16 -0
  46. data/sql/convert.sql +80 -0
  47. data/sql/create.sql +37 -0
  48. data/sql/index.sql +12 -0
  49. data/sql/place.csv +104944 -0
  50. data/sql/place.sql +104948 -0
  51. data/sql/setup.sql +78 -0
  52. data/src/Makefile +13 -0
  53. data/src/README +14 -0
  54. data/src/liblwgeom/Makefile +75 -0
  55. data/src/liblwgeom/box2d.c +54 -0
  56. data/src/liblwgeom/lex.yy.c +4799 -0
  57. data/src/liblwgeom/liblwgeom.h +1405 -0
  58. data/src/liblwgeom/lwalgorithm.c +946 -0
  59. data/src/liblwgeom/lwalgorithm.h +52 -0
  60. data/src/liblwgeom/lwcircstring.c +759 -0
  61. data/src/liblwgeom/lwcollection.c +541 -0
  62. data/src/liblwgeom/lwcompound.c +118 -0
  63. data/src/liblwgeom/lwcurvepoly.c +86 -0
  64. data/src/liblwgeom/lwgeom.c +886 -0
  65. data/src/liblwgeom/lwgeom_api.c +2201 -0
  66. data/src/liblwgeom/lwgparse.c +1219 -0
  67. data/src/liblwgeom/lwgunparse.c +1054 -0
  68. data/src/liblwgeom/lwline.c +525 -0
  69. data/src/liblwgeom/lwmcurve.c +125 -0
  70. data/src/liblwgeom/lwmline.c +137 -0
  71. data/src/liblwgeom/lwmpoint.c +138 -0
  72. data/src/liblwgeom/lwmpoly.c +141 -0
  73. data/src/liblwgeom/lwmsurface.c +129 -0
  74. data/src/liblwgeom/lwpoint.c +439 -0
  75. data/src/liblwgeom/lwpoly.c +579 -0
  76. data/src/liblwgeom/lwsegmentize.c +1047 -0
  77. data/src/liblwgeom/lwutil.c +369 -0
  78. data/src/liblwgeom/measures.c +861 -0
  79. data/src/liblwgeom/postgis_config.h +93 -0
  80. data/src/liblwgeom/ptarray.c +847 -0
  81. data/src/liblwgeom/vsprintf.c +179 -0
  82. data/src/liblwgeom/wktparse.h +126 -0
  83. data/src/liblwgeom/wktparse.lex +74 -0
  84. data/src/liblwgeom/wktparse.tab.c +2353 -0
  85. data/src/liblwgeom/wktparse.tab.h +145 -0
  86. data/src/liblwgeom/wktparse.y +385 -0
  87. data/src/libsqlite3_geocoder/Makefile +22 -0
  88. data/src/libsqlite3_geocoder/Makefile.nix +15 -0
  89. data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
  90. data/src/libsqlite3_geocoder/extension.c +121 -0
  91. data/src/libsqlite3_geocoder/extension.h +13 -0
  92. data/src/libsqlite3_geocoder/levenshtein.c +42 -0
  93. data/src/libsqlite3_geocoder/metaphon.c +278 -0
  94. data/src/libsqlite3_geocoder/util.c +37 -0
  95. data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
  96. data/src/metaphone/Makefile +7 -0
  97. data/src/metaphone/README +49 -0
  98. data/src/metaphone/extension.c +37 -0
  99. data/src/metaphone/metaphon.c +251 -0
  100. data/src/shp2sqlite/Makefile +37 -0
  101. data/src/shp2sqlite/Makefile.nix +36 -0
  102. data/src/shp2sqlite/Makefile.redhat +35 -0
  103. data/src/shp2sqlite/dbfopen.c +1595 -0
  104. data/src/shp2sqlite/getopt.c +695 -0
  105. data/src/shp2sqlite/getopt.h +127 -0
  106. data/src/shp2sqlite/shapefil.h +500 -0
  107. data/src/shp2sqlite/shp2sqlite.c +1974 -0
  108. data/src/shp2sqlite/shpopen.c +1894 -0
  109. data/tests/address.rb +236 -0
  110. data/tests/benchmark.rb +20 -0
  111. data/tests/constants.rb +57 -0
  112. data/tests/data/address-sample.csv +52 -0
  113. data/tests/data/db-test.csv +57 -0
  114. data/tests/data/locations.csv +4 -0
  115. data/tests/database.rb +137 -0
  116. data/tests/generate.rb +34 -0
  117. data/tests/numbers.rb +46 -0
  118. data/tests/run.rb +11 -0
  119. metadata +237 -0
@@ -0,0 +1,36 @@
1
+ # **********************************************************************
2
+ # * $Id: Makefile.in
3
+ # *
4
+ # * PostGIS - Spatial Types for PostgreSQL
5
+ # * http://postgis.refractions.net
6
+ # * Copyright 2008 Mark Cave-Ayland
7
+ # *
8
+ # * This is free software; you can redistribute and/or modify it under
9
+ # * the terms of the GNU General Public Licence. See the COPYING file.
10
+ # *
11
+ # **********************************************************************
12
+
13
+
14
+ CFLAGS=-g -O2 -fPIC -DPIC -Wall -Wmissing-prototypes
15
+
16
+ # Filenames with extension as determined by the OS
17
+ SHP2SQLITE=shp2sqlite
18
+ LIBLWGEOM=../liblwgeom/liblwgeom.a
19
+
20
+ # iconv flags
21
+ ICONV_LDFLAGS=-lc
22
+
23
+ all: $(SHP2SQLITE)
24
+
25
+ $(LIBLWGEOM):
26
+ make -C ../liblwgeom
27
+
28
+ $(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)
29
+ $(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@
30
+
31
+ install: all
32
+ @cp $(SHP2SQLITE) ../../bin
33
+
34
+ clean:
35
+ @rm -f *.o $(SHP2SQLITE)
36
+
@@ -0,0 +1,35 @@
1
+ # **********************************************************************
2
+ # * $Id: Makefile.in
3
+ # *
4
+ # * PostGIS - Spatial Types for PostgreSQL
5
+ # * http://postgis.refractions.net
6
+ # * Copyright 2008 Mark Cave-Ayland
7
+ # *
8
+ # * This is free software; you can redistribute and/or modify it under
9
+ # * the terms of the GNU General Public Licence. See the COPYING file.
10
+ # *
11
+ # **********************************************************************
12
+ CC=gcc
13
+ CFLAGS=-g -O2 -fPIC -DPIC -Wall -Wmissing-prototypes
14
+
15
+ # Filenames with extension as determined by the OS
16
+ SHP2SQLITE=shp2sqlite
17
+ LIBLWGEOM=../liblwgeom/liblwgeom.a
18
+
19
+ # iconv flags
20
+ ICONV_LDFLAGS=-lc
21
+
22
+ all: $(SHP2SQLITE)
23
+
24
+ $(LIBLWGEOM):
25
+ make -C ../liblwgeom
26
+
27
+ $(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)
28
+ $(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@
29
+
30
+ install: all
31
+ @cp $(SHP2SQLITE) ../../bin
32
+
33
+ clean:
34
+ @rm -f *.o $(SHP2SQLITE)
35
+
@@ -0,0 +1,1595 @@
1
+ /******************************************************************************
2
+ * $Id: dbfopen.c 3750 2009-02-19 21:12:22Z pramsey $
3
+ *
4
+ * Project: Shapelib
5
+ * Purpose: Implementation of .dbf access API documented in dbf_api.html.
6
+ * Author: Frank Warmerdam, warmerdam@pobox.com
7
+ *
8
+ ******************************************************************************
9
+ * Copyright (c) 1999, Frank Warmerdam
10
+ *
11
+ * This software is available under the following "MIT Style" license,
12
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
13
+ * option is discussed in more detail in shapelib.html.
14
+ *
15
+ * --
16
+ *
17
+ * Permission is hereby granted, free of charge, to any person obtaining a
18
+ * copy of this software and associated documentation files (the "Software"),
19
+ * to deal in the Software without restriction, including without limitation
20
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21
+ * and/or sell copies of the Software, and to permit persons to whom the
22
+ * Software is furnished to do so, subject to the following conditions:
23
+ *
24
+ * The above copyright notice and this permission notice shall be included
25
+ * in all copies or substantial portions of the Software.
26
+ *
27
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33
+ * DEALINGS IN THE SOFTWARE.
34
+ ******************************************************************************
35
+ *
36
+ * $Log$
37
+ * Revision 1.8 2006/01/16 10:42:57 strk
38
+ * Added support for Bool and Date DBF<=>PGIS mapping
39
+ *
40
+ * Revision 1.7 2006/01/09 16:40:16 strk
41
+ * ISO C90 comments, signedness mismatch fixes
42
+ *
43
+ * Revision 1.6 2003/12/01 20:52:00 strk
44
+ * shapelib put in sync with gdal cvs
45
+ *
46
+ * Revision 1.52 2003/07/08 15:20:03 warmerda
47
+ * avoid warnings about downcasting to unsigned char
48
+ *
49
+ * Revision 1.51 2003/07/08 13:50:15 warmerda
50
+ * DBFIsAttributeNULL check for pszValue==NULL - bug 360
51
+ *
52
+ * Revision 1.50 2003/04/21 18:58:25 warmerda
53
+ * ensure current record is flushed at same time as header is updated
54
+ *
55
+ * Revision 1.49 2003/04/21 18:30:37 warmerda
56
+ * added header write/update public methods
57
+ *
58
+ * Revision 1.48 2003/03/10 14:51:27 warmerda
59
+ * DBFWrite* calls now return FALSE if they have to truncate
60
+ *
61
+ * Revision 1.47 2002/11/20 03:32:22 warmerda
62
+ * Ensure field name in DBFGetFieldIndex() is properly terminated.
63
+ *
64
+ * Revision 1.46 2002/10/09 13:10:21 warmerda
65
+ * Added check that width is positive.
66
+ *
67
+ * Revision 1.45 2002/09/29 00:00:08 warmerda
68
+ * added FTLogical and logical attribute read/write calls
69
+ *
70
+ * Revision 1.44 2002/05/07 13:46:11 warmerda
71
+ * Added DBFWriteAttributeDirectly().
72
+ *
73
+ * Revision 1.43 2002/02/13 19:39:21 warmerda
74
+ * Fix casting issues in DBFCloneEmpty().
75
+ *
76
+ * Revision 1.42 2002/01/15 14:36:07 warmerda
77
+ * updated email address
78
+ *
79
+ * Revision 1.41 2002/01/15 14:31:49 warmerda
80
+ * compute rather than copying nHeaderLength in DBFCloneEmpty()
81
+ *
82
+ * Revision 1.40 2002/01/09 04:32:35 warmerda
83
+ * fixed to read correct amount of header
84
+ *
85
+ * Revision 1.39 2001/12/11 22:41:03 warmerda
86
+ * improve io related error checking when reading header
87
+ *
88
+ * Revision 1.38 2001/11/28 16:07:31 warmerda
89
+ * Cleanup to avoid compiler warnings as suggested by Richard Hash.
90
+ *
91
+ * Revision 1.37 2001/07/04 05:18:09 warmerda
92
+ * do last fix properly
93
+ *
94
+ * Revision 1.36 2001/07/04 05:16:09 warmerda
95
+ * fixed fieldname comparison in DBFGetFieldIndex
96
+ *
97
+ * Revision 1.35 2001/06/22 02:10:06 warmerda
98
+ * fixed NULL shape support with help from Jim Matthews
99
+ *
100
+ * Revision 1.33 2001/05/31 19:20:13 warmerda
101
+ * added DBFGetFieldIndex()
102
+ *
103
+ * Revision 1.32 2001/05/31 18:15:40 warmerda
104
+ * Added support for NULL fields in DBF files
105
+ *
106
+ * Revision 1.31 2001/05/23 13:36:52 warmerda
107
+ * added use of SHPAPI_CALL
108
+ *
109
+ * Revision 1.30 2000/12/05 14:43:38 warmerda
110
+ * DBReadAttribute() white space trimming bug fix
111
+ *
112
+ * Revision 1.29 2000/10/05 14:36:44 warmerda
113
+ * fix bug with writing very wide numeric fields
114
+ *
115
+ * Revision 1.28 2000/09/25 14:18:07 warmerda
116
+ * Added some casts of strlen() return result to fix warnings on some
117
+ * systems, as submitted by Daniel.
118
+ *
119
+ * Revision 1.27 2000/09/25 14:15:51 warmerda
120
+ * added DBFGetNativeFieldType()
121
+ *
122
+ * Revision 1.26 2000/07/07 13:39:45 warmerda
123
+ * removed unused variables, and added system include files
124
+ *
125
+ * Revision 1.25 2000/05/29 18:19:13 warmerda
126
+ * avoid use of uchar, and adding casting fix
127
+ *
128
+ * Revision 1.24 2000/05/23 13:38:27 warmerda
129
+ * Added error checks on return results of fread() and fseek().
130
+ *
131
+ * Revision 1.23 2000/05/23 13:25:49 warmerda
132
+ * Avoid crashing if field or record are out of range in dbfread*attribute().
133
+ *
134
+ * Revision 1.22 1999/12/15 13:47:24 warmerda
135
+ * Added stdlib.h to ensure that atof() is prototyped.
136
+ *
137
+ * Revision 1.21 1999/12/13 17:25:46 warmerda
138
+ * Added support for upper case .DBF extention.
139
+ *
140
+ * Revision 1.20 1999/11/30 16:32:11 warmerda
141
+ * Use atof() instead of sscanf().
142
+ *
143
+ * Revision 1.19 1999/11/05 14:12:04 warmerda
144
+ * updated license terms
145
+ *
146
+ * Revision 1.18 1999/07/27 00:53:28 warmerda
147
+ * ensure that whole old field value clear on write of string
148
+ *
149
+ * Revision 1.1 1999/07/05 18:58:07 warmerda
150
+ * New
151
+ *
152
+ * Revision 1.17 1999/06/11 19:14:12 warmerda
153
+ * Fixed some memory leaks.
154
+ *
155
+ * Revision 1.16 1999/06/11 19:04:11 warmerda
156
+ * Remoted some unused variables.
157
+ *
158
+ * Revision 1.15 1999/05/11 03:19:28 warmerda
159
+ * added new Tuple api, and improved extension handling - add from candrsn
160
+ *
161
+ * Revision 1.14 1999/05/04 15:01:48 warmerda
162
+ * Added 'F' support.
163
+ *
164
+ * Revision 1.13 1999/03/23 17:38:59 warmerda
165
+ * DBFAddField() now actually does return the new field number, or -1 if
166
+ * it fails.
167
+ *
168
+ * Revision 1.12 1999/03/06 02:54:46 warmerda
169
+ * Added logic to convert shapefile name to dbf filename in DBFOpen()
170
+ * for convenience.
171
+ *
172
+ * Revision 1.11 1998/12/31 15:30:34 warmerda
173
+ * Improved the interchangability of numeric and string attributes. Add
174
+ * white space trimming option for attributes.
175
+ *
176
+ * Revision 1.10 1998/12/03 16:36:44 warmerda
177
+ * Use r+b instead of rb+ for binary access.
178
+ *
179
+ * Revision 1.9 1998/12/03 15:34:23 warmerda
180
+ * Updated copyright message.
181
+ *
182
+ * Revision 1.8 1997/12/04 15:40:15 warmerda
183
+ * Added newline character after field definitions.
184
+ *
185
+ * Revision 1.7 1997/03/06 14:02:10 warmerda
186
+ * Ensure bUpdated is initialized.
187
+ *
188
+ * Revision 1.6 1996/02/12 04:54:41 warmerda
189
+ * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
190
+ *
191
+ * Revision 1.5 1995/10/21 03:15:12 warmerda
192
+ * Changed to use binary file access, and ensure that the
193
+ * field name field is zero filled, and limited to 10 chars.
194
+ *
195
+ * Revision 1.4 1995/08/24 18:10:42 warmerda
196
+ * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
197
+ * as on the Sun.
198
+ *
199
+ * Revision 1.3 1995/08/04 03:15:16 warmerda
200
+ * Fixed up header.
201
+ *
202
+ * Revision 1.2 1995/08/04 03:14:43 warmerda
203
+ * Added header.
204
+ */
205
+
206
+ #include "shapefil.h"
207
+
208
+ #include <math.h>
209
+ #include <stdlib.h>
210
+ #include <ctype.h>
211
+ #include <string.h>
212
+
213
+ #ifndef FALSE
214
+ # define FALSE 0
215
+ # define TRUE 1
216
+ #endif
217
+
218
+ static int nStringFieldLen = 0;
219
+ static char * pszStringField = NULL;
220
+
221
+ /************************************************************************/
222
+ /* SfRealloc() */
223
+ /* */
224
+ /* A realloc cover function that will access a NULL pointer as */
225
+ /* a valid input. */
226
+ /************************************************************************/
227
+
228
+ static void * SfRealloc( void * pMem, int nNewSize )
229
+
230
+ {
231
+ if( pMem == NULL )
232
+ return( (void *) malloc(nNewSize) );
233
+ else
234
+ return( (void *) realloc(pMem,nNewSize) );
235
+ }
236
+
237
+ /************************************************************************/
238
+ /* DBFWriteHeader() */
239
+ /* */
240
+ /* This is called to write out the file header, and field */
241
+ /* descriptions before writing any actual data records. This */
242
+ /* also computes all the DBFDataSet field offset/size/decimals */
243
+ /* and so forth values. */
244
+ /************************************************************************/
245
+
246
+ static void DBFWriteHeader(DBFHandle psDBF)
247
+
248
+ {
249
+ unsigned char abyHeader[XBASE_FLDHDR_SZ];
250
+ int i;
251
+
252
+ if( !psDBF->bNoHeader )
253
+ return;
254
+
255
+ psDBF->bNoHeader = FALSE;
256
+
257
+ /* -------------------------------------------------------------------- */
258
+ /* Initialize the file header information. */
259
+ /* -------------------------------------------------------------------- */
260
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
261
+ abyHeader[i] = 0;
262
+
263
+ abyHeader[0] = 0x03; /* memo field? - just copying */
264
+
265
+ /* write out a dummy date */
266
+ abyHeader[1] = 95; /* YY */
267
+ abyHeader[2] = 7; /* MM */
268
+ abyHeader[3] = 26; /* DD */
269
+
270
+ /* record count preset at zero */
271
+
272
+ abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
273
+ abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
274
+
275
+ abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
276
+ abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
277
+
278
+ /* -------------------------------------------------------------------- */
279
+ /* Write the initial 32 byte file header, and all the field */
280
+ /* descriptions. */
281
+ /* -------------------------------------------------------------------- */
282
+ fseek( psDBF->fp, 0, 0 );
283
+ fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
284
+ fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
285
+
286
+ /* -------------------------------------------------------------------- */
287
+ /* Write out the newline character if there is room for it. */
288
+ /* -------------------------------------------------------------------- */
289
+ if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
290
+ {
291
+ char cNewline;
292
+
293
+ cNewline = 0x0d;
294
+ fwrite( &cNewline, 1, 1, psDBF->fp );
295
+ }
296
+ }
297
+
298
+ /************************************************************************/
299
+ /* DBFFlushRecord() */
300
+ /* */
301
+ /* Write out the current record if there is one. */
302
+ /************************************************************************/
303
+
304
+ static void DBFFlushRecord( DBFHandle psDBF )
305
+
306
+ {
307
+ int nRecordOffset;
308
+
309
+ if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
310
+ {
311
+ psDBF->bCurrentRecordModified = FALSE;
312
+
313
+ nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
314
+ + psDBF->nHeaderLength;
315
+
316
+ fseek( psDBF->fp, nRecordOffset, 0 );
317
+ fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
318
+ }
319
+ }
320
+
321
+ /************************************************************************/
322
+ /* DBFUpdateHeader() */
323
+ /************************************************************************/
324
+
325
+ void SHPAPI_CALL
326
+ DBFUpdateHeader( DBFHandle psDBF )
327
+
328
+ {
329
+ unsigned char abyFileHeader[32];
330
+
331
+ if( psDBF->bNoHeader )
332
+ DBFWriteHeader( psDBF );
333
+
334
+ DBFFlushRecord( psDBF );
335
+
336
+ fseek( psDBF->fp, 0, 0 );
337
+ fread( abyFileHeader, 32, 1, psDBF->fp );
338
+
339
+ abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
340
+ abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
341
+ abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
342
+ abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
343
+
344
+ fseek( psDBF->fp, 0, 0 );
345
+ fwrite( abyFileHeader, 32, 1, psDBF->fp );
346
+
347
+ fflush( psDBF->fp );
348
+ }
349
+
350
+ /************************************************************************/
351
+ /* DBFOpen() */
352
+ /* */
353
+ /* Open a .dbf file. */
354
+ /************************************************************************/
355
+
356
+ DBFHandle SHPAPI_CALL
357
+ DBFOpen( const char * pszFilename, const char * pszAccess )
358
+
359
+ {
360
+ DBFHandle psDBF;
361
+ unsigned char *pabyBuf;
362
+ int nFields, nHeadLen, nRecLen, iField, i;
363
+ char *pszBasename, *pszFullname;
364
+
365
+ /* -------------------------------------------------------------------- */
366
+ /* We only allow the access strings "rb" and "r+". */
367
+ /* -------------------------------------------------------------------- */
368
+ if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
369
+ && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
370
+ && strcmp(pszAccess,"r+b") != 0 )
371
+ return( NULL );
372
+
373
+ if( strcmp(pszAccess,"r") == 0 )
374
+ pszAccess = "rb";
375
+
376
+ if( strcmp(pszAccess,"r+") == 0 )
377
+ pszAccess = "rb+";
378
+
379
+ /* -------------------------------------------------------------------- */
380
+ /* Compute the base (layer) name. If there is any extension */
381
+ /* on the passed in filename we will strip it off. */
382
+ /* -------------------------------------------------------------------- */
383
+ pszBasename = (char *) malloc(strlen(pszFilename)+5);
384
+ strcpy( pszBasename, pszFilename );
385
+ for( i = strlen(pszBasename)-1;
386
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
387
+ && pszBasename[i] != '\\';
388
+ i-- ) {}
389
+
390
+ if( pszBasename[i] == '.' )
391
+ pszBasename[i] = '\0';
392
+
393
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
394
+ sprintf( pszFullname, "%s.dbf", pszBasename );
395
+
396
+ psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
397
+ psDBF->fp = fopen( pszFullname, pszAccess );
398
+
399
+ if( psDBF->fp == NULL )
400
+ {
401
+ sprintf( pszFullname, "%s.DBF", pszBasename );
402
+ psDBF->fp = fopen(pszFullname, pszAccess );
403
+ }
404
+
405
+ free( pszBasename );
406
+ free( pszFullname );
407
+
408
+ if( psDBF->fp == NULL )
409
+ {
410
+ free( psDBF );
411
+ return( NULL );
412
+ }
413
+
414
+ psDBF->bNoHeader = FALSE;
415
+ psDBF->nCurrentRecord = -1;
416
+ psDBF->bCurrentRecordModified = FALSE;
417
+
418
+ /* -------------------------------------------------------------------- */
419
+ /* Read Table Header info */
420
+ /* -------------------------------------------------------------------- */
421
+ pabyBuf = (unsigned char *) malloc(500);
422
+ if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
423
+ {
424
+ fclose( psDBF->fp );
425
+ free( pabyBuf );
426
+ free( psDBF );
427
+ return NULL;
428
+ }
429
+
430
+ psDBF->nRecords =
431
+ pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
432
+
433
+ psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
434
+ psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
435
+
436
+ psDBF->nFields = nFields = (nHeadLen - 32) / 32;
437
+
438
+ psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
439
+
440
+ /* -------------------------------------------------------------------- */
441
+ /* Read in Field Definitions */
442
+ /* -------------------------------------------------------------------- */
443
+
444
+ pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
445
+ psDBF->pszHeader = (char *) pabyBuf;
446
+
447
+ fseek( psDBF->fp, 32, 0 );
448
+ if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
449
+ {
450
+ fclose( psDBF->fp );
451
+ free( pabyBuf );
452
+ free( psDBF );
453
+ return NULL;
454
+ }
455
+
456
+ psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
457
+ psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
458
+ psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
459
+ psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
460
+
461
+ for( iField = 0; iField < nFields; iField++ )
462
+ {
463
+ unsigned char *pabyFInfo;
464
+
465
+ pabyFInfo = pabyBuf+iField*32;
466
+
467
+ if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
468
+ {
469
+ psDBF->panFieldSize[iField] = pabyFInfo[16];
470
+ psDBF->panFieldDecimals[iField] = pabyFInfo[17];
471
+ }
472
+ else
473
+ {
474
+ psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
475
+ psDBF->panFieldDecimals[iField] = 0;
476
+ }
477
+
478
+ psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
479
+ if( iField == 0 )
480
+ psDBF->panFieldOffset[iField] = 1;
481
+ else
482
+ psDBF->panFieldOffset[iField] =
483
+ psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
484
+ }
485
+
486
+ return( psDBF );
487
+ }
488
+
489
+ /************************************************************************/
490
+ /* DBFClose() */
491
+ /************************************************************************/
492
+
493
+ void SHPAPI_CALL
494
+ DBFClose(DBFHandle psDBF)
495
+ {
496
+ static char eof = 0x1a;
497
+ char eof_test;
498
+
499
+ /* -------------------------------------------------------------------- */
500
+ /* Write out header if not already written. */
501
+ /* -------------------------------------------------------------------- */
502
+ if( psDBF->bNoHeader )
503
+ DBFWriteHeader( psDBF );
504
+
505
+ DBFFlushRecord( psDBF );
506
+
507
+ /* -------------------------------------------------------------------- */
508
+ /* Update last access date, and number of records if we have */
509
+ /* write access. */
510
+ /* -------------------------------------------------------------------- */
511
+ if( psDBF->bUpdated )
512
+ DBFUpdateHeader( psDBF );
513
+
514
+ /* -------------------------------------------------------------------- */
515
+ /* Add the DBF end-of-file marker after the last record. */
516
+ /* -------------------------------------------------------------------- */
517
+
518
+ fseek(psDBF->fp, -1, SEEK_END);
519
+ fread(&eof_test, 1, 1, psDBF->fp);
520
+ if( eof_test != 0x1a ) /* no EOF exists, so write one */
521
+ {
522
+ fseek(psDBF->fp, 0, SEEK_END);
523
+ fwrite(&eof, 1, 1, psDBF->fp);
524
+ }
525
+
526
+ /* -------------------------------------------------------------------- */
527
+ /* Close, and free resources. */
528
+ /* -------------------------------------------------------------------- */
529
+ fclose( psDBF->fp );
530
+
531
+ if( psDBF->panFieldOffset != NULL )
532
+ {
533
+ free( psDBF->panFieldOffset );
534
+ free( psDBF->panFieldSize );
535
+ free( psDBF->panFieldDecimals );
536
+ free( psDBF->pachFieldType );
537
+ }
538
+
539
+ free( psDBF->pszHeader );
540
+ free( psDBF->pszCurrentRecord );
541
+
542
+ free( psDBF );
543
+
544
+ if( pszStringField != NULL )
545
+ {
546
+ free( pszStringField );
547
+ pszStringField = NULL;
548
+ nStringFieldLen = 0;
549
+ }
550
+ }
551
+
552
+ /************************************************************************/
553
+ /* DBFCreate() */
554
+ /* */
555
+ /* Create a new .dbf file. */
556
+ /************************************************************************/
557
+
558
+ DBFHandle SHPAPI_CALL
559
+ DBFCreate( const char * pszFilename )
560
+
561
+ {
562
+ DBFHandle psDBF;
563
+ FILE *fp;
564
+ char *pszFullname, *pszBasename;
565
+ int i;
566
+
567
+ /* -------------------------------------------------------------------- */
568
+ /* Compute the base (layer) name. If there is any extension */
569
+ /* on the passed in filename we will strip it off. */
570
+ /* -------------------------------------------------------------------- */
571
+ pszBasename = (char *) malloc(strlen(pszFilename)+5);
572
+ strcpy( pszBasename, pszFilename );
573
+ for( i = strlen(pszBasename)-1;
574
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
575
+ && pszBasename[i] != '\\';
576
+ i-- ) {}
577
+
578
+ if( pszBasename[i] == '.' )
579
+ pszBasename[i] = '\0';
580
+
581
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
582
+ sprintf( pszFullname, "%s.dbf", pszBasename );
583
+ free( pszBasename );
584
+
585
+ /* -------------------------------------------------------------------- */
586
+ /* Create the file. */
587
+ /* -------------------------------------------------------------------- */
588
+ fp = fopen( pszFullname, "wb" );
589
+ if( fp == NULL )
590
+ return( NULL );
591
+
592
+ fputc( 0, fp );
593
+ fclose( fp );
594
+
595
+ fp = fopen( pszFullname, "rb+" );
596
+ if( fp == NULL )
597
+ return( NULL );
598
+
599
+ free( pszFullname );
600
+
601
+ /* -------------------------------------------------------------------- */
602
+ /* Create the info structure. */
603
+ /* -------------------------------------------------------------------- */
604
+ psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
605
+
606
+ psDBF->fp = fp;
607
+ psDBF->nRecords = 0;
608
+ psDBF->nFields = 0;
609
+ psDBF->nRecordLength = 1;
610
+ psDBF->nHeaderLength = 33;
611
+ psDBF->bUpdated = FALSE;
612
+
613
+ psDBF->panFieldOffset = NULL;
614
+ psDBF->panFieldSize = NULL;
615
+ psDBF->panFieldDecimals = NULL;
616
+ psDBF->pachFieldType = NULL;
617
+ psDBF->pszHeader = NULL;
618
+
619
+ psDBF->nCurrentRecord = -1;
620
+ psDBF->bCurrentRecordModified = FALSE;
621
+ psDBF->pszCurrentRecord = NULL;
622
+
623
+ psDBF->bNoHeader = TRUE;
624
+
625
+ return( psDBF );
626
+ }
627
+
628
+ /************************************************************************/
629
+ /* DBFAddField() */
630
+ /* */
631
+ /* Add a field to a newly created .dbf file before any records */
632
+ /* are written. */
633
+ /************************************************************************/
634
+
635
+ int SHPAPI_CALL
636
+ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
637
+ DBFFieldType eType, int nWidth, int nDecimals )
638
+
639
+ {
640
+ char *pszFInfo;
641
+ int i;
642
+
643
+ /* -------------------------------------------------------------------- */
644
+ /* Do some checking to ensure we can add records to this file. */
645
+ /* -------------------------------------------------------------------- */
646
+ if( psDBF->nRecords > 0 )
647
+ return( -1 );
648
+
649
+ if( !psDBF->bNoHeader )
650
+ return( -1 );
651
+
652
+ if( eType != FTDouble && nDecimals != 0 )
653
+ return( -1 );
654
+
655
+ if( nWidth < 1 )
656
+ return -1;
657
+
658
+ /* -------------------------------------------------------------------- */
659
+ /* SfRealloc all the arrays larger to hold the additional field */
660
+ /* information. */
661
+ /* -------------------------------------------------------------------- */
662
+ psDBF->nFields++;
663
+
664
+ psDBF->panFieldOffset = (int *)
665
+ SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
666
+
667
+ psDBF->panFieldSize = (int *)
668
+ SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
669
+
670
+ psDBF->panFieldDecimals = (int *)
671
+ SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
672
+
673
+ psDBF->pachFieldType = (char *)
674
+ SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
675
+
676
+ /* -------------------------------------------------------------------- */
677
+ /* Assign the new field information fields. */
678
+ /* -------------------------------------------------------------------- */
679
+ psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
680
+ psDBF->nRecordLength += nWidth;
681
+ psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
682
+ psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
683
+
684
+ if( eType == FTLogical )
685
+ psDBF->pachFieldType[psDBF->nFields-1] = 'L';
686
+ else if( eType == FTString )
687
+ psDBF->pachFieldType[psDBF->nFields-1] = 'C';
688
+ else if( eType == FTDate )
689
+ psDBF->pachFieldType[psDBF->nFields-1] = 'D';
690
+ else
691
+ psDBF->pachFieldType[psDBF->nFields-1] = 'N';
692
+
693
+ /* -------------------------------------------------------------------- */
694
+ /* Extend the required header information. */
695
+ /* -------------------------------------------------------------------- */
696
+ psDBF->nHeaderLength += 32;
697
+ psDBF->bUpdated = FALSE;
698
+
699
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
700
+
701
+ pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
702
+
703
+ for( i = 0; i < 32; i++ )
704
+ pszFInfo[i] = '\0';
705
+
706
+ if( (int) strlen(pszFieldName) < 10 )
707
+ strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
708
+ else
709
+ strncpy( pszFInfo, pszFieldName, 10);
710
+
711
+ pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
712
+
713
+ if( eType == FTString )
714
+ {
715
+ pszFInfo[16] = (unsigned char) (nWidth % 256);
716
+ pszFInfo[17] = (unsigned char) (nWidth / 256);
717
+ }
718
+ else
719
+ {
720
+ pszFInfo[16] = (unsigned char) nWidth;
721
+ pszFInfo[17] = (unsigned char) nDecimals;
722
+ }
723
+
724
+ /* -------------------------------------------------------------------- */
725
+ /* Make the current record buffer appropriately larger. */
726
+ /* -------------------------------------------------------------------- */
727
+ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
728
+ psDBF->nRecordLength);
729
+
730
+ return( psDBF->nFields-1 );
731
+ }
732
+
733
+
734
+ /************************************************************************/
735
+ /* DBFReadSetup() */
736
+ /* */
737
+ /* Prep a record for reading. */
738
+ /************************************************************************/
739
+
740
+ int DBFReadSetup(DBFHandle psDBF, int hEntity)
741
+ {
742
+ int nRecordOffset;
743
+
744
+ /* -------------------------------------------------------------------- */
745
+ /* Verify selection. */
746
+ /* -------------------------------------------------------------------- */
747
+ if( hEntity < 0 || hEntity >= psDBF->nRecords )
748
+ return( 0 );
749
+
750
+ /* -------------------------------------------------------------------- */
751
+ /* Have we read the record? */
752
+ /* -------------------------------------------------------------------- */
753
+ if( psDBF->nCurrentRecord != hEntity )
754
+ {
755
+ DBFFlushRecord( psDBF );
756
+
757
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
758
+
759
+ if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
760
+ {
761
+ fprintf( stderr, "fseek(%d) failed on DBF file.\n",
762
+ nRecordOffset );
763
+ return 0;
764
+ }
765
+
766
+ if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
767
+ 1, psDBF->fp ) != 1 )
768
+ {
769
+ fprintf( stderr, "fread(%d) failed on DBF file.\n",
770
+ psDBF->nRecordLength );
771
+ return 0;
772
+ }
773
+
774
+ psDBF->nCurrentRecord = hEntity;
775
+ }
776
+
777
+ return 1;
778
+
779
+ }
780
+
781
+
782
+ /************************************************************************/
783
+ /* DBFReadDeleted() */
784
+ /* */
785
+ /* Read whether a record is deleted. */
786
+ /************************************************************************/
787
+
788
+ int DBFReadDeleted(DBFHandle psDBF, int hEntity)
789
+ {
790
+ unsigned char *pabyRec;
791
+
792
+ if( ! DBFReadSetup( psDBF, hEntity) )
793
+ return 0;
794
+
795
+ /* get reference to current record */
796
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
797
+
798
+ /* 0x20 => not deleted, 0x24 => deleted */
799
+ return *pabyRec == 0x20 ? 0 : 1;
800
+
801
+ }
802
+
803
+ /************************************************************************/
804
+ /* DBFReadAttribute() */
805
+ /* */
806
+ /* Read one of the attribute fields of a record. */
807
+ /************************************************************************/
808
+
809
+ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
810
+ char chReqType )
811
+
812
+ {
813
+ unsigned char *pabyRec;
814
+ void *pReturnField = NULL;
815
+
816
+ static double dDoubleField;
817
+
818
+ /* -------------------------------------------------------------------- */
819
+ /* Verify selection. */
820
+ /* -------------------------------------------------------------------- */
821
+ if( iField < 0 || iField >= psDBF->nFields )
822
+ return( NULL );
823
+
824
+ if( ! DBFReadSetup( psDBF, hEntity) )
825
+ return( NULL );
826
+
827
+ /* get reference to current record */
828
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
829
+
830
+ /* -------------------------------------------------------------------- */
831
+ /* Ensure our field buffer is large enough to hold this buffer. */
832
+ /* -------------------------------------------------------------------- */
833
+ if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
834
+ {
835
+ nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
836
+ pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
837
+ }
838
+
839
+ /* -------------------------------------------------------------------- */
840
+ /* Extract the requested field. */
841
+ /* -------------------------------------------------------------------- */
842
+ strncpy( pszStringField,
843
+ ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
844
+ psDBF->panFieldSize[iField] );
845
+ pszStringField[psDBF->panFieldSize[iField]] = '\0';
846
+
847
+ pReturnField = pszStringField;
848
+
849
+ /* -------------------------------------------------------------------- */
850
+ /* Decode the field. */
851
+ /* -------------------------------------------------------------------- */
852
+ if( chReqType == 'N' )
853
+ {
854
+ dDoubleField = atof(pszStringField);
855
+ pReturnField = &dDoubleField;
856
+ }
857
+
858
+ /* -------------------------------------------------------------------- */
859
+ /* Should we trim white space off the string attribute value? */
860
+ /* -------------------------------------------------------------------- */
861
+ #ifdef TRIM_DBF_WHITESPACE
862
+ else
863
+ {
864
+ char *pchSrc, *pchDst;
865
+
866
+ pchDst = pchSrc = pszStringField;
867
+ while( *pchSrc == ' ' )
868
+ pchSrc++;
869
+
870
+ while( *pchSrc != '\0' )
871
+ *(pchDst++) = *(pchSrc++);
872
+ *pchDst = '\0';
873
+
874
+ while( pchDst != pszStringField && *(--pchDst) == ' ' )
875
+ *pchDst = '\0';
876
+ }
877
+ #endif
878
+
879
+ return( pReturnField );
880
+ }
881
+
882
+ /************************************************************************/
883
+ /* DBFReadIntAttribute() */
884
+ /* */
885
+ /* Read an integer attribute. */
886
+ /************************************************************************/
887
+
888
+ int SHPAPI_CALL
889
+ DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
890
+
891
+ {
892
+ double *pdValue;
893
+
894
+ pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
895
+
896
+ if( pdValue == NULL )
897
+ return 0;
898
+ else
899
+ return( (int) *pdValue );
900
+ }
901
+
902
+ /************************************************************************/
903
+ /* DBFReadDoubleAttribute() */
904
+ /* */
905
+ /* Read a double attribute. */
906
+ /************************************************************************/
907
+
908
+ double SHPAPI_CALL
909
+ DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
910
+
911
+ {
912
+ double *pdValue;
913
+
914
+ pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
915
+
916
+ if( pdValue == NULL )
917
+ return 0.0;
918
+ else
919
+ return( *pdValue );
920
+ }
921
+
922
+ /************************************************************************/
923
+ /* DBFReadStringAttribute() */
924
+ /* */
925
+ /* Read a string attribute. */
926
+ /************************************************************************/
927
+
928
+ const char SHPAPI_CALL1(*)
929
+ DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
930
+
931
+ {
932
+ return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
933
+ }
934
+
935
+ /************************************************************************/
936
+ /* DBFReadLogicalAttribute() */
937
+ /* */
938
+ /* Read a logical attribute. */
939
+ /************************************************************************/
940
+
941
+ const char SHPAPI_CALL1(*)
942
+ DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
943
+
944
+ {
945
+ return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
946
+ }
947
+
948
+ /************************************************************************/
949
+ /* DBFIsAttributeNULL() */
950
+ /* */
951
+ /* Return TRUE if value for field is NULL. */
952
+ /* */
953
+ /* Contributed by Jim Matthews. */
954
+ /************************************************************************/
955
+
956
+ int SHPAPI_CALL
957
+ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
958
+
959
+ {
960
+ const char *pszValue;
961
+
962
+ pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
963
+
964
+ if( pszValue == NULL )
965
+ return TRUE;
966
+
967
+ switch(psDBF->pachFieldType[iField])
968
+ {
969
+ case 'N':
970
+ case 'F':
971
+ /* NULL numeric fields have value "****************" */
972
+ return pszValue[0] == '*';
973
+
974
+ case 'D':
975
+ /* NULL date fields have value "00000000" */
976
+ return (strncmp(pszValue,"00000000",8) == 0 || strlen(pszValue) == 0);
977
+
978
+ case 'L':
979
+ /* NULL boolean fields have value "?" */
980
+ return pszValue[0] == '?';
981
+
982
+ default:
983
+ /* empty string fields are considered NULL */
984
+ return strlen(pszValue) == 0;
985
+ }
986
+ }
987
+
988
+ /************************************************************************/
989
+ /* DBFGetFieldCount() */
990
+ /* */
991
+ /* Return the number of fields in this table. */
992
+ /************************************************************************/
993
+
994
+ int SHPAPI_CALL
995
+ DBFGetFieldCount( DBFHandle psDBF )
996
+
997
+ {
998
+ return( psDBF->nFields );
999
+ }
1000
+
1001
+ /************************************************************************/
1002
+ /* DBFGetRecordCount() */
1003
+ /* */
1004
+ /* Return the number of records in this table. */
1005
+ /************************************************************************/
1006
+
1007
+ int SHPAPI_CALL
1008
+ DBFGetRecordCount( DBFHandle psDBF )
1009
+
1010
+ {
1011
+ return( psDBF->nRecords );
1012
+ }
1013
+
1014
+ /************************************************************************/
1015
+ /* DBFGetFieldInfo() */
1016
+ /* */
1017
+ /* Return any requested information about the field. */
1018
+ /************************************************************************/
1019
+
1020
+ DBFFieldType SHPAPI_CALL
1021
+ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1022
+ int * pnWidth, int * pnDecimals )
1023
+
1024
+ {
1025
+ if( iField < 0 || iField >= psDBF->nFields )
1026
+ return( FTInvalid );
1027
+
1028
+ if( pnWidth != NULL )
1029
+ *pnWidth = psDBF->panFieldSize[iField];
1030
+
1031
+ if( pnDecimals != NULL )
1032
+ *pnDecimals = psDBF->panFieldDecimals[iField];
1033
+
1034
+ if( pszFieldName != NULL )
1035
+ {
1036
+ int i;
1037
+
1038
+ strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1039
+ pszFieldName[11] = '\0';
1040
+ for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1041
+ pszFieldName[i] = '\0';
1042
+ }
1043
+
1044
+ if ( psDBF->pachFieldType[iField] == 'L' )
1045
+ return( FTLogical);
1046
+
1047
+ else if( psDBF->pachFieldType[iField] == 'D' )
1048
+ return ( FTDate );
1049
+
1050
+ else if( psDBF->pachFieldType[iField] == 'N'
1051
+ || psDBF->pachFieldType[iField] == 'F' )
1052
+ {
1053
+ if( psDBF->panFieldDecimals[iField] > 0 )
1054
+ return( FTDouble );
1055
+ else
1056
+ return( FTInteger );
1057
+ }
1058
+ else
1059
+ {
1060
+ return( FTString );
1061
+ }
1062
+ }
1063
+
1064
+ /************************************************************************/
1065
+ /* DBFWriteAttribute() */
1066
+ /* */
1067
+ /* Write an attribute record to the file. */
1068
+ /************************************************************************/
1069
+
1070
+ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1071
+ void * pValue )
1072
+
1073
+ {
1074
+ int nRecordOffset, i, j, nRetResult = TRUE;
1075
+ unsigned char *pabyRec;
1076
+ char szSField[400], szFormat[20];
1077
+
1078
+ /* -------------------------------------------------------------------- */
1079
+ /* Is this a valid record? */
1080
+ /* -------------------------------------------------------------------- */
1081
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
1082
+ return( FALSE );
1083
+
1084
+ if( psDBF->bNoHeader )
1085
+ DBFWriteHeader(psDBF);
1086
+
1087
+ /* -------------------------------------------------------------------- */
1088
+ /* Is this a brand new record? */
1089
+ /* -------------------------------------------------------------------- */
1090
+ if( hEntity == psDBF->nRecords )
1091
+ {
1092
+ DBFFlushRecord( psDBF );
1093
+
1094
+ psDBF->nRecords++;
1095
+ for( i = 0; i < psDBF->nRecordLength; i++ )
1096
+ psDBF->pszCurrentRecord[i] = ' ';
1097
+
1098
+ psDBF->nCurrentRecord = hEntity;
1099
+ }
1100
+
1101
+ /* -------------------------------------------------------------------- */
1102
+ /* Is this an existing record, but different than the last one */
1103
+ /* we accessed? */
1104
+ /* -------------------------------------------------------------------- */
1105
+ if( psDBF->nCurrentRecord != hEntity )
1106
+ {
1107
+ DBFFlushRecord( psDBF );
1108
+
1109
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1110
+
1111
+ fseek( psDBF->fp, nRecordOffset, 0 );
1112
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1113
+
1114
+ psDBF->nCurrentRecord = hEntity;
1115
+ }
1116
+
1117
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1118
+
1119
+ psDBF->bCurrentRecordModified = TRUE;
1120
+ psDBF->bUpdated = TRUE;
1121
+
1122
+ /* -------------------------------------------------------------------- */
1123
+ /* Translate NULL value to valid DBF file representation. */
1124
+ /* */
1125
+ /* Contributed by Jim Matthews. */
1126
+ /* -------------------------------------------------------------------- */
1127
+ if( pValue == NULL )
1128
+ {
1129
+ switch(psDBF->pachFieldType[iField])
1130
+ {
1131
+ case 'N':
1132
+ case 'F':
1133
+ /* NULL numeric fields have value "****************" */
1134
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1135
+ psDBF->panFieldSize[iField] );
1136
+ break;
1137
+
1138
+ case 'D':
1139
+ /* NULL date fields have value "00000000" */
1140
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1141
+ psDBF->panFieldSize[iField] );
1142
+ break;
1143
+
1144
+ case 'L':
1145
+ /* NULL boolean fields have value "?" */
1146
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1147
+ psDBF->panFieldSize[iField] );
1148
+ break;
1149
+
1150
+ default:
1151
+ /* empty string fields are considered NULL */
1152
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1153
+ psDBF->panFieldSize[iField] );
1154
+ break;
1155
+ }
1156
+ return TRUE;
1157
+ }
1158
+
1159
+ /* -------------------------------------------------------------------- */
1160
+ /* Assign all the record fields. */
1161
+ /* -------------------------------------------------------------------- */
1162
+ switch( psDBF->pachFieldType[iField] )
1163
+ {
1164
+ case 'D':
1165
+ case 'N':
1166
+ case 'F':
1167
+ if( psDBF->panFieldDecimals[iField] == 0 )
1168
+ {
1169
+ int nWidth = psDBF->panFieldSize[iField];
1170
+
1171
+ if( sizeof(szSField)-2 < nWidth )
1172
+ nWidth = sizeof(szSField)-2;
1173
+
1174
+ sprintf( szFormat, "%%%dd", nWidth );
1175
+ sprintf(szSField, szFormat, (int) *((double *) pValue) );
1176
+ if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1177
+ {
1178
+ szSField[psDBF->panFieldSize[iField]] = '\0';
1179
+ nRetResult = FALSE;
1180
+ }
1181
+
1182
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1183
+ szSField, strlen(szSField) );
1184
+ }
1185
+ else
1186
+ {
1187
+ int nWidth = psDBF->panFieldSize[iField];
1188
+
1189
+ if( sizeof(szSField)-2 < nWidth )
1190
+ nWidth = sizeof(szSField)-2;
1191
+
1192
+ sprintf( szFormat, "%%%d.%df",
1193
+ nWidth, psDBF->panFieldDecimals[iField] );
1194
+ sprintf(szSField, szFormat, *((double *) pValue) );
1195
+ if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1196
+ {
1197
+ szSField[psDBF->panFieldSize[iField]] = '\0';
1198
+ nRetResult = FALSE;
1199
+ }
1200
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1201
+ szSField, strlen(szSField) );
1202
+ }
1203
+ break;
1204
+
1205
+ case 'L':
1206
+ if (psDBF->panFieldSize[iField] >= 1 &&
1207
+ (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1208
+ *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1209
+ break;
1210
+
1211
+ default:
1212
+ if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1213
+ {
1214
+ j = psDBF->panFieldSize[iField];
1215
+ nRetResult = FALSE;
1216
+ }
1217
+ else
1218
+ {
1219
+ memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1220
+ psDBF->panFieldSize[iField] );
1221
+ j = strlen((char *) pValue);
1222
+ }
1223
+
1224
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1225
+ (char *) pValue, j );
1226
+ break;
1227
+ }
1228
+
1229
+ return( nRetResult );
1230
+ }
1231
+
1232
+ /************************************************************************/
1233
+ /* DBFWriteAttributeDirectly() */
1234
+ /* */
1235
+ /* Write an attribute record to the file, but without any */
1236
+ /* reformatting based on type. The provided buffer is written */
1237
+ /* as is to the field position in the record. */
1238
+ /************************************************************************/
1239
+
1240
+ int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1241
+ const void * pValue )
1242
+
1243
+ {
1244
+ int nRecordOffset, i, j;
1245
+ unsigned char *pabyRec;
1246
+
1247
+ /* -------------------------------------------------------------------- */
1248
+ /* Is this a valid record? */
1249
+ /* -------------------------------------------------------------------- */
1250
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
1251
+ return( FALSE );
1252
+
1253
+ if( psDBF->bNoHeader )
1254
+ DBFWriteHeader(psDBF);
1255
+
1256
+ /* -------------------------------------------------------------------- */
1257
+ /* Is this a brand new record? */
1258
+ /* -------------------------------------------------------------------- */
1259
+ if( hEntity == psDBF->nRecords )
1260
+ {
1261
+ DBFFlushRecord( psDBF );
1262
+
1263
+ psDBF->nRecords++;
1264
+ for( i = 0; i < psDBF->nRecordLength; i++ )
1265
+ psDBF->pszCurrentRecord[i] = ' ';
1266
+
1267
+ psDBF->nCurrentRecord = hEntity;
1268
+ }
1269
+
1270
+ /* -------------------------------------------------------------------- */
1271
+ /* Is this an existing record, but different than the last one */
1272
+ /* we accessed? */
1273
+ /* -------------------------------------------------------------------- */
1274
+ if( psDBF->nCurrentRecord != hEntity )
1275
+ {
1276
+ DBFFlushRecord( psDBF );
1277
+
1278
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1279
+
1280
+ fseek( psDBF->fp, nRecordOffset, 0 );
1281
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1282
+
1283
+ psDBF->nCurrentRecord = hEntity;
1284
+ }
1285
+
1286
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1287
+
1288
+ /* -------------------------------------------------------------------- */
1289
+ /* Assign all the record fields. */
1290
+ /* -------------------------------------------------------------------- */
1291
+ if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1292
+ j = psDBF->panFieldSize[iField];
1293
+ else
1294
+ {
1295
+ memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1296
+ psDBF->panFieldSize[iField] );
1297
+ j = strlen((char *) pValue);
1298
+ }
1299
+
1300
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1301
+ (char *) pValue, j );
1302
+
1303
+ psDBF->bCurrentRecordModified = TRUE;
1304
+ psDBF->bUpdated = TRUE;
1305
+
1306
+ return( TRUE );
1307
+ }
1308
+
1309
+ /************************************************************************/
1310
+ /* DBFWriteDoubleAttribute() */
1311
+ /* */
1312
+ /* Write a double attribute. */
1313
+ /************************************************************************/
1314
+
1315
+ int SHPAPI_CALL
1316
+ DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1317
+ double dValue )
1318
+
1319
+ {
1320
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1321
+ }
1322
+
1323
+ /************************************************************************/
1324
+ /* DBFWriteIntegerAttribute() */
1325
+ /* */
1326
+ /* Write a integer attribute. */
1327
+ /************************************************************************/
1328
+
1329
+ int SHPAPI_CALL
1330
+ DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1331
+ int nValue )
1332
+
1333
+ {
1334
+ double dValue = nValue;
1335
+
1336
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1337
+ }
1338
+
1339
+ /************************************************************************/
1340
+ /* DBFWriteStringAttribute() */
1341
+ /* */
1342
+ /* Write a string attribute. */
1343
+ /************************************************************************/
1344
+
1345
+ int SHPAPI_CALL
1346
+ DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1347
+ const char * pszValue )
1348
+
1349
+ {
1350
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1351
+ }
1352
+
1353
+ /************************************************************************/
1354
+ /* DBFWriteNULLAttribute() */
1355
+ /* */
1356
+ /* Write a string attribute. */
1357
+ /************************************************************************/
1358
+
1359
+ int SHPAPI_CALL
1360
+ DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1361
+
1362
+ {
1363
+ return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1364
+ }
1365
+
1366
+ /************************************************************************/
1367
+ /* DBFWriteLogicalAttribute() */
1368
+ /* */
1369
+ /* Write a logical attribute. */
1370
+ /************************************************************************/
1371
+
1372
+ int SHPAPI_CALL
1373
+ DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1374
+ const char lValue)
1375
+
1376
+ {
1377
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1378
+ }
1379
+
1380
+ /************************************************************************/
1381
+ /* DBFWriteTuple() */
1382
+ /* */
1383
+ /* Write an attribute record to the file. */
1384
+ /************************************************************************/
1385
+
1386
+ int SHPAPI_CALL
1387
+ DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1388
+
1389
+ {
1390
+ int nRecordOffset, i;
1391
+ unsigned char *pabyRec;
1392
+
1393
+ /* -------------------------------------------------------------------- */
1394
+ /* Is this a valid record? */
1395
+ /* -------------------------------------------------------------------- */
1396
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
1397
+ return( FALSE );
1398
+
1399
+ if( psDBF->bNoHeader )
1400
+ DBFWriteHeader(psDBF);
1401
+
1402
+ /* -------------------------------------------------------------------- */
1403
+ /* Is this a brand new record? */
1404
+ /* -------------------------------------------------------------------- */
1405
+ if( hEntity == psDBF->nRecords )
1406
+ {
1407
+ DBFFlushRecord( psDBF );
1408
+
1409
+ psDBF->nRecords++;
1410
+ for( i = 0; i < psDBF->nRecordLength; i++ )
1411
+ psDBF->pszCurrentRecord[i] = ' ';
1412
+
1413
+ psDBF->nCurrentRecord = hEntity;
1414
+ }
1415
+
1416
+ /* -------------------------------------------------------------------- */
1417
+ /* Is this an existing record, but different than the last one */
1418
+ /* we accessed? */
1419
+ /* -------------------------------------------------------------------- */
1420
+ if( psDBF->nCurrentRecord != hEntity )
1421
+ {
1422
+ DBFFlushRecord( psDBF );
1423
+
1424
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1425
+
1426
+ fseek( psDBF->fp, nRecordOffset, 0 );
1427
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1428
+
1429
+ psDBF->nCurrentRecord = hEntity;
1430
+ }
1431
+
1432
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1433
+
1434
+ memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1435
+
1436
+ psDBF->bCurrentRecordModified = TRUE;
1437
+ psDBF->bUpdated = TRUE;
1438
+
1439
+ return( TRUE );
1440
+ }
1441
+
1442
+ /************************************************************************/
1443
+ /* DBFReadTuple() */
1444
+ /* */
1445
+ /* Read one of the attribute fields of a record. */
1446
+ /************************************************************************/
1447
+
1448
+ const char SHPAPI_CALL1(*)
1449
+ DBFReadTuple(DBFHandle psDBF, int hEntity )
1450
+
1451
+ {
1452
+ int nRecordOffset;
1453
+ unsigned char *pabyRec;
1454
+ static char *pReturnTuple = NULL;
1455
+
1456
+ static int nTupleLen = 0;
1457
+
1458
+ /* -------------------------------------------------------------------- */
1459
+ /* Have we read the record? */
1460
+ /* -------------------------------------------------------------------- */
1461
+ if( hEntity < 0 || hEntity >= psDBF->nRecords )
1462
+ return( NULL );
1463
+
1464
+ if( psDBF->nCurrentRecord != hEntity )
1465
+ {
1466
+ DBFFlushRecord( psDBF );
1467
+
1468
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1469
+
1470
+ fseek( psDBF->fp, nRecordOffset, 0 );
1471
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1472
+
1473
+ psDBF->nCurrentRecord = hEntity;
1474
+ }
1475
+
1476
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1477
+
1478
+ if ( nTupleLen < psDBF->nRecordLength) {
1479
+ nTupleLen = psDBF->nRecordLength;
1480
+ pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1481
+ }
1482
+
1483
+ memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1484
+
1485
+ return( pReturnTuple );
1486
+ }
1487
+
1488
+ /************************************************************************/
1489
+ /* DBFCloneEmpty() */
1490
+ /* */
1491
+ /* Read one of the attribute fields of a record. */
1492
+ /************************************************************************/
1493
+
1494
+ DBFHandle SHPAPI_CALL
1495
+ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1496
+ {
1497
+ DBFHandle newDBF;
1498
+
1499
+ newDBF = DBFCreate ( pszFilename );
1500
+ if ( newDBF == NULL ) return ( NULL );
1501
+
1502
+ newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1503
+ memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1504
+
1505
+ newDBF->nFields = psDBF->nFields;
1506
+ newDBF->nRecordLength = psDBF->nRecordLength;
1507
+ newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1508
+
1509
+ newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1510
+ memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1511
+ newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1512
+ memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1513
+ newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1514
+ memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1515
+ newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1516
+ memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1517
+
1518
+ newDBF->bNoHeader = TRUE;
1519
+ newDBF->bUpdated = TRUE;
1520
+
1521
+ DBFWriteHeader ( newDBF );
1522
+ DBFClose ( newDBF );
1523
+
1524
+ newDBF = DBFOpen ( pszFilename, "rb+" );
1525
+
1526
+ return ( newDBF );
1527
+ }
1528
+
1529
+ /************************************************************************/
1530
+ /* DBFGetNativeFieldType() */
1531
+ /* */
1532
+ /* Return the DBase field type for the specified field. */
1533
+ /* */
1534
+ /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1535
+ /* 'N' (Numeric, with or without decimal), */
1536
+ /* 'L' (Logical), */
1537
+ /* 'M' (Memo: 10 digits .DBT block ptr) */
1538
+ /************************************************************************/
1539
+
1540
+ char SHPAPI_CALL
1541
+ DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1542
+
1543
+ {
1544
+ if( iField >=0 && iField < psDBF->nFields )
1545
+ return psDBF->pachFieldType[iField];
1546
+
1547
+ return ' ';
1548
+ }
1549
+
1550
+ /************************************************************************/
1551
+ /* str_to_upper() */
1552
+ /************************************************************************/
1553
+
1554
+ static void str_to_upper (char *string)
1555
+ {
1556
+ int len;
1557
+ short i = -1;
1558
+
1559
+ len = strlen (string);
1560
+
1561
+ while (++i < len)
1562
+ if (isalpha(string[i]) && islower(string[i]))
1563
+ string[i] = (char) toupper ((int)string[i]);
1564
+ }
1565
+
1566
+ /************************************************************************/
1567
+ /* DBFGetFieldIndex() */
1568
+ /* */
1569
+ /* Get the index number for a field in a .dbf file. */
1570
+ /* */
1571
+ /* Contributed by Jim Matthews. */
1572
+ /************************************************************************/
1573
+
1574
+ int SHPAPI_CALL
1575
+ DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1576
+
1577
+ {
1578
+ char name[12], name1[12], name2[12];
1579
+ int i;
1580
+
1581
+ strncpy(name1, pszFieldName,11);
1582
+ name1[11] = '\0';
1583
+ str_to_upper(name1);
1584
+
1585
+ for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1586
+ {
1587
+ DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1588
+ strncpy(name2,name,11);
1589
+ str_to_upper(name2);
1590
+
1591
+ if(!strncmp(name1,name2,10))
1592
+ return(i);
1593
+ }
1594
+ return(-1);
1595
+ }