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

Last change on this file since 18439 was 18439, checked in by frederik, 10 years ago

Allow creation of expiry lists for 900913 tiles even if your target
projection is not 900913 (e.g. you have your PostGIS table in lat/lon).

Also fixes another bug in the old projection code where expire_from_bbox
would not expire the whole box properly (expire-tiles.c around line 333,
should have used min/max lon/lat but used min lon/lat twice).

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