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

Last change on this file since 14841 was 14841, checked in by zere, 11 years ago

Use bzip2 interface directly, rather than through the zlib compatibility interface to deal with multiple streams in pbzip2-generated files. Also added a 'null' output for testing purposes.

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