source: subversion/applications/utils/export/osm2pgsql/osm2pgsql.c @ 20475

Last change on this file since 20475 was 20475, checked in by giggls, 10 years ago

Add an experimental feature to generate hstore enabled PgSQL tables.

At least in theory this will allow for 3-column output tables now.

Tested with the following environment:

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