geo_coder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }