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

Last change on this file since 18001 was 18001, checked in by jonb, 10 years ago

Apply fix from Milo to display projection information when executed with: -h -v. Fixes #2357

  • Property svn:keywords set to Rev
File size: 25.3 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 ./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 = "./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 ((expire_tiles_zoom >= 0) && (projection != PROJ_SPHERE_MERC)) {
698        fprintf(stderr, "Error: --expire-tiles can only be used with spherical mercator projection!\n");
699        exit(EXIT_FAILURE);
700    }
701   
702    if( cache < 0 ) cache = 0;
703
704    if (pass_prompt)
705        password = simple_prompt("Password:", 100, 0);
706
707    conninfo = build_conninfo(db, username, password, host, port);
708    sql_conn = PQconnectdb(conninfo);
709    if (PQstatus(sql_conn) != CONNECTION_OK) {
710        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(sql_conn));
711        exit(EXIT_FAILURE);
712    }
713    PQfinish(sql_conn);
714
715    text_init();
716    initList(&tags);
717
718    count_node = max_node = 0;
719    count_way = max_way = 0;
720    count_rel = max_rel = 0;
721
722    LIBXML_TEST_VERSION
723
724    project_init(projection);
725    fprintf(stderr, "Using projection SRS %d (%s)\n", 
726        project_getprojinfo()->srs, project_getprojinfo()->descr );
727
728    if (parse_bbox())
729        return 1;
730
731    options.conninfo = conninfo;
732    options.prefix = prefix;
733    options.append = append;
734    options.slim = slim;
735    options.projection = project_getprojinfo()->srs;
736    options.scale = (projection==PROJ_LATLONG)?10000000:100;
737    options.mid = slim ? &mid_pgsql : &mid_ram;
738    options.cache = cache;
739    options.style = style;
740    options.expire_tiles_zoom = expire_tiles_zoom;
741    options.expire_tiles_zoom_min = expire_tiles_zoom_min;
742    options.expire_tiles_filename = expire_tiles_filename;
743
744    if (strcmp("pgsql", output_backend) == 0) {
745      out = &out_pgsql;
746    } else if (strcmp("gazetteer", output_backend) == 0) {
747      out = &out_gazetteer;
748    } else if (strcmp("null", output_backend) == 0) {
749      out = &out_null;
750    } else {
751      fprintf(stderr, "Output backend `%s' not recognised. Should be one of [pgsql, null].\n", output_backend);
752      exit(EXIT_FAILURE);
753    }
754
755    out->start(&options);
756
757    realloc_nodes();
758    realloc_members();
759
760    while (optind < argc) {
761        fprintf(stderr, "\nReading in file: %s\n", argv[optind]);
762        if (streamFile(argv[optind], sanitize) != 0)
763            exit_nicely();
764        optind++;
765    }
766
767    xmlCleanupParser();
768    xmlMemoryDump();
769   
770    if (count_node || count_way || count_rel) {
771        fprintf(stderr, "\n");
772        fprintf(stderr, "Node stats: total(%d), max(%d)\n", count_node, max_node);
773        fprintf(stderr, "Way stats: total(%d), max(%d)\n", count_way, max_way);
774        fprintf(stderr, "Relation stats: total(%d), max(%d)\n", count_rel, max_rel);
775    }
776    out->stop();
777   
778    free(nds);
779    free(members);
780
781    project_exit();
782    text_exit();
783    fprintf(stderr, "\n");
784
785    return 0;
786}
Note: See TracBrowser for help on using the repository browser.