source: subversion/applications/utils/export/osm2pgsql/primitive_xml_parsing/osm2pgsql.c @ 22268

Last change on this file since 22268 was 22268, checked in by frederik, 9 years ago

osm2pgsql version without libxml

File size: 29.7 KB
Line 
1/*
2#-----------------------------------------------------------------------------
3# osm2pgsql - converts planet.osm file into PostgreSQL
4# compatible output suitable to be rendered by mapnik
5# Use: osm2pgsql planet.osm.bz2
6#-----------------------------------------------------------------------------
7# Original Python implementation by Artem Pavlenko
8# Re-implementation by Jon Burgess, Copyright 2006
9#
10# This program is free software; you can redistribute it and/or
11# modify it under the terms of the GNU General Public License
12# as published by the Free Software Foundation; either version 2
13# of the License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23#-----------------------------------------------------------------------------
24*/
25
26#define _GNU_SOURCE
27#include <stdio.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31#include <assert.h>
32#include <getopt.h>
33#include <libgen.h>
34
35#include <libpq-fe.h>
36
37#include "osmtypes.h"
38#include "build_geometry.h"
39#include "keyvals.h"
40#include "middle-pgsql.h"
41#include "middle-ram.h"
42#include "output-pgsql.h"
43#include "output-gazetteer.h"
44#include "output-null.h"
45#include "sanitizer.h"
46#include "reprojection.h"
47#include "text-tree.h"
48#include "input.h"
49#include "sprompt.h"
50
51typedef enum { FILETYPE_NONE, FILETYPE_OSM, FILETYPE_OSMCHANGE, FILETYPE_PLANETDIFF } filetypes_t;
52typedef enum { ACTION_NONE, ACTION_CREATE, ACTION_MODIFY, ACTION_DELETE } actions_t;
53
54static int count_node,    max_node;
55static int count_way,     max_way;
56static int count_rel,     max_rel;
57
58struct output_t *out;
59
60/* Since {node,way} elements are not nested we can guarantee the
61   values in an end tag must match those of the corresponding
62   start tag and can therefore be cached.
63*/
64static double node_lon, node_lat;
65static struct keyval tags;
66static int *nds;
67static int nd_count, nd_max;
68static struct member *members;
69static int member_count, member_max;
70static int osm_id;
71
72#define INIT_MAX_MEMBERS 64
73#define INIT_MAX_NODES  4096
74
75int verbose;
76static void realloc_nodes();
77static void realloc_members();
78
79// Bounding box to filter imported data
80const char *bbox = NULL;
81static double minlon, minlat, maxlon, maxlat;
82static int extra_attributes;
83
84static void printStatus(void)
85{
86    fprintf(stderr, "\rProcessing: Node(%dk) Way(%dk) Relation(%dk)",
87            count_node/1000, count_way/1000, count_rel/1000);
88}
89
90static int parse_bbox(void)
91{
92    int n;
93
94    if (!bbox)
95        return 0;
96
97    n = sscanf(bbox, "%lf,%lf,%lf,%lf", &minlon, &minlat, &maxlon, &maxlat);
98    if (n != 4) {
99        fprintf(stderr, "Bounding box must be specified like: minlon,minlat,maxlon,maxlat\n");
100        return 1;
101    }
102    if (maxlon <= minlon) {
103        fprintf(stderr, "Bounding box failed due to maxlon <= minlon\n");
104        return 1;
105    }
106    if (maxlat <= minlat) {
107        fprintf(stderr, "Bounding box failed due to maxlat <= minlat\n");
108        return 1;
109    }
110    printf("Applying Bounding box: %f,%f to %f,%f\n", minlon,minlat,maxlon,maxlat);
111    return 0;
112}
113
114static int node_wanted(double lat, double lon)
115{
116    if (!bbox)
117        return 1;
118
119    if (lat < minlat || lat > maxlat)
120        return 0;
121    if (lon < minlon || lon > maxlon)
122        return 0;
123    return 1;
124}
125
126static filetypes_t filetype = FILETYPE_NONE;
127static actions_t action = ACTION_NONE;
128
129
130char *extractAttribute(char **token, int tokens, char *attname)
131{
132    char buffer[256];
133    int cl;
134    int i;
135    sprintf(buffer, "%s=\"", attname);
136    cl = strlen(buffer);
137    for (i=0; i<tokens; i++)
138    {
139        if (!strncmp(token[i], buffer, cl))
140        {
141            char *quote = index(token[i] + cl, '"');
142            if (quote == NULL) quote = token[i] + strlen(token[i]) + 1;
143            *quote = 0;
144            if (strchr(token[i]+cl, '&') == 0) return (token[i] + cl);
145
146            char *in;
147            char *out;
148            for (in=token[i]+cl, out=token[i]+cl; *in; in++)
149            {
150                if (*in == '&')
151                {
152                    if (!strncmp(in+1, "quot;", 5))
153                    {
154                        *out++ = '"';
155                        in+=5;
156                    }
157                    else if (!strncmp(in+1, "lt;", 3))
158                    {
159                        *out++ = '<';
160                        in+=3;
161                    }
162                    else if (!strncmp(in+1, "gt;", 3))
163                    {
164                        *out++ = '>';
165                        in+=3;
166                    }
167                    else if (!strncmp(in+1, "apos;", 5))
168                    {
169                        *out++ = '\'';
170                        in+=5;
171                    }
172                }
173                else
174                {
175                    *out++ = *in;
176                }
177            }
178            *out = 0;
179            return (token[i]+cl);
180        }
181    }
182    return NULL;
183}
184
185/* Parses the action="foo" tags in JOSM change files. Obvisouly not useful from osmChange files */
186static actions_t ParseAction(char **token, int tokens)
187{
188    if( filetype == FILETYPE_OSMCHANGE || filetype == FILETYPE_PLANETDIFF )
189        return action;
190    actions_t new_action = ACTION_NONE;
191    char *action = extractAttribute(token, tokens, "action");
192    if( action == NULL )
193        new_action = ACTION_CREATE;
194    else if( strcmp((char *)action, "modify") == 0 )
195        new_action = ACTION_MODIFY;
196    else if( strcmp((char *)action, "delete") == 0 )
197        new_action = ACTION_DELETE;
198    else
199    {
200        fprintf( stderr, "Unknown value for action: %s\n", (char*)action );
201        exit_nicely();
202    }
203    return new_action;
204}
205
206void StartElement(char *name, char *line)
207{
208    char *xid, *xlat, *xlon, *xk, *xv, *xrole, *xtype;
209    char *token[255];
210    int tokens = 0;
211
212    if (filetype == FILETYPE_NONE)
213    {
214        if (!strcmp(name, "?xml")) return;
215        if (!strcmp(name, "osm"))
216        {
217            filetype = FILETYPE_OSM;
218            action = ACTION_CREATE;
219        }
220        else if (!strcmp(name, "osmChange"))
221        {
222            filetype = FILETYPE_OSMCHANGE;
223            action = ACTION_NONE;
224        }
225        else if (!strcmp(name, "planetdiff"))
226        {
227            filetype = FILETYPE_PLANETDIFF;
228            action = ACTION_NONE;
229        }
230        else
231        {
232            fprintf( stderr, "Unknown XML document type: %s\n", name );
233            exit_nicely();
234        }
235        return;
236    }
237
238    tokens=1;
239    token[0] = line;
240    int quote = 0;
241    char *i;
242    for (i=line; *i; i++)
243    {
244        if (quote)
245        {
246            if (*i == '"') 
247            {
248                quote = 0;
249            }
250        }
251        else
252        {
253            if (*i == '"')
254            {
255                quote = 1;
256            }
257            else if (isspace(*i))
258            {
259                *i = 0;
260                token[tokens++] = i + 1;
261            }
262        }
263    }
264
265    if (!strcmp(name, "node")) {
266        xid  = extractAttribute(token, tokens, "id");
267        xlon = extractAttribute(token, tokens, "lon");
268        xlat = extractAttribute(token, tokens, "lat");
269        assert(xid); assert(xlon); assert(xlat);
270
271        osm_id  = strtol((char *)xid, NULL, 10);
272        node_lon = strtod((char *)xlon, NULL);
273        node_lat = strtod((char *)xlat, NULL);
274        action = ParseAction(token, tokens);
275
276        if (osm_id > max_node)
277            max_node = osm_id;
278
279        count_node++;
280        if (count_node%10000 == 0)
281            printStatus();
282    } else if (!strcmp(name, "tag")) {
283        xk = extractAttribute(token, tokens, "k");
284        assert(xk);
285
286        /* 'created_by' and 'source' are common and not interesting to mapnik renderer */
287        if (strcmp((char *)xk, "created_by") && strcmp((char *)xk, "source")) {
288            char *p;
289            xv = extractAttribute(token, tokens, "v");
290            assert(xv);
291            while ((p = strchr(xk, ' ')))
292                *p = '_';
293
294            addItem(&tags, xk, (char *)xv, 0);
295        }
296    } else if (!strcmp(name, "way")) {
297
298        xid  = extractAttribute(token, tokens, "id");
299        assert(xid);
300        osm_id   = strtol((char *)xid, NULL, 10);
301        action = ParseAction(token, tokens);
302
303        if (osm_id > max_way)
304            max_way = osm_id;
305
306        count_way++;
307        if (count_way%1000 == 0)
308            printStatus();
309
310        nd_count = 0;
311    } else if (!strcmp(name, "nd")) {
312        xid  = extractAttribute(token, tokens, "ref");
313        assert(xid);
314
315        nds[nd_count++] = strtol( (char *)xid, NULL, 10 );
316
317        if( nd_count >= nd_max )
318          realloc_nodes();
319    } else if (!strcmp(name, "relation")) {
320        xid  = extractAttribute(token, tokens, "id");
321        assert(xid);
322        osm_id   = strtol((char *)xid, NULL, 10);
323        action = ParseAction(token, tokens);
324
325        if (osm_id > max_rel)
326            max_rel = osm_id;
327
328        count_rel++;
329        if (count_rel%1000 == 0)
330            printStatus();
331
332        member_count = 0;
333    } else if (!strcmp(name, "member")) {
334        xrole = extractAttribute(token, tokens, "role");
335        assert(xrole);
336
337        xtype = extractAttribute(token, tokens, "type");
338        assert(xtype);
339
340        xid  = extractAttribute(token, tokens, "ref");
341        assert(xid);
342
343        members[member_count].id   = strtol( (char *)xid, NULL, 0 );
344        members[member_count].role = strdup( (char *)xrole );
345
346        /* Currently we are only interested in 'way' members since these form polygons with holes */
347        if (!strcmp(xtype, "way"))
348            members[member_count].type = OSMTYPE_WAY;
349        else if (!strcmp(xtype, "node"))
350            members[member_count].type = OSMTYPE_NODE;
351        else if (!strcmp(xtype, "relation"))
352            members[member_count].type = OSMTYPE_RELATION;
353        member_count++;
354
355        if( member_count >= member_max )
356            realloc_members();
357    } else if (!strcmp(name, "add") ||
358               !strcmp(name, "create")) {
359        action = ACTION_CREATE;
360        action = ACTION_MODIFY; // Turns all creates into modifies, makes it resiliant against inconsistant snapshots.
361    } else if (!strcmp(name, "modify")) {
362        action = ACTION_MODIFY;
363    } else if (!strcmp(name, "delete")) {
364        action = ACTION_DELETE;
365    } else if (!strcmp(name, "bound")) {
366        /* ignore */
367    } else if (!strcmp(name, "bounds")) {
368        /* ignore */
369    } else if (!strcmp(name, "changeset")) {
370        /* ignore */
371    } else {
372        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
373    }
374
375    // Collect extra attribute information and add as tags
376    if (extra_attributes && (!strcmp(name, "node") ||
377                             !strcmp(name, "way") ||
378                             !strcmp(name, "relation")))
379    {
380        char *xtmp;
381
382        xtmp = extractAttribute(token, tokens, "user");
383        if (xtmp) {
384            addItem(&tags, "osm_user", (char *)xtmp, 0);
385        }
386
387        xtmp = extractAttribute(token, tokens, "uid");
388        if (xtmp) {
389            addItem(&tags, "osm_uid", (char *)xtmp, 0);
390        }
391
392        xtmp = extractAttribute(token, tokens, "version");
393        if (xtmp) {
394            addItem(&tags, "osm_version", (char *)xtmp, 0);
395        }
396
397        xtmp = extractAttribute(token, tokens, "timestamp");
398        if (xtmp) {
399            addItem(&tags, "osm_timestamp", (char *)xtmp, 0);
400        }
401    }
402}
403
404static void resetMembers()
405{
406  int i;
407  for(i=0; i<member_count; i++ )
408    free( members[i].role );
409}
410
411void EndElement(const char *name)
412{
413    if (!strcmp(name, "node")) {
414        if (node_wanted(node_lat, node_lon)) {
415            reproject(&node_lat, &node_lon);
416            if( action == ACTION_CREATE )
417                out->node_add(osm_id, node_lat, node_lon, &tags);
418            else if( action == ACTION_MODIFY )
419                out->node_modify(osm_id, node_lat, node_lon, &tags);
420            else if( action == ACTION_DELETE )
421                out->node_delete(osm_id);
422            else
423            {
424                fprintf( stderr, "Don't know action for node %d\n", osm_id );
425                exit_nicely();
426            }
427        }
428        resetList(&tags);
429    } else if (!strcmp(name, "way")) {
430        if( action == ACTION_CREATE )
431            out->way_add(osm_id, nds, nd_count, &tags );
432        else if( action == ACTION_MODIFY )
433            out->way_modify(osm_id, nds, nd_count, &tags );
434        else if( action == ACTION_DELETE )
435            out->way_delete(osm_id);
436        else
437        {
438            fprintf( stderr, "Don't know action for way %d\n", osm_id );
439            exit_nicely();
440        }
441        resetList(&tags);
442    } else if (!strcmp(name, "relation")) {
443        if( action == ACTION_CREATE )
444            out->relation_add(osm_id, members, member_count, &tags);
445        else if( action == ACTION_MODIFY )
446            out->relation_modify(osm_id, members, member_count, &tags);
447        else if( action == ACTION_DELETE )
448            out->relation_delete(osm_id);
449        else
450        {
451            fprintf( stderr, "Don't know action for relation %d\n", osm_id );
452            exit_nicely();
453        }
454        resetList(&tags);
455        resetMembers();
456    } else if (!strcmp(name, "tag")) {
457        /* ignore */
458    } else if (!strcmp(name, "nd")) {
459        /* ignore */
460    } else if (!strcmp(name, "member")) {
461        /* ignore */
462    } else if (!strcmp(name, "osm")) {
463        printStatus();
464        filetype = FILETYPE_NONE;
465    } else if (!strcmp(name, "osmChange")) {
466        printStatus();
467        filetype = FILETYPE_NONE;
468    } else if (!strcmp(name, "planetdiff")) {
469        printStatus();
470        filetype = FILETYPE_NONE;
471    } else if (!strcmp(name, "bound")) {
472        /* ignore */
473    } else if (!strcmp(name, "bounds")) {
474        /* ignore */
475    } else if (!strcmp(name, "changeset")) {
476        /* ignore */
477        resetList(&tags); /* We may have accumulated some tags even if we ignored the changeset */
478    } else if (!strcmp(name, "add")) {
479        action = ACTION_NONE;
480    } else if (!strcmp(name, "create")) {
481        action = ACTION_NONE;
482    } else if (!strcmp(name, "modify")) {
483        action = ACTION_NONE;
484    } else if (!strcmp(name, "delete")) {
485        action = ACTION_NONE;
486    } else {
487        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
488    }
489}
490
491static void process(char *line) {
492    char *lt = index(line, '<');
493    if (lt)
494    {
495        char *spc = index(lt+1, ' ');
496        char *gt = index(lt+1, '>');
497        char *nx = spc;
498        if (*(lt+1) == '/')
499        {
500            *gt = 0;
501            EndElement(lt+2);
502        }
503        else
504        {
505            int slash = 0;
506            if (gt != NULL) { 
507                *gt-- = 0; 
508                if (nx == NULL || gt < nx) nx = gt; 
509                while(gt>lt)
510                {
511                    if (*gt=='/') { slash=1; *gt=0; break; }
512                    if (!isspace(*gt)) break;
513                    gt--;
514                }
515            }
516            *nx++ = 0;
517            //printf ("nx=%d, lt+1=#%s#\n", nx-lt,lt+1);
518            StartElement(lt+1, nx);
519            if (slash) EndElement(lt+1);
520        }
521    }
522}
523
524static int streamFile(char *filename, int sanitize) {
525    struct Input *i;
526    int ret = 0;
527    char buffer[65536];
528    int bufsz = 0;
529    int offset = 0;
530
531    i = inputOpen(filename);
532
533    if (i != NULL) {
534        while(1)
535        {
536            bufsz = bufsz + readFile(i, buffer + bufsz, sizeof(buffer) - bufsz);
537            char *nl = index(buffer, '\n');
538            if (nl == 0) break;
539            *nl=0;
540            while (nl && nl < buffer + bufsz)
541            {
542                *nl = 0;
543                process(buffer + offset);
544                offset = nl - buffer + 1;
545                //printf("\nsearch line at %d, buffer sz is %d = ",offset, bufsz);
546                nl = index(buffer + offset, '\n');
547                //printf("%d\n", nl ? nl-buffer : -1);
548            }
549            memcpy(buffer, buffer + offset, bufsz - offset);
550            bufsz = bufsz - offset;
551            offset = 0;
552        }
553    } else {
554        fprintf(stderr, "Unable to open %s\n", filename);
555        return 1;
556    }
557    return 0;
558}
559
560void exit_nicely(void)
561{
562    fprintf(stderr, "Error occurred, cleaning up\n");
563    out->cleanup();
564    exit(1);
565}
566 
567static void short_usage(char *arg0)
568{
569    const char *name = basename(arg0);
570
571    fprintf(stderr, "Usage error. For further information see:\n");
572    fprintf(stderr, "\t%s -h|--help\n", name);
573}
574
575static void long_usage(char *arg0)
576{
577    int i;
578    const char *name = basename(arg0);
579
580    fprintf(stderr, "Usage:\n");
581    fprintf(stderr, "\t%s [options] planet.osm\n", name);
582    fprintf(stderr, "\t%s [options] planet.osm.{gz,bz2}\n", name);
583    fprintf(stderr, "\t%s [options] file1.osm file2.osm file3.osm\n", name);
584    fprintf(stderr, "\nThis will import the data from the OSM file(s) into a PostgreSQL database\n");
585    fprintf(stderr, "suitable for use by the Mapnik renderer\n");
586    fprintf(stderr, "\nOptions:\n");
587    fprintf(stderr, "   -a|--append\t\tAdd the OSM file into the database without removing\n");
588    fprintf(stderr, "              \t\texisting data.\n");
589    fprintf(stderr, "   -b|--bbox\t\tApply a bounding box filter on the imported data\n");
590    fprintf(stderr, "              \t\tMust be specified as: minlon,minlat,maxlon,maxlat\n");
591    fprintf(stderr, "              \t\te.g. --bbox -0.5,51.25,0.5,51.75\n");
592    fprintf(stderr, "   -c|--create\t\tRemove existing data from the database. This is the \n");
593    fprintf(stderr, "              \t\tdefault if --append is not specified.\n");
594    fprintf(stderr, "   -d|--database\tThe name of the PostgreSQL database to connect\n");
595    fprintf(stderr, "                \tto (default: gis).\n");
596    fprintf(stderr, "   -i|--tablespace-index\tThe name of the PostgreSQL tablespace where indexes will be create\n");
597    fprintf(stderr, "                \tto (default: pg_default).\n");
598    fprintf(stderr, "   -l|--latlong\t\tStore data in degrees of latitude & longitude.\n");
599    fprintf(stderr, "   -m|--merc\t\tStore data in proper spherical mercator (default)\n");
600    fprintf(stderr, "   -M|--oldmerc\t\tStore data in the legacy OSM mercator format\n");
601    fprintf(stderr, "   -E|--proj num\tUse projection EPSG:num\n");
602    fprintf(stderr, "   -u|--utf8-sanitize\tRepair bad UTF8 input data (present in planet\n");
603    fprintf(stderr, "                \tdumps prior to August 2007). Adds about 10%% overhead.\n");
604    fprintf(stderr, "   -p|--prefix\t\tPrefix for table names (default planet_osm)\n");
605    fprintf(stderr, "   -s|--slim\t\tStore temporary data in the database. This greatly\n");
606    fprintf(stderr, "            \t\treduces the RAM usage but is much slower.\n");
607
608    if (sizeof(int*) == 4) {
609        fprintf(stderr, "            \t\tYou are running this on 32bit system, so at most\n");
610        fprintf(stderr, "            \t\t3GB of RAM will be used. If you encounter unexpected\n");
611        fprintf(stderr, "            \t\texceptions during import, you should try this switch.\n");
612    }
613   
614    fprintf(stderr, "   -S|--style\t\tLocation of the style file. Defaults to " OSM2PGSQL_DATADIR "/default.style\n");
615    fprintf(stderr, "   -C|--cache\t\tOnly for slim mode: Use upto this many MB for caching nodes\n");
616    fprintf(stderr, "             \t\tDefault is 800\n");
617    fprintf(stderr, "   -U|--username\tPostgresql user name.\n");
618    fprintf(stderr, "   -W|--password\tForce password prompt.\n");
619    fprintf(stderr, "   -H|--host\t\tDatabase server hostname or socket location.\n");
620    fprintf(stderr, "   -P|--port\t\tDatabase server port.\n");
621    fprintf(stderr, "   -e|--expire-tiles [min_zoom-]max_zoom\tCreate a tile expiry list.\n");
622    fprintf(stderr, "   -o|--expire-output filename\tOutput filename for expired tiles list.\n");
623    fprintf(stderr, "   -O|--output\t\tOutput backend.\n");
624    fprintf(stderr, "              \t\tpgsql - Output to a PostGIS database. (default)\n");
625    fprintf(stderr, "              \t\tgazetteer - Output to a PostGIS database suitable for gazetteer\n");
626    fprintf(stderr, "              \t\tnull  - No output. Useful for testing.\n");
627    fprintf(stderr, "   -x|--extra-attributes\n");
628    fprintf(stderr, "              \t\tInclude attributes for each object in the database.\n");
629    fprintf(stderr, "              \t\tThis includes the username, userid, timestamp and version.\n"); 
630    fprintf(stderr, "              \t\tNote: this option also requires additional entries in your style file.\n"); 
631    fprintf(stderr, "   -k|--hstore\t\tGenerate an additional hstore (key/value) column to  postgresql tables\n");
632    fprintf(stderr, "   -G|--multi-geometry\t\tGenerate multi-geometry features in postgresql tables.\n");
633    fprintf(stderr, "   -h|--help\t\tHelp information.\n");
634    fprintf(stderr, "   -v|--verbose\t\tVerbose output.\n");
635    fprintf(stderr, "\n");
636    if(!verbose)
637    {
638        fprintf(stderr, "Add -v to display supported projections.\n");
639        fprintf(stderr, "Use -E to access any espg projections (usually in /usr/share/proj/epsg)\n" );
640    }
641    else
642    {
643        fprintf(stderr, "Supported projections:\n" );
644        for(i=0; i<PROJ_COUNT; i++ )
645        {
646            fprintf( stderr, "%-20s(%2s) SRS:%6d %s\n", 
647                    Projection_Info[i].descr, Projection_Info[i].option, Projection_Info[i].srs, Projection_Info[i].proj4text);
648        }
649    }
650}
651
652const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port)
653{
654    static char conninfo[1024];
655
656    conninfo[0]='\0';
657    strcat(conninfo, "dbname='");
658    strcat(conninfo, db);
659    strcat(conninfo, "'");
660
661    if (username) {
662        strcat(conninfo, " user='");
663        strcat(conninfo, username);
664        strcat(conninfo, "'");
665    }
666    if (password) {
667        strcat(conninfo, " password='");
668        strcat(conninfo, password);
669        strcat(conninfo, "'");
670    }
671    if (host) {
672        strcat(conninfo, " host='");
673        strcat(conninfo, host);
674        strcat(conninfo, "'");
675    }
676    if (port) {
677        strcat(conninfo, " port='");
678        strcat(conninfo, port);
679        strcat(conninfo, "'");
680    }
681
682    return conninfo;
683}
684
685static void realloc_nodes()
686{
687  if( nd_max == 0 )
688    nd_max = INIT_MAX_NODES;
689  else
690    nd_max <<= 1;
691   
692  nds = realloc( nds, nd_max * sizeof( nds[0] ) );
693  if( !nds )
694  {
695    fprintf( stderr, "Failed to expand node list to %d\n", nd_max );
696    exit_nicely();
697  }
698}
699
700static void realloc_members()
701{
702  if( member_max == 0 )
703    member_max = INIT_MAX_NODES;
704  else
705    member_max <<= 1;
706   
707  members = realloc( members, member_max * sizeof( members[0] ) );
708  if( !members )
709  {
710    fprintf( stderr, "Failed to expand member list to %d\n", member_max );
711    exit_nicely();
712  }
713}
714
715int main(int argc, char *argv[])
716{
717    int append=0;
718    int create=0;
719    int slim=0;
720    int sanitize=0;
721    int long_usage_bool=0;
722    int pass_prompt=0;
723    int projection = PROJ_SPHERE_MERC;
724    int expire_tiles_zoom = -1;
725    int expire_tiles_zoom_min = -1;
726    int enable_hstore = 0;
727    int enable_multi = 0;
728    const char *expire_tiles_filename = "dirty_tiles";
729    const char *db = "gis";
730    const char *username=NULL;
731    const char *host=NULL;
732    const char *password=NULL;
733    const char *port = "5432";
734    const char *tblsindex = "pg_default"; // default TABLESPACE for index
735    const char *conninfo = NULL;
736    const char *prefix = "planet_osm";
737    const char *style = OSM2PGSQL_DATADIR "/default.style";
738    const char *temparg;
739    const char *output_backend = "pgsql";
740    int cache = 800;
741    struct output_options options;
742    PGconn *sql_conn;
743
744    fprintf(stderr, "osm2pgsql SVN version %s\n\n", VERSION);
745
746    while (1) {
747        int c, option_index = 0;
748        static struct option long_options[] = {
749            {"append",   0, 0, 'a'},
750            {"bbox",     1, 0, 'b'},
751            {"create",   0, 0, 'c'},
752            {"database", 1, 0, 'd'},
753            {"latlong",  0, 0, 'l'},
754            {"verbose",  0, 0, 'v'},
755            {"slim",     0, 0, 's'},
756            {"prefix",   1, 0, 'p'},
757            {"proj",     1, 0, 'E'},
758            {"merc",     0, 0, 'm'},
759            {"oldmerc",  0, 0, 'M'},
760            {"utf8-sanitize", 0, 0, 'u'},
761            {"cache",    1, 0, 'C'},
762            {"username", 1, 0, 'U'},
763            {"password", 0, 0, 'W'},
764            {"host",     1, 0, 'H'},
765            {"port",     1, 0, 'P'},
766            {"tablespace-index", 1, 0, 'i'},
767            {"help",     0, 0, 'h'},
768            {"style",    1, 0, 'S'},
769            {"expire-tiles", 1, 0, 'e'},
770            {"expire-output", 1, 0, 'o'},
771            {"output",   1, 0, 'O'},
772            {"extra-attributes", 0, 0, 'x'},
773            {"hstore", 0, 0, 'k'},
774            {"multi-geometry", 0, 0, 'G'},
775            {0, 0, 0, 0}
776        };
777
778        c = getopt_long (argc, argv, "ab:cd:hlmMp:suvU:WH:P:i:E:C:S:e:o:O:xkG", long_options, &option_index);
779        if (c == -1)
780            break;
781
782        switch (c) {
783            case 'a': append=1;   break;
784            case 'b': bbox=optarg; break;
785            case 'c': create=1;   break;
786            case 'v': verbose=1;  break;
787            case 's': slim=1;     break;
788            case 'u': sanitize=1; break;
789            case 'l': projection=PROJ_LATLONG;  break;
790            case 'm': projection=PROJ_SPHERE_MERC; break;
791            case 'M': projection=PROJ_MERC; break;
792            case 'E': projection=-atoi(optarg); break;
793            case 'p': prefix=optarg; break;
794            case 'd': db=optarg;  break;
795            case 'C': cache = atoi(optarg); break;
796            case 'U': username=optarg; break;
797            case 'W': pass_prompt=1; break;
798            case 'H': host=optarg; break;
799            case 'P': port=optarg; break;
800            case 'S': style=optarg; break;
801            case 'i': tblsindex=optarg; break;
802            case 'e':
803                expire_tiles_zoom_min = atoi(optarg);
804                temparg = strchr(optarg, '-');
805                if (temparg) expire_tiles_zoom = atoi(temparg + 1);
806                if (expire_tiles_zoom < expire_tiles_zoom_min) expire_tiles_zoom = expire_tiles_zoom_min;
807                break;
808            case 'o': expire_tiles_filename=optarg; break;
809            case 'O': output_backend = optarg; break;
810            case 'x': extra_attributes=1; break;
811            case 'k': enable_hstore=1; break;
812            case 'G': enable_multi=1; break;
813            case 'h': long_usage_bool=1; break;
814            case '?':
815            default:
816                short_usage(argv[0]);
817                exit(EXIT_FAILURE);
818        }
819    }
820
821    if (long_usage_bool) {
822        long_usage(argv[0]);
823        exit(EXIT_FAILURE);
824    }
825
826    if (argc == optind) {  // No non-switch arguments
827        short_usage(argv[0]);
828        exit(EXIT_FAILURE);
829    }
830
831    if (append && create) {
832        fprintf(stderr, "Error: --append and --create options can not be used at the same time!\n");
833        exit(EXIT_FAILURE);
834    }
835
836    if( cache < 0 ) cache = 0;
837
838    if (pass_prompt)
839        password = simple_prompt("Password:", 100, 0);
840    else {
841        password = getenv("PGPASS");
842    }   
843       
844
845    conninfo = build_conninfo(db, username, password, host, port);
846    sql_conn = PQconnectdb(conninfo);
847    if (PQstatus(sql_conn) != CONNECTION_OK) {
848        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(sql_conn));
849        exit(EXIT_FAILURE);
850    }
851    PQfinish(sql_conn);
852
853    text_init();
854    initList(&tags);
855
856    count_node = max_node = 0;
857    count_way = max_way = 0;
858    count_rel = max_rel = 0;
859
860    LIBXML_TEST_VERSION
861
862    project_init(projection);
863    fprintf(stderr, "Using projection SRS %d (%s)\n", 
864        project_getprojinfo()->srs, project_getprojinfo()->descr );
865
866    if (parse_bbox())
867        return 1;
868
869    options.conninfo = conninfo;
870    options.prefix = prefix;
871    options.append = append;
872    options.slim = slim;
873    options.projection = project_getprojinfo()->srs;
874    options.scale = (projection==PROJ_LATLONG)?10000000:100;
875    options.mid = slim ? &mid_pgsql : &mid_ram;
876    options.cache = cache;
877    options.style = style;
878    options.tblsindex = tblsindex;
879    options.expire_tiles_zoom = expire_tiles_zoom;
880    options.expire_tiles_zoom_min = expire_tiles_zoom_min;
881    options.expire_tiles_filename = expire_tiles_filename;
882    options.enable_multi = enable_multi;
883    options.enable_hstore = enable_hstore;
884
885    if (strcmp("pgsql", output_backend) == 0) {
886      out = &out_pgsql;
887    } else if (strcmp("gazetteer", output_backend) == 0) {
888      out = &out_gazetteer;
889    } else if (strcmp("null", output_backend) == 0) {
890      out = &out_null;
891    } else {
892      fprintf(stderr, "Output backend `%s' not recognised. Should be one of [pgsql, gazetteer, null].\n", output_backend);
893      exit(EXIT_FAILURE);
894    }
895
896    out->start(&options);
897
898    realloc_nodes();
899    realloc_members();
900
901    if (sizeof(int*) == 4 && options.slim != 1) {
902        fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n");
903        fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n");
904        fprintf(stderr, "!! exceptions during import, you should try running in slim\n");
905        fprintf(stderr, "!! mode using parameter -s.\n");
906    }
907
908    while (optind < argc) {
909        fprintf(stderr, "\nReading in file: %s\n", argv[optind]);
910        if (streamFile(argv[optind], sanitize) != 0)
911            exit_nicely();
912        optind++;
913    }
914
915    if (count_node || count_way || count_rel) {
916        fprintf(stderr, "\n");
917        fprintf(stderr, "Node stats: total(%d), max(%d)\n", count_node, max_node);
918        fprintf(stderr, "Way stats: total(%d), max(%d)\n", count_way, max_way);
919        fprintf(stderr, "Relation stats: total(%d), max(%d)\n", count_rel, max_rel);
920    }
921    out->stop();
922   
923    free(nds);
924    free(members);
925
926    project_exit();
927    text_exit();
928    fprintf(stderr, "\n");
929
930    return 0;
931}
Note: See TracBrowser for help on using the repository browser.