1 /***************************************
2  OSM planet file fixme finder.
3 
4  Part of the Routino routing software.
5  ******************/ /******************
6  This file Copyright 2008-2015 Andrew M. Bishop
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU Affero General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU Affero General Public License for more details.
17 
18  You should have received a copy of the GNU Affero General Public License
19  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  ***************************************/
21 
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 
28 #include "version.h"
29 
30 #include "types.h"
31 #include "ways.h"
32 
33 #include "typesx.h"
34 #include "nodesx.h"
35 #include "waysx.h"
36 #include "relationsx.h"
37 
38 #include "files.h"
39 #include "logging.h"
40 #include "errorlogx.h"
41 #include "functions.h"
42 #include "osmparser.h"
43 #include "tagging.h"
44 #include "uncompress.h"
45 
46 
47 /* Global variables */
48 
49 /*+ The name of the temporary directory. +*/
50 char *option_tmpdirname=NULL;
51 
52 /*+ The amount of RAM to use for filesorting. +*/
53 size_t option_filesort_ramsize=0;
54 
55 /*+ The number of threads to use for filesorting. +*/
56 int option_filesort_threads=1;
57 
58 
59 /* Local functions */
60 
61 static void print_usage(int detail,const char *argerr,const char *err);
62 
63 
64 /*++++++++++++++++++++++++++++++++++++++
65   The main program for the find-fixme.
66   ++++++++++++++++++++++++++++++++++++++*/
67 
main(int argc,char ** argv)68 int main(int argc,char** argv)
69 {
70  NodesX     *OSMNodes;
71  WaysX      *OSMWays;
72  RelationsX *OSMRelations;
73  ErrorLogsX *OSMErrorLogs;
74  char       *dirname=NULL,*prefix=NULL,*tagging=NULL;
75  int         option_keep=1;
76  int         option_filenames=0;
77  int         arg;
78 
79  printf_program_start();
80 
81  /* Parse the command line arguments */
82 
83  for(arg=1;arg<argc;arg++)
84    {
85     if(!strcmp(argv[arg],"--version"))
86        print_usage(-1,NULL,NULL);
87     else if(!strcmp(argv[arg],"--help"))
88        print_usage(1,NULL,NULL);
89     else if(!strncmp(argv[arg],"--dir=",6))
90        dirname=&argv[arg][6];
91     else if(!strncmp(argv[arg],"--sort-ram-size=",16))
92        option_filesort_ramsize=atoi(&argv[arg][16]);
93 #if defined(USE_PTHREADS) && USE_PTHREADS
94     else if(!strncmp(argv[arg],"--sort-threads=",15))
95        option_filesort_threads=atoi(&argv[arg][15]);
96 #endif
97     else if(!strncmp(argv[arg],"--tmpdir=",9))
98        option_tmpdirname=&argv[arg][9];
99     else if(!strncmp(argv[arg],"--tagging=",10))
100        tagging=&argv[arg][10];
101     else if(!strcmp(argv[arg],"--loggable"))
102        option_loggable=1;
103     else if(!strcmp(argv[arg],"--logtime"))
104        option_logtime=1;
105     else if(!strcmp(argv[arg],"--logmemory"))
106        option_logmemory=1;
107     else if(argv[arg][0]=='-' && argv[arg][1]=='-')
108        print_usage(0,argv[arg],NULL);
109     else
110        option_filenames++;
111    }
112 
113  /* Check the specified command line options */
114 
115  if(!option_filesort_ramsize)
116    {
117 #if SLIM
118     option_filesort_ramsize=64*1024*1024;
119 #else
120     option_filesort_ramsize=256*1024*1024;
121 #endif
122    }
123  else
124     option_filesort_ramsize*=1024*1024;
125 
126  if(!option_tmpdirname)
127    {
128     if(!dirname)
129        option_tmpdirname=".";
130     else
131        option_tmpdirname=dirname;
132    }
133 
134  if(tagging)
135    {
136     if(!ExistsFile(tagging))
137       {
138        fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
139        exit(EXIT_FAILURE);
140       }
141    }
142  else
143    {
144     tagging=FileName(dirname,prefix,"fixme.xml");
145 
146     if(!ExistsFile(tagging))
147       {
148        fprintf(stderr,"Error: The '--tagging' option was not used and the default 'fixme.xml' does not exist.\n");
149        exit(EXIT_FAILURE);
150       }
151    }
152 
153  if(ParseXMLTaggingRules(tagging))
154    {
155     fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
156     exit(EXIT_FAILURE);
157    }
158 
159  /* Create new node, segment, way and relation variables */
160 
161  OSMNodes=NewNodeList(0,0);
162 
163  OSMWays=NewWayList(0,0);
164 
165  OSMRelations=NewRelationList(0,0);
166 
167  /* Create the error log file */
168 
169  open_errorlog(FileName(dirname,prefix,"fixme.log"),0,option_keep);
170 
171  /* Parse the file */
172 
173  for(arg=1;arg<argc;arg++)
174    {
175     int fd;
176     char *filename,*p;
177 
178     if(argv[arg][0]=='-' && argv[arg][1]=='-')
179        continue;
180 
181     filename=strcpy(malloc(strlen(argv[arg])+1),argv[arg]);
182 
183     fd=OpenFile(filename);
184 
185     if((p=strstr(filename,".bz2")) && !strcmp(p,".bz2"))
186       {
187        fd=Uncompress_Bzip2(fd);
188        *p=0;
189       }
190 
191     if((p=strstr(filename,".gz")) && !strcmp(p,".gz"))
192       {
193        fd=Uncompress_Gzip(fd);
194        *p=0;
195       }
196 
197     if((p=strstr(filename,".xz")) && !strcmp(p,".xz"))
198       {
199        fd=Uncompress_Xz(fd);
200        *p=0;
201       }
202 
203     printf("\nParse OSM Data [%s]\n==============\n\n",filename);
204     fflush(stdout);
205 
206     if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
207       {
208        if(ParsePBFFile(fd,OSMNodes,OSMWays,OSMRelations))
209           exit(EXIT_FAILURE);
210       }
211     else if((p=strstr(filename,".o5m")) && !strcmp(p,".o5m"))
212       {
213        if(ParseO5MFile(fd,OSMNodes,OSMWays,OSMRelations))
214           exit(EXIT_FAILURE);
215       }
216     else
217       {
218        if(ParseOSMFile(fd,OSMNodes,OSMWays,OSMRelations))
219           exit(EXIT_FAILURE);
220       }
221 
222     CloseFile(fd);
223 
224     free(filename);
225    }
226 
227  DeleteXMLTaggingRules();
228 
229  FinishNodeList(OSMNodes);
230  FinishWayList(OSMWays);
231  FinishRelationList(OSMRelations);
232 
233  /* Sort the data */
234 
235  printf("\nSort OSM Data\n=============\n\n");
236  fflush(stdout);
237 
238  /* Sort the nodes, ways and relations */
239 
240  SortNodeList(OSMNodes);
241 
242  SortWayList(OSMWays);
243 
244  SortRelationList(OSMRelations);
245 
246  /* Process the data */
247 
248  RenameFile(OSMNodes->filename_tmp,OSMNodes->filename);
249  RenameFile(OSMWays->filename_tmp,OSMWays->filename);
250  RenameFile(OSMRelations->rrfilename_tmp,OSMRelations->rrfilename);
251  RenameFile(OSMRelations->trfilename_tmp,OSMRelations->trfilename);
252 
253  close_errorlog();
254 
255  printf("\nCreate Error Log\n================\n\n");
256  fflush(stdout);
257 
258  OSMErrorLogs=NewErrorLogList();
259 
260  ProcessErrorLogs(OSMErrorLogs,OSMNodes,OSMWays,OSMRelations);
261 
262  SortErrorLogsGeographically(OSMErrorLogs);
263 
264  SaveErrorLogs(OSMErrorLogs,FileName(dirname,prefix,"fixme.mem"));
265 
266  FreeErrorLogList(OSMErrorLogs);
267 
268  /* Free the memory (delete the temporary files) */
269 
270  FreeNodeList(OSMNodes,0);
271  FreeWayList(OSMWays,0);
272  FreeRelationList(OSMRelations,0);
273 
274  printf("\n");
275  fflush(stdout);
276 
277  printf_program_end();
278 
279  exit(EXIT_SUCCESS);
280 }
281 
282 
283 /*++++++++++++++++++++++++++++++++++++++
284   Print out the usage information.
285 
286   int detail The level of detail to use: -1 = just version number, 0 = low detail, 1 = full details.
287 
288   const char *argerr The argument that gave the error (if there is one).
289 
290   const char *err Other error message (if there is one).
291   ++++++++++++++++++++++++++++++++++++++*/
292 
print_usage(int detail,const char * argerr,const char * err)293 static void print_usage(int detail,const char *argerr,const char *err)
294 {
295  if(detail<0)
296    {
297     fprintf(stderr,
298             "Routino version " ROUTINO_VERSION " " ROUTINO_URL ".\n"
299             );
300    }
301 
302  if(detail>=0)
303    {
304     fprintf(stderr,
305             "Usage: fixme-finder [--version]\n"
306             "                    [--help]\n"
307             "                    [--dir=<dirname>]\n"
308 #if defined(USE_PTHREADS) && USE_PTHREADS
309             "                    [--sort-ram-size=<size>] [--sort-threads=<number>]\n"
310 #else
311             "                    [--sort-ram-size=<size>]\n"
312 #endif
313             "                    [--tmpdir=<dirname>]\n"
314             "                    [--tagging=<filename>]\n"
315             "                    [--loggable] [--logtime] [--logmemory]\n"
316             "                    [<filename.osm> ...\n"
317             "                     | <filename.pbf> ...\n"
318             "                     | <filename.o5m> ..."
319 #if defined(USE_BZIP2) && USE_BZIP2
320             "\n                     | <filename.(osm|o5m).bz2> ..."
321 #endif
322 #if defined(USE_GZIP) && USE_GZIP
323             "\n                     | <filename.(osm|o5m).gz> ..."
324 #endif
325 #if defined(USE_XZ) && USE_XZ
326             "\n                     | <filename.(osm|o5m).xz> ..."
327 #endif
328             "]\n");
329 
330     if(argerr)
331        fprintf(stderr,
332                "\n"
333                "Error with command line parameter: %s\n",argerr);
334 
335     if(err)
336        fprintf(stderr,
337                "\n"
338                "Error: %s\n",err);
339    }
340 
341  if(detail==1)
342     fprintf(stderr,
343             "\n"
344             "--version                 Print the version of Routino.\n"
345             "\n"
346             "--help                    Prints this information.\n"
347             "\n"
348             "--dir=<dirname>           The directory containing the fixme database.\n"
349             "\n"
350             "--sort-ram-size=<size>    The amount of RAM (in MB) to use for data sorting\n"
351 #if SLIM
352             "                          (defaults to 64MB otherwise.)\n"
353 #else
354             "                          (defaults to 256MB otherwise.)\n"
355 #endif
356 #if defined(USE_PTHREADS) && USE_PTHREADS
357             "--sort-threads=<number>   The number of threads to use for data sorting.\n"
358 #endif
359             "\n"
360             "--tmpdir=<dirname>        The directory name for temporary files.\n"
361             "                          (defaults to the '--dir' option directory.)\n"
362             "\n"
363             "--tagging=<filename>      The name of the XML file containing the tagging rules\n"
364             "                          (defaults to 'fixme.xml' with '--dir' option)\n"
365             "\n"
366             "--loggable                Print progress messages suitable for logging to file.\n"
367             "--logtime                 Print the elapsed time for each processing step.\n"
368             "--logmemory               Print the max allocated/mapped memory for each step.\n"
369             "\n"
370             "<filename.osm>, <filename.pbf>, <filename.o5m>\n"
371             "                          The name(s) of the file(s) to read and parse.\n"
372             "                          Filenames ending '.pbf' read as PBF, filenames ending\n"
373             "                          '.o5m' read as O5M, others as XML.\n"
374 #if defined(USE_BZIP2) && USE_BZIP2
375             "                          Filenames ending '.bz2' will be bzip2 uncompressed.\n"
376 #endif
377 #if defined(USE_GZIP) && USE_GZIP
378             "                          Filenames ending '.gz' will be gzip uncompressed.\n"
379 #endif
380 #if defined(USE_XZ) && USE_XZ
381             "                          Filenames ending '.xz' will be xz uncompressed.\n"
382 #endif
383             );
384 
385  exit(!detail);
386 }
387