root/tags/1.1.7/loader/shp2pgsql.c

Revision 2513, 43.0 KB (checked in by mschaber, 5 years ago)

sanitized usage info output on loader/dumper

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mime-type set to text/plain
Line 
1/**********************************************************************
2 * $Id$
3 *
4 * PostGIS - Spatial Types for PostgreSQL
5 * http://postgis.refractions.net
6 * Copyright 2001-2003 Refractions Research Inc.
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of hte GNU General Public Licence. See the COPYING file.
10 *
11 **********************************************************************
12 * Using shapelib 1.2.8, this program reads in shape files and
13 * processes it's contents into a Insert statements which can be
14 * easily piped into a database frontend.
15 * Specifically designed to insert type 'geometry' (a custom
16 * written PostgreSQL type) for the shape files and PostgreSQL
17 * standard types for all attributes of the entity.
18 *
19 * Original Author: Jeff Lounsbury, jeffloun@refractions.net
20 *
21 * Maintainer: Sandro Santilli, strk@refractions.net
22 *
23 **********************************************************************/
24
25#include "../config.h"
26#include "shapefil.h"
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <ctype.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <unistd.h>
34#include <errno.h>
35#include "getopt.h"
36#ifdef HAVE_ICONV_H
37#include <iconv.h>
38#endif
39
40
41#define POINTTYPE       1
42#define LINETYPE        2
43#define POLYGONTYPE     3
44#define MULTIPOINTTYPE  4
45#define MULTILINETYPE   5
46#define MULTIPOLYGONTYPE        6
47#define COLLECTIONTYPE  7
48
49#define WKBZOFFSET 0x80000000
50#define WKBMOFFSET 0x40000000
51
52/*#define DEBUG 1 */
53
54typedef struct {double x, y, z, m;} Point;
55
56typedef struct Ring {
57        Point *list;            /* list of points */
58        struct Ring  *next;
59        int n;                  /* number of points in list */
60        unsigned int linked;    /* number of "next" rings */
61} Ring;
62
63/* Values for null_policy global */
64enum {
65        insert_null,
66        skip_null,
67        abort_on_null
68};
69
70/* globals */
71int     dump_format = 0; /* 0=insert statements, 1 = dump */
72int     simple_geometries = 0; /* 0 = MULTILINESTRING/MULTIPOLYGON, 1 = LINESTRING/POLYGON */
73int     quoteidentifiers = 0;
74int     forceint4 = 0;
75int     createindex = 0;
76char    opt = ' ';
77char    *col_names = NULL;
78char    *pgtype;
79int     istypeM = 0;
80int     pgdims;
81unsigned int wkbtype;
82char    *shp_file = NULL;
83int     hwgeom = 0; /* old (hwgeom) mode */
84#ifdef USE_ICONV
85char    *encoding=NULL;
86#endif
87int null_policy = insert_null;
88
89DBFFieldType *types;    /* Fields type, width and precision */
90SHPHandle  hSHPHandle;
91DBFHandle  hDBFHandle;
92int shpfiletype;
93SHPObject  *obj=NULL;
94int     *widths;
95int     *precisions;
96char    *table=NULL,*schema=NULL,*geom=NULL;
97int     num_fields,num_records,num_entities;
98char    **field_names;
99char    *sr_id = NULL;
100
101/* Prototypes */
102int Insert_attributes(DBFHandle hDBFHandle, int row);
103char *make_good_string(char *str);
104char *protect_quotes_string(char *str);
105int PIP( Point P, Point* V, int n );
106void *safe_malloc(size_t size);
107void CreateTable(void);
108void CreateIndex(void);
109void usage(char *me, int exitcode, FILE* out);
110void InsertPoint(void);
111void InsertPointWKT(void);
112void InsertMultiPoint(void);
113void InsertPolygon(void);
114void InsertPolygonWKT(void);
115void InsertLineString(int id);
116void InsertLineStringWKT(int id);
117int ParseCmdline(int ARGC, char **ARGV);
118void SetPgType(void);
119char *dump_ring(Ring *ring);
120#ifdef USE_ICONV
121char *utf8(const char *fromcode, char *inputbuf);
122#endif
123int FindPolygons(SHPObject *obj, Ring ***Out);
124void ReleasePolygons(Ring **polys, int npolys);
125void DropTable(char *schema, char *table, char *geom);
126void GetFieldsSpec(void);
127void LoadData(void);
128void OpenShape(void);
129void LowerCase(char *s);
130void Cleanup(void);
131
132
133/* WKB */
134static char getEndianByte(void);
135static void print_wkb_bytes(unsigned char* ptr, unsigned int cnt, size_t size);
136static void print_wkb_byte(unsigned char val);
137static void print_wkb_int(int val);
138static void print_wkb_double(double val);
139
140static char rcsid[] =
141  "$Id$";
142
143void *safe_malloc(size_t size)
144{
145        void *ret = malloc(size);
146        if ( ! ret ) {
147                fprintf(stderr, "Out of virtual memory\n");
148                exit(1);
149        }
150        return ret;
151}
152
153#define malloc(x) safe_malloc(x)
154
155
156char *
157make_good_string(char *str)
158{
159        /*
160         * find all the tabs and make them \<tab>s
161         *
162         * 1. find # of tabs
163         * 2. make new string
164         *
165         * we dont escape already escaped tabs
166         */
167
168        char *result;
169        char *ptr, *optr;
170        int toescape = 0;
171        size_t size;
172#ifdef USE_ICONV
173        char *utf8str=NULL;
174
175        if ( encoding )
176        {
177                utf8str=utf8(encoding, str);
178                if ( ! utf8str ) exit(1);
179                str = utf8str;
180        }
181#endif
182
183        ptr = str;
184
185        while (*ptr) {
186                if ( *ptr == '\t' || *ptr == '\\' ) toescape++;
187                ptr++;
188        }
189
190        if (toescape == 0) return str;
191
192        size = ptr-str+toescape+1;
193
194        result = calloc(1, size);
195
196        optr=result;
197        ptr=str;
198        while (*ptr) {
199                if ( *ptr == '\t' || *ptr == '\\' ) *optr++='\\';
200                *optr++=*ptr++;
201        }
202        *optr='\0';
203
204#ifdef USE_ICONV
205        if ( encoding ) free(str);
206#endif
207
208        return result;
209       
210}
211
212char *
213protect_quotes_string(char *str)
214{
215        /*
216         * find all quotes and make them \quotes
217         * find all '\' and make them '\\'
218         *       
219         * 1. find # of characters
220         * 2. make new string
221         */
222
223        char    *result;
224        char    *ptr, *optr;
225        int     toescape = 0;
226        size_t size;
227#ifdef USE_ICONV
228        char *utf8str=NULL;
229
230        if ( encoding )
231        {
232                utf8str=utf8(encoding, str);
233                if ( ! utf8str ) exit(1);
234                str = utf8str;
235        }
236#endif
237
238        ptr = str;
239
240        while (*ptr) {
241                if ( *ptr == '\'' || *ptr == '\\' ) toescape++;
242                ptr++;
243        }
244
245        if (toescape == 0) return str;
246       
247        size = ptr-str+toescape+1;
248
249        result = calloc(1, size);
250
251        optr=result;
252        ptr=str;
253        while (*ptr) {
254                if ( *ptr == '\'' || *ptr == '\\' ) *optr++='\\';
255                *optr++=*ptr++;
256        }
257        *optr='\0';
258
259#ifdef USE_ICONV
260        if ( encoding ) free(str);
261#endif
262
263        return result;
264}
265
266
267
268/*
269 * PIP(): crossing number test for a point in a polygon
270 *      input:   P = a point,
271 *               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
272 *      returns: 0 = outside, 1 = inside
273 */
274int
275PIP( Point P, Point* V, int n )
276{
277        int cn = 0;    /* the crossing number counter */
278        int i;
279
280    /* loop through all edges of the polygon */
281    for (i=0; i<n-1; i++) {    /* edge from V[i] to V[i+1] */
282       if (((V[i].y <= P.y) && (V[i+1].y > P.y))    /* an upward crossing */
283        || ((V[i].y > P.y) && (V[i+1].y <= P.y))) { /* a downward crossing */
284            double vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
285            if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) /* P.x < intersect */
286                ++cn;   /* a valid crossing of y=P.y right of P.x */
287        }
288    }
289    return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
290
291}
292
293
294/*Insert the attributes from the correct row of dbf file */
295
296int
297Insert_attributes(DBFHandle hDBFHandle, int row)
298{
299   int i,num_fields;
300   char val[1024];
301   char *escval;
302
303   num_fields = DBFGetFieldCount( hDBFHandle );
304   for( i = 0; i < num_fields; i++ )
305   {
306      if(DBFIsAttributeNULL( hDBFHandle, row, i))
307      {
308         if(dump_format)
309         {
310            printf("\\N");
311            printf("\t");
312         }
313         else
314         {
315            printf("NULL");
316            printf(",");
317         }
318      }
319
320      else /* Attribute NOT NULL */
321      {
322         switch (types[i])
323         {
324            case FTInteger:
325            case FTDouble:
326               if ( -1 == snprintf(val, 1024, "%s",
327                     DBFReadStringAttribute(hDBFHandle, row, i)) )
328               {
329                  fprintf(stderr, "Warning: field %d name trucated\n", i);
330                  val[1023] = '\0';
331               }
332               /* pg_atoi() does not do this */
333               if ( val[0] == '\0' ) { val[0] = '0'; val[1] = '\0'; }
334               if ( val[strlen(val)-1] == '.' ) val[strlen(val)-1] = '\0';
335               break;
336
337            case FTString:
338            case FTLogical:
339            case FTDate:
340               if ( -1 == snprintf(val, 1024, "%s",
341                     DBFReadStringAttribute(hDBFHandle, row, i)) )
342               {
343                  fprintf(stderr, "Warning: field %d name trucated\n", i);
344                  val[1023] = '\0';
345               }
346               break;
347
348            default:
349               fprintf(stderr,
350                  "Error: field %d has invalid or unknown field type (%d)\n",
351                  i, types[i]);
352               exit(1);
353         }
354 
355                        if (dump_format) {
356                                escval = make_good_string(val);
357                                printf("%s", escval);
358                                printf("\t");
359                        } else {
360                                escval = protect_quotes_string(val);
361                                printf("'%s'", escval);
362                                printf(",");
363                        }
364                        if ( val != escval ) free(escval);
365                 }
366        }
367        return 1;
368}
369
370
371
372
373/*
374 * main()     
375 * see description at the top of this file
376 */
377int
378main (int ARGC, char **ARGV)
379{
380
381        /*
382         * Parse command line
383         */
384        if ( ! ParseCmdline(ARGC, ARGV) ) usage(ARGV[0], 2, stderr);
385
386        /*
387         * Open shapefile and initialize globals
388         */
389        OpenShape();
390
391        /*
392         * Compute output geometry type
393         */
394        SetPgType();
395
396        fprintf(stderr, "Shapefile type: %s\n", SHPTypeName(shpfiletype));
397        fprintf(stderr, "Postgis type: %s[%d]\n", pgtype, pgdims);
398
399#ifdef USE_ICONV
400        if ( encoding )
401        {
402                printf("SET CLIENT_ENCODING TO UTF8;\n");
403        }
404#endif /* defined USE_ICONV */
405
406        /*
407         * Drop table if requested
408         */
409        if(opt == 'd') DropTable(schema, table, geom);
410
411        /*
412         * Get col names and types for table creation
413         * and data load.
414         */
415        GetFieldsSpec();
416
417        printf("BEGIN;\n");
418
419        /*
420         * If not in 'append' mode create the spatial table
421         */
422        if(opt != 'a') CreateTable();
423
424        /*
425         * Create GiST index if requested
426         */
427        if(createindex) CreateIndex();
428
429        /*
430         * Generate INSERT or COPY lines
431         */
432        if(opt != 'p') LoadData();
433
434        printf("END;\n"); /* End the last transaction */
435
436
437        return 0;
438}/*end main() */
439
440void
441LowerCase(char *s)
442{
443        int j;
444        for (j=0; j<strlen(s); j++) s[j] = tolower(s[j]);
445}
446
447void
448Cleanup(void)
449{
450        if ( col_names ) free(col_names);
451}
452
453void
454OpenShape(void)
455{
456        int j;
457        SHPObject *obj=NULL;
458
459        hSHPHandle = SHPOpen( shp_file, "rb" );
460        if (hSHPHandle == NULL) {
461                fprintf(stderr, "%s: shape (.shp) or index files (.shx) can not be opened.\n", shp_file);
462                exit(-1);
463        }
464        hDBFHandle = DBFOpen( shp_file, "rb" );
465        if (hSHPHandle == NULL || hDBFHandle == NULL){
466                fprintf(stderr, "%s: dbf file (.dbf) can not be opened.\n",
467                        shp_file);
468                exit(-1);
469        }
470        SHPGetInfo(hSHPHandle, &num_entities, &shpfiletype, NULL, NULL);
471
472        if ( null_policy == abort_on_null )
473        {
474                for (j=0; j<num_entities; j++)
475                {
476                        obj = SHPReadObject(hSHPHandle,j);
477                        if ( ! obj )
478                        {
479                fprintf(stderr, "Error reading shape object %d\n", j);
480                exit(1);
481                        }
482                        if ( obj->nVertices == 0 )
483                        {
484                fprintf(stderr, "Empty geometries found, aborted.\n");
485                exit(1);
486                        }
487                        SHPDestroyObject(obj);
488                }
489        }
490
491}
492
493void
494CreateTable(void)
495{
496        int j;
497        int field_precision, field_width;
498        DBFFieldType type = -1;
499
500        /*
501         * Create a table for inserting the shapes into with appropriate
502         * columns and types
503         */
504
505        if ( schema )
506        {
507                printf("CREATE TABLE \"%s\".\"%s\" (gid serial PRIMARY KEY",
508                        schema, table);
509        }
510        else
511        {
512                printf("CREATE TABLE \"%s\" (gid serial PRIMARY KEY", table);
513        }
514
515        for(j=0;j<num_fields;j++)
516        {
517                type = types[j];
518                field_width = widths[j];
519                field_precision = precisions[j];
520
521                printf(",\n\"%s\" ", field_names[j]);
522
523                if(type == FTString)
524                {
525                        /* use DBF attribute size as maximum width */
526                        printf ("varchar(%d)", field_width);
527                }
528                else if (type == FTDate)
529                {
530                        printf ("date");
531                }
532                else if (type == FTInteger)
533                {
534                        if ( forceint4 )
535                        {
536                                printf ("int4");
537                        }
538                        else if  ( field_width <= 5 )
539                        {
540                                printf ("int2");
541                        }
542                        else if  ( field_width <= 10 )
543                        {
544                                printf ("int4");
545                        }
546                        else if  ( field_width <= 19 )
547                        {
548                                printf ("int8");
549                        }
550                        else
551                        {
552                                printf("numeric(%d,0)",
553                                        field_width);
554                        }
555                }
556                else if(type == FTDouble)
557                {
558                        if( field_width > 18 )
559                        {
560                                printf ("numeric");
561                        }
562                        else
563                        {
564                                printf ("float8");
565                        }
566                }
567                else if(type == FTLogical)
568                {
569                        printf ("boolean");
570                }
571                else
572                {
573                        printf ("Invalid type in DBF file");
574                }
575        }
576        printf (");\n");
577
578        /* Create the geometry column with an addgeometry call */
579        if ( schema )
580        {
581                printf("SELECT AddGeometryColumn('%s','%s','%s','%s',",
582                        schema, table, geom, sr_id);
583        }
584        else
585        {
586                printf("SELECT AddGeometryColumn('','%s','%s','%s',",
587                        table, geom, sr_id);
588        }
589
590        printf("'%s',%d);\n", pgtype, pgdims);
591}
592
593void
594CreateIndex(void)
595{
596        /*
597         * Create gist index
598         */
599        if ( schema )
600        {
601                printf("CREATE INDEX \"%s_%s_gist\" ON \"%s\".\"%s\" using gist (\"%s\" gist_geometry_ops);\n", table, geom, schema, table, geom);
602        }
603        else
604        {
605                printf("CREATE INDEX \"%s_%s_gist\" ON \"%s\" using gist (\"%s\" gist_geometry_ops);\n", table, geom, table, geom);
606        }
607}
608
609void
610LoadData(void)
611{
612        int j, trans=0;
613
614        if (dump_format){
615                if ( schema )
616                {
617                        printf("COPY \"%s\".\"%s\" %s FROM stdin;\n",
618                                schema, table, col_names);
619                }
620                else
621                {
622                        printf("COPY \"%s\" %s FROM stdin;\n",
623                                table, col_names);
624                }
625        }
626
627
628        /**************************************************************
629         *
630         *   MAIN SHAPE OBJECTS SCAN
631         *
632         **************************************************************/
633        for (j=0; j<num_entities; j++)
634        {
635                /*wrap a transaction block around each 250 inserts... */
636                if ( ! dump_format )
637                {
638                        if (trans == 250) {
639                                trans=0;
640                                printf("END;\n");
641                                printf("BEGIN;\n");
642                        }
643                }
644                trans++;
645                /* transaction stuff done */
646
647                /*open the next object */
648                obj = SHPReadObject(hSHPHandle,j);
649                if ( ! obj )
650                {
651                        fprintf(stderr, "Error reading shape object %d\n", j);
652                        exit(1);
653                }
654
655                if ( null_policy == skip_null && obj->nVertices == 0 )
656                {
657                        SHPDestroyObject(obj);
658                        continue;
659                }
660
661                if (!dump_format)
662                {
663                        if ( schema )
664                        {
665                                printf("INSERT INTO \"%s\".\"%s\" %s VALUES (",
666                                        schema, table, col_names);
667                        }
668                        else
669                        {
670                                printf("INSERT INTO \"%s\" %s VALUES (",
671                                        table, col_names);
672                        }
673                }
674                Insert_attributes(hDBFHandle,j);
675
676                /* ---------- NULL SHAPE ----------------- */
677                if (obj->nVertices == 0)
678                {
679                        if (dump_format) printf("\\N\n");
680                        else printf("NULL);\n");
681                        SHPDestroyObject(obj); 
682                        continue;
683                }
684
685                switch (obj->nSHPType)
686                {
687                        case SHPT_POLYGON:
688                        case SHPT_POLYGONM:
689                        case SHPT_POLYGONZ:
690                                if ( hwgeom ) InsertPolygonWKT();
691                                else InsertPolygon();
692                                break;
693
694                        case SHPT_POINT:
695                        case SHPT_POINTM:
696                        case SHPT_POINTZ:
697                                if ( hwgeom ) InsertPointWKT();
698                                else InsertPoint();
699                                break;
700
701                        case SHPT_MULTIPOINT:
702                        case SHPT_MULTIPOINTM:
703                        case SHPT_MULTIPOINTZ:
704                                if ( hwgeom ) InsertPointWKT();
705                                else InsertMultiPoint();
706                                break;
707
708                        case SHPT_ARC:
709                        case SHPT_ARCM:
710                        case SHPT_ARCZ:
711                                if ( hwgeom ) InsertLineStringWKT(j);
712                                else InsertLineString(j);
713                                break;
714
715                        default:
716                                printf ("\n\n**** Type is NOT SUPPORTED, type id = %d ****\n\n",
717                                        obj->nSHPType);
718                                break;
719
720                }
721               
722                SHPDestroyObject(obj); 
723
724        } /* END of MAIN SHAPE OBJECT LOOP */
725
726
727        if ((dump_format) ) {
728                printf("\\.\n");
729
730        }
731}
732
733void
734usage(char *me, int exitcode, FILE* out)
735{
736        fprintf(out, "RCSID: %s RELEASE: %s\n", rcsid, POSTGIS_VERSION);
737        fprintf(out, "USAGE: %s [<options>] <shapefile> [<schema>.]<table>\n", me);
738        fprintf(out, "OPTIONS:\n");
739        fprintf(out, "  -s <srid>  Set the SRID field. If not specified it defaults to -1.\n");
740        fprintf(out, "  (-d|a|c|p) These are mutually exclusive options:\n");
741        fprintf(out, "      -d  Drops the table, then recreates it and populates\n");
742        fprintf(out, "          it with current shape file data.\n");
743        fprintf(out, "      -a  Appends shape file into current table, must be\n");
744        fprintf(out, "          exactly the same table schema.\n");
745        fprintf(out, "      -c  Creates a new table and populates it, this is the\n");
746        fprintf(out, "          default if you do not specify any options.\n");
747        fprintf(out, "      -p  Prepare mode, only creates the table.\n");
748        fprintf(out, "  -g <geometry_column> Specify the name of the geometry column\n");
749        fprintf(out, "     (mostly useful in append mode).\n");
750        fprintf(out, "  -D  Use postgresql dump format (defaults to sql insert statments.\n");
751        fprintf(out, "  -k  Keep postgresql identifiers case.\n");
752        fprintf(out, "  -i  Use int4 type for all integer dbf fields.\n");
753        fprintf(out, "  -I  Create a GiST index on the geometry column.\n");
754        fprintf(out, "  -S  Generate simple geometries instead of MULTI geometries.\n");
755        fprintf(out, "  -w  Use wkt format (for postgis-0.x support - drops M - drifts coordinates).\n");
756#ifdef USE_ICONV
757        fprintf(out, "  -W <encoding> Specify the character encoding of Shape's\n");
758        fprintf(out, "     attribute column. (default : \"ASCII\")\n");
759#endif
760        fprintf(out, "  -N <policy> Specify NULL geometries handling policy (insert,skip,abort)\n");
761        fprintf(out, "  -? Display this help screen\n");
762        exit (exitcode);
763}
764
765void
766InsertLineString(int id)
767{
768        int pi; /* part index */
769        unsigned int subtype = LINETYPE | (wkbtype&WKBZOFFSET) |
770                (wkbtype&WKBMOFFSET);
771
772        /* Invalid (MULTI)Linestring */
773        if ( obj->nVertices < 2 )
774        {
775                fprintf(stderr,
776                        "MULTILINESTRING %d as %d vertices, set to NULL\n",
777                        id, obj->nVertices);
778                if (dump_format) printf("\\N\n");
779                else printf("NULL);\n");
780
781                return;
782        }
783
784        if (!dump_format) printf("'");
785        if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
786
787        if (simple_geometries==0) // We write MULTI geometries, so generate Header
788        {
789                print_wkb_byte(getEndianByte());
790                print_wkb_int(wkbtype);
791                print_wkb_int(obj->nParts); /* npolys */
792        }
793        else if ((obj->nParts)!=1) // We write Non-MULTI geometries, but have several parts:
794        {
795                fprintf(stderr, "We have a MultiLineString with %d parts, can't use -S switch!\n", obj->nParts);
796                exit(1);               
797        }
798
799        for (pi=0; pi<obj->nParts; pi++)
800        {
801                int vi; /* vertex index */
802                int vs; /* start vertex */
803                int ve; /* end vertex */
804
805                print_wkb_byte(getEndianByte());
806                print_wkb_int(subtype);
807
808                /* Set start and end vertexes */
809                if ( pi==obj->nParts-1 ) ve = obj->nVertices;
810                else ve = obj->panPartStart[pi+1];
811                vs = obj->panPartStart[pi];
812
813                print_wkb_int(ve-vs);
814                for ( vi=vs; vi<ve; vi++)
815                {
816                        print_wkb_double(obj->padfX[vi]);
817                        print_wkb_double(obj->padfY[vi]);
818                        if ( wkbtype & WKBZOFFSET )
819                                print_wkb_double(obj->padfZ[vi]);
820                        if ( wkbtype & WKBMOFFSET )
821                                print_wkb_double(obj->padfM[vi]);
822                }
823        }
824
825        if (dump_format) printf("\n");
826        else printf("');\n");
827}
828
829void
830InsertLineStringWKT(int id)
831{
832        int pi; /* part index */
833
834        /* Invalid (MULTI)Linestring */
835        if ( obj->nVertices < 2 )
836        {
837                fprintf(stderr,
838                        "MULTILINESTRING %d as %d vertices, set to NULL\n",
839                        id, obj->nVertices);
840                if (dump_format) printf("\\N\n");
841                else printf("NULL);\n");
842
843                return;
844        }
845
846        if (dump_format) printf("SRID=%s;",sr_id );
847        else printf("GeometryFromText('");
848       
849        if (simple_geometries==0) // We write MULTI geometries, so generate Header
850        {
851                printf("MULTILINESTRING(");
852        }
853        else if ((obj->nParts)==1)
854        {
855                printf("LINESTRING");
856        }
857        else // We write Non-MULTI geometries, but have several parts:
858        {
859                fprintf(stderr, "We have a Multilinestring with %d parts, can't use -S switch!\n", obj->nParts);
860                exit(1);               
861        }
862
863        for (pi=0; pi<obj->nParts; pi++)
864        {
865                int vi; /* vertex index */
866                int vs; /* start vertex */
867                int ve; /* end vertex */
868
869                if (pi) printf(",");
870                printf("(");
871
872                /* Set start and end vertexes */
873                if ( pi==obj->nParts-1 ) ve = obj->nVertices;
874                else ve = obj->panPartStart[pi+1];
875                vs = obj->panPartStart[pi];
876
877                for ( vi=vs; vi<ve; vi++)
878                {
879                        if ( vi > vs ) printf(",");
880                        printf("%.15g %.15g",
881                                obj->padfX[vi],
882                                obj->padfY[vi]);
883                        if ( wkbtype & WKBZOFFSET )
884                                printf(" %.15g", obj->padfZ[vi]);
885                }
886
887                printf(")");
888                               
889        }
890
891        if (simple_geometries==0) printf(")");
892
893        if (dump_format) printf("\n");
894        else printf("',%s) );\n",sr_id);
895}
896
897int
898FindPolygons(SHPObject *obj, Ring ***Out)
899{
900        Ring **Outer;    /* Pointers to Outer rings */
901        int out_index=0; /* Count of Outer rings */
902        Ring **Inner;    /* Pointers to Inner rings */
903        int in_index=0;  /* Count of Inner rings */
904        int pi; /* part index */
905
906#ifdef DEBUG
907        static int call = -1;
908        call++;
909
910        fprintf(stderr, "FindPolygons[%d]: allocated space for %d rings\n",
911                call, obj->nParts);
912#endif
913
914        /* Allocate initial memory */
915        Outer = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
916        Inner = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
917
918        /* Iterate over rings dividing in Outers and Inners */
919        for (pi=0; pi<obj->nParts; pi++)
920        {
921                int vi; /* vertex index */
922                int vs; /* start index */
923                int ve; /* end index */
924                int nv; /* number of vertex */
925                double area = 0.0;
926                Ring *ring;
927
928                /* Set start and end vertexes */
929                if ( pi==obj->nParts-1 ) ve = obj->nVertices;
930                else ve = obj->panPartStart[pi+1];
931                vs = obj->panPartStart[pi];
932
933                /* Compute number of vertexes */
934                nv = ve-vs;
935
936                /* Allocate memory for a ring */
937                ring = (Ring*)malloc(sizeof(Ring));
938                ring->list = (Point*)malloc(sizeof(Point)*nv);
939                ring->n = nv;
940                ring->next = NULL;
941                ring->linked = 0;
942
943                /* Iterate over ring vertexes */
944                for ( vi=vs; vi<ve; vi++)
945                {
946                        int vn = vi+1; /* next vertex for area */
947                        if ( vn==ve ) vn = vs;
948
949                        ring->list[vi-vs].x = obj->padfX[vi];
950                        ring->list[vi-vs].y = obj->padfY[vi];
951                        ring->list[vi-vs].z = obj->padfZ[vi];
952                        ring->list[vi-vs].m = obj->padfM[vi];
953
954                        area += (obj->padfX[vi] * obj->padfY[vn]) -
955                                (obj->padfY[vi] * obj->padfX[vn]);
956                }
957
958                /* Close the ring with first vertex  */
959                /*ring->list[vi].x = obj->padfX[vs]; */
960                /*ring->list[vi].y = obj->padfY[vs]; */
961                /*ring->list[vi].z = obj->padfZ[vs]; */
962                /*ring->list[vi].m = obj->padfM[vs]; */
963
964                /* Clockwise (or single-part). It's an Outer Ring ! */
965                if(area < 0.0 || obj->nParts ==1) {
966                        Outer[out_index] = ring;
967                        out_index++;
968                }
969
970                /* Counterclockwise. It's an Inner Ring ! */
971                else {
972                        Inner[in_index] = ring;
973                        in_index++;
974                }
975        }
976
977#ifdef DEBUG
978        fprintf(stderr, "FindPolygons[%d]: found %d Outer, %d Inners\n",
979                call, out_index, in_index);
980#endif
981
982        /* Put the inner rings into the list of the outer rings */
983        /* of which they are within */
984        for(pi=0; pi<in_index; pi++)
985        {
986                Point pt,pt2;
987                int i;
988                Ring *inner=Inner[pi], *outer=NULL;
989
990                pt.x = inner->list[0].x;
991                pt.y = inner->list[0].y;
992
993                pt2.x = inner->list[1].x;
994                pt2.y = inner->list[1].y;
995
996                for(i=0; i<out_index; i++)
997                {
998                        int in;
999
1000                        in = PIP(pt, Outer[i]->list, Outer[i]->n);
1001                        if( in || PIP(pt2, Outer[i]->list, Outer[i]->n) )
1002                        {
1003                                outer = Outer[i];
1004                                break;
1005                        }
1006                        /*fprintf(stderr, "!PIP %s\nOUTE %s\n", dump_ring(inner), dump_ring(Outer[i])); */
1007                }
1008
1009                if ( outer )
1010                {
1011                        outer->linked++;
1012                        while(outer->next) outer = outer->next;
1013                        outer->next = inner;
1014                }
1015                else
1016                {
1017                        /* The ring wasn't within any outer rings, */
1018                        /* assume it is a new outer ring. */
1019#ifdef DEBUG
1020                        fprintf(stderr,
1021                                "FindPolygons[%d]: hole %d is orphan\n",
1022                                call, pi);
1023#endif
1024                        Outer[out_index] = inner;
1025                        out_index++;
1026                }
1027        }
1028
1029        *Out = Outer;
1030        free(Inner);
1031
1032        return out_index;
1033}
1034
1035void
1036ReleasePolygons(Ring **polys, int npolys)
1037{
1038        int pi;
1039        /* Release all memory */
1040        for(pi=0; pi<npolys; pi++)
1041        {
1042                Ring *Poly, *temp;
1043                Poly = polys[pi];
1044                while(Poly != NULL){
1045                        temp = Poly;
1046                        Poly = Poly->next;
1047                        free(temp->list);
1048                        free(temp);
1049                }
1050        }
1051}
1052
1053/*This function basically deals with the polygon case. */
1054/*it sorts the polys in order of outer,inner,inner, so that inners */
1055/*always come after outers they are within  */
1056void
1057InsertPolygon(void)
1058{
1059        unsigned int subtype = POLYGONTYPE | (wkbtype&WKBZOFFSET) |
1060                (wkbtype&WKBMOFFSET);
1061        Ring **Outer;
1062        int out_index;
1063        int pi; /* part index */
1064
1065        out_index = FindPolygons(obj, &Outer);
1066
1067        if (!dump_format) printf("'");
1068        if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
1069
1070        if (simple_geometries==0) // We write MULTI geometries, so generate Header
1071        {
1072                print_wkb_byte(getEndianByte());
1073                print_wkb_int(wkbtype);
1074                print_wkb_int(out_index); /* npolys */
1075        }
1076        else if (out_index!=1) // We write Non-MULTI geometries, but have several parts:
1077        {
1078                fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", out_index);
1079                exit(1);               
1080        }
1081
1082        /* Write the coordinates */
1083        for(pi=0; pi<out_index; pi++)
1084        {
1085                Ring *poly;
1086
1087                poly = Outer[pi];
1088
1089                print_wkb_byte(getEndianByte());
1090                print_wkb_int(subtype);
1091                print_wkb_int(poly->linked+1); /* nrings */
1092
1093                while(poly)
1094                {
1095                        int vi; /* vertex index */
1096
1097                        print_wkb_int(poly->n); /* npoints */
1098
1099                        for(vi=0; vi<poly->n; vi++)
1100                        {
1101                                print_wkb_double(poly->list[vi].x);
1102                                print_wkb_double(poly->list[vi].y);
1103                                if ( wkbtype & WKBZOFFSET )
1104                                        print_wkb_double(poly->list[vi].z);
1105                                if ( wkbtype & WKBMOFFSET )
1106                                        print_wkb_double(poly->list[vi].m);
1107                        }
1108
1109                        poly = poly->next;
1110                }
1111
1112        }
1113
1114        if (dump_format) printf("\n");
1115        else printf("');\n");
1116
1117        /* Release all memory */
1118        ReleasePolygons(Outer, out_index);
1119        free(Outer);
1120}
1121
1122void
1123InsertPolygonWKT(void)
1124{
1125        Ring **Outer;    /* Pointers to Outer rings */
1126        int out_index=0; /* Count of Outer rings */
1127        int pi; /* part index */
1128
1129#ifdef DEBUG
1130        static int call = -1;
1131        call++;
1132
1133        fprintf(stderr, "InsertPolygon[%d]: allocated space for %d rings\n",
1134                call, obj->nParts);
1135#endif
1136
1137        out_index = FindPolygons(obj, &Outer);
1138
1139        if (dump_format) printf("SRID=%s;",sr_id );
1140        else printf("GeometryFromText('");
1141       
1142        if (simple_geometries==0) // We write MULTI geometries, so generate Header
1143        {
1144                printf("MULTIPOLYGON(");
1145        }
1146        else if (out_index==1)
1147        {
1148                printf("POLYGON");
1149        }
1150        else
1151        { // We write Non-MULTI geometries, but have several parts:
1152                fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", out_index);
1153                exit(1);               
1154        }
1155
1156        /* Write the coordinates */
1157        for(pi=0; pi<out_index; pi++)
1158        {
1159                Ring *poly;
1160
1161                poly = Outer[pi];
1162
1163                if ( pi ) printf(",");
1164                printf("(");
1165
1166                while(poly)
1167                {
1168                        int vi; /* vertex index */
1169
1170                        printf("(");
1171                        for(vi=0; vi<poly->n; vi++)
1172                        {
1173                                if ( vi ) printf(",");
1174                                printf("%.15g %.15g",
1175                                        poly->list[vi].x,
1176                                        poly->list[vi].y);
1177                                if ( wkbtype & WKBZOFFSET )
1178                                        printf(" %.15g", poly->list[vi].z);
1179                        }
1180                        printf(")");
1181
1182                        poly = poly->next;
1183                        if ( poly ) printf(",");
1184                }
1185
1186                printf(")");
1187
1188        }
1189
1190        if (simple_geometries==0) printf(")");
1191       
1192        if (dump_format) printf("\n");
1193        else printf("',%s) );\n",sr_id);
1194
1195        /* Release all memory */
1196        ReleasePolygons(Outer, out_index);
1197        free(Outer);
1198}
1199
1200void
1201InsertPoint(void)
1202{
1203        if (!dump_format) printf("'");
1204        if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
1205
1206        print_wkb_byte(getEndianByte());
1207        print_wkb_int(wkbtype);
1208        print_wkb_double(obj->padfX[0]);
1209        print_wkb_double(obj->padfY[0]);
1210        if ( wkbtype & WKBZOFFSET ) print_wkb_double(obj->padfZ[0]);
1211        if ( wkbtype & WKBMOFFSET ) print_wkb_double(obj->padfM[0]);
1212
1213        if (dump_format) printf("\n");
1214        else printf("');\n");
1215}
1216
1217void
1218InsertPointWKT(void)
1219{
1220        unsigned int u;
1221        if (dump_format) printf("SRID=%s;%s(", sr_id, pgtype);
1222        else printf("GeometryFromText('%s(", pgtype);
1223
1224        for (u=0;u<obj->nVertices; u++){
1225                if (u>0) printf(",");
1226                printf("%.15g %.15g",obj->padfX[u],obj->padfY[u]);
1227                if ( wkbtype & WKBZOFFSET ) printf(" %.15g", obj->padfZ[u]);
1228        }
1229        if (dump_format) printf(")\n");
1230        else printf(")',%s) );\n",sr_id);
1231
1232}
1233
1234void
1235InsertMultiPoint(void)
1236{
1237        unsigned int u;
1238        unsigned int subtype = POINTTYPE | (wkbtype&WKBZOFFSET) |
1239                (wkbtype&WKBMOFFSET);
1240
1241        if (!dump_format) printf("'");
1242        if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
1243
1244        print_wkb_byte(getEndianByte());
1245        print_wkb_int(wkbtype);
1246        print_wkb_int(obj->nVertices);
1247       
1248        for (u=0;u<obj->nVertices; u++)
1249        {
1250                print_wkb_byte(getEndianByte());
1251                print_wkb_int(subtype);
1252                print_wkb_double(obj->padfX[u]);
1253                print_wkb_double(obj->padfY[u]);
1254                if ( wkbtype & WKBZOFFSET ) print_wkb_double(obj->padfZ[u]);
1255                if ( wkbtype & WKBMOFFSET ) print_wkb_double(obj->padfM[u]);
1256        }
1257
1258        if (dump_format) printf("\n");
1259        else printf("');\n");
1260}
1261
1262int
1263ParseCmdline(int ARGC, char **ARGV)
1264{
1265        int c;
1266        int curindex=0;
1267        char  *ptr;
1268        extern char *optarg;
1269        extern int optind;
1270
1271        if ( ARGC == 1 ) {
1272                usage(ARGV[0], 0, stdout);
1273        }
1274
1275        while ((c = getopt(ARGC, ARGV, "kcdapDs:Sg:iW:wIN:")) != EOF){
1276               switch (c) {
1277               case 'c':
1278                    if (opt == ' ')
1279                         opt ='c';
1280                    else
1281                         return 0;
1282                    break;
1283               case 'd':
1284                    if (opt == ' ')
1285                         opt ='d';
1286                    else
1287                         return 0;
1288                    break;
1289               case 'a':
1290                    if (opt == ' ')
1291                         opt ='a';
1292                    else
1293                         return 0;
1294                    break;
1295               case 'p':
1296                    if (opt == ' ')
1297                         opt ='p';
1298                    else
1299                         return 0;
1300                    break;
1301               case 'D':
1302                    dump_format =1;
1303                    break;
1304               case 'S':
1305                    simple_geometries =1;
1306                    break;
1307               case 's':
1308                    sr_id = optarg;
1309                    break;
1310               case 'g':
1311                    geom = optarg;
1312                    break;
1313               case 'k':
1314                    quoteidentifiers = 1;
1315                    break;
1316               case 'i':
1317                    forceint4 = 1;
1318                    break;
1319               case 'I':
1320                    createindex = 1;
1321                    break;
1322               case 'w':
1323                    hwgeom = 1;
1324                    break;
1325                case 'W':
1326#ifdef USE_ICONV
1327                    encoding = optarg;
1328#else
1329                    fprintf(stderr, "WARNING: the -W switch will have no effect. UTF8 disabled at compile time\n");
1330#endif
1331                    break;
1332                case 'N':
1333                        switch (optarg[0])
1334                        {       
1335                                case 'a':
1336                                        null_policy = abort_on_null;
1337                                        break;
1338                                case 'i':
1339                                        null_policy = insert_null;
1340                                        break;
1341                                case 's':
1342                                        null_policy = skip_null;
1343                                        break;
1344                                default:
1345                                        fprintf(stderr, "Unsupported NULL geometry handling policy.\nValid policies: insert, skip, abort\n");
1346                                        exit(1);
1347                        }
1348                    break;
1349               case '?':
1350                    usage(ARGV[0], 0, stdout);
1351               default:             
1352                return 0;
1353               }
1354        }
1355
1356        if ( !sr_id ) sr_id = "-1";
1357
1358        if ( !geom ) geom = "the_geom";
1359
1360        if ( opt==' ' ) opt = 'c';
1361
1362        for (; optind < ARGC; optind++){
1363                if(curindex ==0){
1364                        shp_file = ARGV[optind];
1365                }else if(curindex == 1){
1366                        table = ARGV[optind];
1367                        if ( (ptr=strchr(table, '.')) )
1368                        {
1369                                *ptr = '\0';
1370                                schema = table;
1371                                table = ptr+1;
1372                        }
1373                }
1374                curindex++;
1375        }
1376       
1377        /*
1378         * Third argument (if present) is supported for compatibility
1379         * with old shp2pgsql versions taking also database name.
1380         */
1381        if(curindex < 2 || curindex > 3){
1382                return 0;
1383        }
1384
1385        /*
1386         * Transform table name to lower case unless asked
1387         * to keep original case (we'll quote it later on)
1388         */
1389        if ( ! quoteidentifiers )
1390        {
1391                LowerCase(table);
1392                if ( schema ) LowerCase(schema);
1393        }
1394
1395        return 1;
1396}
1397
1398
1399void
1400SetPgType(void)
1401{
1402        switch(shpfiletype)
1403        {
1404                case SHPT_POINT: /* Point */
1405                        pgtype = "POINT";
1406                        wkbtype = POINTTYPE;
1407                        pgdims = 2;
1408                        break;
1409                case SHPT_ARC: /* PolyLine */
1410                        pgtype = "MULTILINESTRING";
1411                        wkbtype = MULTILINETYPE ;
1412                        pgdims = 2;
1413                        break;
1414                case SHPT_POLYGON: /* Polygon */
1415                        pgtype = "MULTIPOLYGON";
1416                        wkbtype = MULTIPOLYGONTYPE;
1417                        pgdims = 2;
1418                        break;
1419                case SHPT_MULTIPOINT: /* MultiPoint */
1420                        pgtype = "MULTIPOINT";
1421                        wkbtype = MULTIPOINTTYPE;
1422                        pgdims = 2;
1423                        break;
1424                case SHPT_POINTM: /* PointM */
1425                        wkbtype = POINTTYPE | WKBMOFFSET;
1426                        if ( ! hwgeom ) {
1427                                pgtype = "POINTM";
1428                                pgdims = 3;
1429                                istypeM = 1;
1430                        } else {
1431                                pgtype = "POINT";
1432                                pgdims = 2;
1433                        }
1434                        break;
1435                case SHPT_ARCM: /* PolyLineM */
1436                        wkbtype = MULTILINETYPE | WKBMOFFSET;
1437                        if ( ! hwgeom ) {
1438                                pgtype = "MULTILINESTRINGM";
1439                                pgdims = 3;
1440                                istypeM = 1;
1441                        } else {
1442                                pgtype = "MULTILINESTRING";
1443                                pgdims = 2;
1444                        }
1445                        break;
1446                case SHPT_POLYGONM: /* PolygonM */
1447                        wkbtype = MULTIPOLYGONTYPE | WKBMOFFSET;
1448                        if ( ! hwgeom ) {
1449                                pgtype = "MULTIPOLYGONM";
1450                                pgdims = 3;
1451                                istypeM = 1;
1452                        } else {
1453                                pgtype = "MULTIPOLYGON";
1454                                pgdims = 2;
1455                        }
1456                        break;
1457                case SHPT_MULTIPOINTM: /* MultiPointM */
1458                        wkbtype = MULTIPOINTTYPE | WKBMOFFSET;
1459                        if ( ! hwgeom ) {
1460                                pgtype = "MULTIPOINTM";
1461                                pgdims = 3;
1462                                istypeM = 1;
1463                        } else {
1464                                pgtype = "MULTIPOINT";
1465                                pgdims = 2;
1466                        }
1467                        break;
1468                case SHPT_POINTZ: /* PointZ */
1469                        wkbtype = POINTTYPE | WKBMOFFSET | WKBZOFFSET;
1470                        pgtype = "POINT";
1471                        if ( ! hwgeom ) pgdims = 4;
1472                        else pgdims = 3;
1473                        break;
1474                case SHPT_ARCZ: /* PolyLineZ */
1475                        pgtype = "MULTILINESTRING";
1476                        wkbtype = MULTILINETYPE | WKBZOFFSET | WKBMOFFSET;
1477                        if ( ! hwgeom ) pgdims = 4;
1478                        else pgdims = 3;
1479                        break;
1480                case SHPT_POLYGONZ: /* MultiPolygonZ */
1481                        pgtype = "MULTIPOLYGON";
1482                        wkbtype = MULTIPOLYGONTYPE | WKBZOFFSET | WKBMOFFSET;
1483                        if ( ! hwgeom ) pgdims = 4;
1484                        else pgdims = 3;
1485                        break;
1486                case SHPT_MULTIPOINTZ: /* MultiPointZ */
1487                        pgtype = "MULTIPOINT";
1488                        wkbtype = MULTIPOINTTYPE | WKBZOFFSET | WKBMOFFSET;
1489                        if ( ! hwgeom ) pgdims = 4;
1490                        else pgdims = 3;
1491                        break;
1492                default:
1493                        pgtype = "GEOMETRY";
1494                        wkbtype = COLLECTIONTYPE | WKBZOFFSET | WKBMOFFSET;
1495                        pgdims = 4;
1496                        fprintf(stderr, "Unknown geometry type: %d\n",
1497                                shpfiletype);
1498                        break;
1499        }
1500
1501        if (simple_geometries)
1502        {
1503                // adjust geometry name for CREATE TABLE by skipping MULTI
1504                if ((wkbtype & 0x7) == MULTIPOLYGONTYPE) pgtype += 5;
1505                if ((wkbtype & 0x7) == MULTILINETYPE) pgtype += 5;
1506        }                       
1507}
1508
1509char *
1510dump_ring(Ring *ring)
1511{
1512        char *buf = malloc(256*ring->n);
1513        int i;
1514
1515        buf[0] = '\0';
1516        for (i=0; i<ring->n; i++)
1517        {
1518                if (i) strcat(buf, ",");
1519                sprintf(buf+strlen(buf), "%g %g",
1520                        ring->list[i].x,
1521                        ring->list[i].y);
1522        }
1523        return buf;
1524}
1525
1526/*--------------- WKB handling  */
1527
1528static char outchr[]={"0123456789ABCDEF"};
1529
1530static int endian_check_int = 1; /* dont modify this!!! */
1531
1532static char
1533getEndianByte(void)
1534{
1535        /* 0 = big endian, 1 = little endian */
1536        if ( *((char *) &endian_check_int) ) return 1;
1537        else return 0;
1538}
1539
1540static void
1541print_wkb_double(double val)
1542{
1543        print_wkb_bytes((unsigned char *)&val, 1, 8);
1544}
1545
1546static void
1547print_wkb_byte(unsigned char val)
1548{
1549        print_wkb_bytes((unsigned char *)&val, 1, 1);
1550}
1551
1552static void
1553print_wkb_int(int val)
1554{
1555        print_wkb_bytes((unsigned char *)&val, 1, 4);
1556}
1557
1558static void
1559print_wkb_bytes(unsigned char *ptr, unsigned int cnt, size_t size)
1560{
1561        unsigned int bc; /* byte count */
1562        static char buf[256];
1563        char *bufp;
1564
1565        if ( size*cnt*2 > 256 )
1566        {
1567                fprintf(stderr,
1568                        "You found a bug! wkb_bytes does not allocate enough bytes");
1569                exit(4);
1570        }
1571
1572        bufp = buf;
1573        while(cnt--){
1574                for(bc=0; bc<size; bc++)
1575                {
1576                        *bufp++ = outchr[ptr[bc]>>4];
1577                        *bufp++ = outchr[ptr[bc]&0x0F];
1578                }
1579        }
1580        *bufp = '\0';
1581        /*fprintf(stderr, "\nwkbbytes:%s\n", buf); */
1582        printf("%s", buf);
1583}
1584
1585void
1586DropTable(char *schema, char *table, char *geom)
1587{
1588                /*---------------Drop the table--------------------------
1589                 * TODO: if the table has more then one geometry column
1590                 * the DROP TABLE call will leave spurious records in
1591                 * geometry_columns.
1592                 *
1593                 * If the geometry column in the table being dropped
1594                 * does not match 'the_geom' or the name specified with
1595                 * -g an error is returned by DropGeometryColumn.
1596                 *
1597                 * The table to be dropped might not exist.
1598                 *
1599                 */
1600                if ( schema )
1601                {
1602                        printf("SELECT DropGeometryColumn('%s','%s','%s');\n",
1603                                schema, table, geom);
1604                        printf("DROP TABLE \"%s\".\"%s\";\n", schema, table);
1605                }
1606                else
1607                {
1608                        printf("SELECT DropGeometryColumn('','%s','%s');\n",
1609                                table, geom);
1610                        printf("DROP TABLE \"%s\";\n", table);
1611                }
1612}
1613
1614void
1615GetFieldsSpec(void)
1616{
1617/*
1618 * Shapefile (dbf) field name are at most 10chars + 1 NULL.
1619 * Postgresql field names are at most 63 bytes + 1 NULL.
1620 */
1621#define MAXFIELDNAMELEN 64
1622        int field_precision, field_width;
1623        int j, z;
1624        char  name[MAXFIELDNAMELEN];
1625        char  name2[MAXFIELDNAMELEN];
1626        DBFFieldType type = -1;
1627#ifdef USE_ICONV
1628        char *utf8str;
1629#endif
1630
1631        num_fields = DBFGetFieldCount( hDBFHandle );
1632        num_records = DBFGetRecordCount(hDBFHandle);
1633        field_names = malloc(num_fields*sizeof(char*));
1634        types = (DBFFieldType *)malloc(num_fields*sizeof(int));
1635        widths = malloc(num_fields*sizeof(int));
1636        precisions = malloc(num_fields*sizeof(int));
1637        col_names = malloc((num_fields+2) * sizeof(char) * MAXFIELDNAMELEN);
1638        strcpy(col_names, "(" );
1639
1640        /*fprintf(stderr, "Number of fields from DBF: %d\n", num_fields); */
1641        for(j=0;j<num_fields;j++)
1642        {
1643                type = DBFGetFieldInfo(hDBFHandle, j, name, &field_width, &field_precision);
1644
1645/*fprintf(stderr, "Field %d (%s) width/decimals: %d/%d\n", j, name, field_width, field_precision); */
1646                types[j] = type;
1647                widths[j] = field_width;
1648                precisions[j] = field_precision;
1649
1650#ifdef USE_ICONV
1651                if ( encoding )
1652                {
1653                        utf8str = utf8(encoding, name);
1654                        if ( ! utf8str ) exit(1);
1655                        strcpy(name, utf8str);
1656                        free(utf8str);
1657                }
1658#endif
1659
1660
1661                /*
1662                 * Make field names lowercase unless asked to
1663                 * keep identifiers case.
1664                 */
1665                if ( ! quoteidentifiers ) LowerCase(name);
1666
1667                /*
1668                 * Escape names starting with the
1669                 * escape char (_), those named 'gid'
1670                 * or after pgsql reserved attribute names
1671                 */
1672                if( name[0]=='_' ||
1673                        ! strcmp(name,"gid") ||
1674                        ! strcmp(name, "tableoid") ||
1675                        ! strcmp(name, "cmax") ||
1676                        ! strcmp(name, "xmax") ||
1677                        ! strcmp(name, "cmin") ||
1678                        ! strcmp(name, "primary") ||
1679                        ! strcmp(name, "oid") ||
1680                        ! strcmp(name, "ctid") )
1681                {
1682                        strcpy(name2+2, name);
1683                        name2[0] = '_';
1684                        name2[1] = '_';
1685                        strcpy(name, name2);
1686                }
1687
1688                /* Avoid duplicating field names */
1689                for(z=0; z < j ; z++){
1690                        if(strcmp(field_names[z],name)==0){
1691                                strcat(name,"__");
1692                                sprintf(name+strlen(name),"%i",j);
1693                                break;
1694                        }
1695                }       
1696
1697                field_names[j] = malloc (strlen(name)+1);
1698                strcpy(field_names[j], name);
1699
1700                /*sprintf(col_names, "%s\"%s\",", col_names, name);*/
1701                strcat(col_names, "\"");
1702                strcat(col_names, name);
1703                strcat(col_names, "\",");
1704        }
1705        /*sprintf(col_names, "%s\"%s\")", col_names, geom);*/
1706        strcat(col_names, geom);
1707        strcat(col_names, ")");
1708}
1709
1710#ifdef USE_ICONV
1711
1712char *
1713utf8 (const char *fromcode, char *inputbuf)
1714{
1715        iconv_t cd;
1716        char *outputptr;
1717        char *outputbuf;
1718        size_t outbytesleft;
1719        size_t inbytesleft;
1720
1721        inbytesleft = strlen (inputbuf);
1722
1723        cd = iconv_open ("UTF-8", fromcode);
1724        if (cd == (iconv_t) - 1)
1725        {
1726                fprintf(stderr, "utf8: iconv_open: %s\n", strerror (errno));
1727                return NULL;
1728        }
1729
1730        outbytesleft = inbytesleft*3+1; /* UTF8 string can be 3 times larger */
1731                                        /* then local string */
1732        outputbuf = (char *) malloc (outbytesleft);
1733        if (!outputbuf)
1734        {
1735                fprintf(stderr, "utf8: malloc: %s\n", strerror (errno));
1736                return NULL;
1737        }
1738        memset (outputbuf, 0, outbytesleft);
1739        outputptr = outputbuf;
1740
1741        if (-1==iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft))
1742        {
1743                fprintf(stderr, "utf8: %s", strerror (errno));
1744                return NULL;
1745        }
1746
1747        iconv_close (cd);
1748
1749        return outputbuf;
1750}
1751
1752#endif /* defined USE_ICONV */
1753
1754/**********************************************************************
1755 * $Log$
1756 * Revision 1.108  2006/06/16 14:12:17  strk
1757 *         - BUGFIX in pgsql2shp successful return code.
1758 *         - BUGFIX in shp2pgsql handling of MultiLine WKT.
1759 *
1760 * Revision 1.107  2006/04/18 09:16:26  strk
1761 * Substituted bzero() use with memset()
1762 *
1763 * Revision 1.106  2006/01/16 10:42:58  strk
1764 * Added support for Bool and Date DBF<=>PGIS mapping
1765 *
1766 * Revision 1.105  2006/01/09 16:40:16  strk
1767 * ISO C90 comments, signedness mismatch fixes
1768 *
1769 * Revision 1.104  2005/11/01 09:25:47  strk
1770 * Reworked NULL geometries handling code letting user specify policy (insert,skip,abort). Insert is the default.
1771 *
1772 * Revision 1.103  2005/10/24 15:54:22  strk
1773 * fixed wrong assumption about maximum size of integer attributes (width is maximum size of text representation)
1774 *
1775 * Revision 1.102  2005/10/24 11:30:59  strk
1776 *
1777 * Fixed a bug in string attributes handling truncating values of maximum
1778 * allowed length, curtesy of Lars Roessiger.
1779 * Reworked integer attributes handling to be stricter in dbf->sql mapping
1780 * and to allow for big int8 values in sql->dbf conversion
1781 *
1782 * Revision 1.101  2005/10/21 11:33:55  strk
1783 * Applied patch by Lars Roessiger handling numerical values with a trailing decima
1784 * l dot
1785 *
1786 * Revision 1.100  2005/10/13 13:40:20  strk
1787 * Fixed return code from shp2pgsql
1788 *
1789 * Revision 1.99  2005/10/03 18:08:55  strk
1790 * Stricter string attributes lenght handling. DBF header will be used
1791 * to set varchar maxlenght, (var)char typmod will be used to set DBF header
1792 * len.
1793 *
1794 * Revision 1.98  2005/10/03 07:45:58  strk
1795 * Issued a warning when -W is specified and no UTF8 support has been compiled in.
1796 *
1797 * Revision 1.97  2005/09/30 08:59:29  strk
1798 * Fixed release of stack memory occurring when shp2pgsql is compiled with USE_ICONV defined, an attribute value needs to be escaped and no -W is used
1799 *
1800 * Revision 1.96  2005/08/29 22:36:25  strk
1801 * Removed premature object destruction in InsertLineString{WKT,} causing segfault
1802 *
1803 * Revision 1.95  2005/08/29 11:48:33  strk
1804 * Fixed sprintf() calls to avoid overlapping memory,
1805 * reworked not-null objects existance check to reduce startup costs.
1806 *
1807 * Revision 1.94  2005/07/27 02:47:14  strk
1808 * Support for multibyte field names in loader
1809 *
1810 * Revision 1.93  2005/07/27 02:35:50  strk
1811 * Minor cleanups in loader
1812 *
1813 * Revision 1.92  2005/07/27 02:07:01  strk
1814 * Fixed handling of POINT types as WKT (-w) in loader
1815 *
1816 * Revision 1.91  2005/07/04 09:47:03  strk
1817 * Added conservative iconv detection code
1818 *
1819 * Revision 1.90  2005/06/16 17:55:58  strk
1820 * Added -I switch for GiST index creation in loader
1821 *
1822 * Revision 1.89  2005/04/21 09:08:34  strk
1823 * Applied patch from Ron Mayer fixing a segfault in string escaper funx
1824 *
1825 * Revision 1.88  2005/04/14 12:58:59  strk
1826 * Applied patch by Gino Lucrezi fixing bug in string escaping code.
1827 *
1828 * Revision 1.87  2005/04/06 14:16:43  strk
1829 * Removed manual update of gid field.
1830 *
1831 * Revision 1.86  2005/04/06 14:02:08  mschaber
1832 * added -p option (prepare mode) that spits out the table schema without
1833 * inserting any data.
1834 *
1835 * Revision 1.85  2005/04/06 10:46:10  strk
1836 * Bugfix in -w (hwgeom) handling of ZM shapefiles.
1837 * Big reorganizzation of code to easy maintainance.
1838 *
1839 * Revision 1.84  2005/04/04 20:51:26  strk
1840 * Added -w flag to output old (WKT/HWGEOM) sql.
1841 *
1842 * Revision 1.83  2005/03/15 12:24:40  strk
1843 * hole-in-ring detector made more readable
1844 *
1845 * Revision 1.82  2005/03/14 22:02:31  strk
1846 * Fixed holes handling.
1847 *
1848 * Revision 1.81  2005/03/08 11:06:33  strk
1849 * modernized old-style parameter declarations
1850 *
1851 * Revision 1.80  2005/03/04 14:48:22  strk
1852 * Applied patch from Jonne Savolainen fixing multilines handling
1853 *
1854 * Revision 1.79  2005/01/31 22:15:22  strk
1855 * Added maintainer notice, to reduce Jeff-strk mail bounces
1856 *
1857 * Revision 1.78  2005/01/17 09:21:13  strk
1858 * Added one more bytes for terminating NULL in utf8 encoder
1859 *
1860 * Revision 1.77  2005/01/16 16:50:01  strk
1861 * String escaping algorithm made simpler and more robust.
1862 * Removed escaped strings leaking.
1863 * Fixed UTF8 encoder to allocate enough space for 3bytes chars strings.
1864 *
1865 * Revision 1.76  2005/01/12 17:03:20  strk
1866 * Added optional UTF8 output support as suggested by IIDA Tetsushi
1867 *
1868 * Revision 1.75  2004/11/15 10:51:35  strk
1869 * Fixed a bug in PIP invocation, added some debugging lines.
1870 *
1871 * Revision 1.74  2004/10/17 13:25:44  strk
1872 * removed USE_WKB partially-used define
1873 *
1874 * Revision 1.73  2004/10/17 13:24:44  strk
1875 * HEXWKB polygon
1876 *
1877 * Revision 1.72  2004/10/17 12:59:12  strk
1878 * HEXWKB multiline output
1879 *
1880 * Revision 1.71  2004/10/17 12:26:02  strk
1881 * Point and MultiPoint loaded using HEXWKB.
1882 *
1883 * Revision 1.70  2004/10/15 22:01:35  strk
1884 * Initial WKB functionalities
1885 *
1886 * Revision 1.69  2004/10/07 21:52:28  strk
1887 * Lots of rewriting/cleanup. TypeM/TypeZ supports.
1888 *
1889 * Revision 1.68  2004/10/07 06:54:24  strk
1890 * cleanups
1891 *
1892 * Revision 1.67  2004/10/06 10:11:16  strk
1893 * Other separator fixes
1894 *
1895 * Revision 1.66  2004/10/06 09:40:27  strk
1896 * Handled 0-DBF-attributes corner case.
1897 *
1898 * Revision 1.65  2004/09/20 17:13:31  strk
1899 * changed comments to better show shape type handling
1900 *
1901 * Revision 1.64  2004/08/20 08:14:37  strk
1902 * Whole output wrapped in transaction blocks.
1903 * Drops are out of transaction, and multiple transactions are used
1904 * for INSERT mode.
1905 *
1906 **********************************************************************/
Note: See TracBrowser for help on using the browser.