[routino] 02/13: Imported Upstream version 2.7.3

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Feb 20 20:20:42 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository routino.

commit e2331adfe017bb186dd402d848b75795e3317327
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Feb 6 21:22:22 2015 +0100

    Imported Upstream version 2.7.3
---
 ChangeLog                           | 173 +++++++++++++++++++++++++++
 doc/DATALIFE.txt                    |  93 +++++++++------
 doc/NEWS.txt                        |  27 ++++-
 doc/README.txt                      |   1 +
 doc/USAGE.txt                       |  25 +++-
 doc/html/readme.html                |  34 +++++-
 doc/html/usage.html                 |  16 ++-
 extras/find-fixme/README.txt        |   3 +-
 extras/find-fixme/fixme-dumper.c    |   4 +-
 extras/find-fixme/fixme-finder.c    |  10 +-
 extras/find-fixme/osmparser.c       |  10 +-
 extras/tagmodifier/tagmodifier.c    |   6 +-
 src/errorlogx.c                     |  11 +-
 src/filedumper.c                    |   2 +-
 src/filedumperx.c                   |   4 +-
 src/files.c                         |  28 +++++
 src/files.h                         |   3 +-
 src/logging.c                       | 231 ++++++++++++++++++++++++++++++++++--
 src/logging.h                       |   9 +-
 src/nodes.c                         | 181 ++++++++++++++--------------
 src/nodes.h                         |   4 +-
 src/nodesx.c                        | 114 ++++++++++++++----
 src/optimiser.c                     |  80 +++++++++++--
 src/planetsplitter.c                |  92 ++++++++++----
 src/profiles.c                      |   8 +-
 src/prunex.c                        |  24 +++-
 src/relations.c                     |   5 +-
 src/relationsx.c                    |  53 ++++++++-
 src/results.c                       |  12 ++
 src/router.c                        |  63 ++++++++--
 src/segments.c                      |  67 ++++++++++-
 src/segments.h                      |   3 +
 src/segmentsx.c                     |  52 +++++---
 src/sorting.c                       |  36 +++++-
 src/superx.c                        |  12 +-
 src/typesx.h                        |   6 +-
 src/visualiser.c                    |  46 +++----
 src/ways.c                          |   5 +-
 src/waysx.c                         |  20 +++-
 src/waysx.h                         |   4 +-
 web/translations/translation.de.txt |   3 +-
 web/www/routino/router.html.de      |   2 +-
 xml/routino-translations.xml        |   2 +-
 43 files changed, 1265 insertions(+), 319 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index fd2e42f..3999129 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,176 @@
+2014-11-08  Andrew M. Bishop <amb>
+
+	Version 2.7.3 released.
+
+2014-11-08 [r1616]  Andrew M. Bishop <amb>
+
+	* FILES, doc/NEWS.txt, doc/README.txt, doc/html/readme.html:
+	  Updated for version 2.7.3.
+
+2014-11-08 [r1615]  Andrew M. Bishop <amb>
+
+	* web/translations/translation.de.txt,
+	  xml/routino-translations.xml: Translation of the final German
+	  word missing from the XML file.
+
+2014-10-25 [r1614]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/nodesx.c, src/planetsplitter.c,
+	  src/relationsx.c: Sort the data geographically before pruning so
+	  that the data points physically close together are close together
+	  in memory which reduces swapping/paging and therefore runs much
+	  faster when memory is limited.
+
+2014-10-23 [r1613]  Andrew M. Bishop <amb>
+
+	* src/logging.c: Comment fixes, tidy-up and one bug fixed.
+
+2014-10-22 [r1612]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/waysx.c: Use the waysx->idata array instead
+	  of wayx->id when logging node errors during the segment creation.
+
+2014-10-21 [r1609-1611]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt: Correct errors in wayx->id usage when
+	  compacting ways.
+
+	* src/logging.c: Improve the message printed at the end when using
+	  --logtime or --logmemory.
+
+	* src/planetsplitter.c: Clarify some comments.
+
+2014-10-18 [r1608]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/segmentsx.c: Use the waysx->idata array
+	  when logging duplicate segments rather than looking up the wayx
+	  and using its id, also saves mapping the ways into memory.
+
+2014-10-18 [r1606-1607]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/segmentsx.c: Use the nodesx->idata array
+	  when logging duplicate segments rather than looking up the nodex
+	  and using its id.
+
+	* src/nodesx.c: Shrink the size of the nodesx->idata array when
+	  removing non-highway nodes.
+
+2014-10-18 [r1605]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/nodesx.c, src/planetsplitter.c,
+	  src/relationsx.c, src/segmentsx.c, src/superx.c: Free memory that
+	  it allocated by IndexSegments() when no longer needed rather than
+	  holding on to it.
+
+2014-10-14 [r1604]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, src/planetsplitter.c: Speed up the database
+	  generation when pruning by reducing the amount of random memory
+	  accesses are required by compacting the database after each step.
+	  Unless there is enough RAM to hold all the memory mapped files
+	  this should be faster.
+
+2014-10-13 [r1603]  Andrew M. Bishop <amb>
+
+	* src/nodes.c, src/segments.c, src/segments.h, src/segmentsx.c: Try
+	  to speed up the search for the closest node/segment by minimising
+	  the number of nodes that are examined in detail.
+
+2014-10-10 [r1602]  Andrew M. Bishop <amb>
+
+	* src/nodes.c, src/relations.c, src/segments.c, src/ways.c: Record
+	  the memory used by the node, segment, way and relation caches in
+	  the slim mode router.
+
+2014-10-10 [r1601]  Andrew M. Bishop <amb>
+
+	* extras/find-fixme/fixme-finder.c, src/logging.c,
+	  src/planetsplitter.c, src/router.c: Log the router time in
+	  microseconds rather than milliseconds. Add a note at the end
+	  about the format of the time and memory logging.
+
+2014-10-10 [r1600]  Andrew M. Bishop <amb>
+
+	* doc/USAGE.txt, doc/html/usage.html, src/logging.c, src/nodes.c,
+	  src/optimiser.c, src/results.c, src/router.c: Add the '--logtime'
+	  and '--logmemory' options to the router to report the time and
+	  maximum memory in use (allocated and mapped files) during each
+	  step of the routing.
+
+2014-09-30 [r1599]  Andrew M. Bishop <amb>
+
+	* extras/find-fixme/fixme-dumper.c,
+	  extras/find-fixme/fixme-finder.c,
+	  extras/tagmodifier/tagmodifier.c, src/filedumper.c,
+	  src/filedumperx.c, src/planetsplitter.c, src/router.c: Use exit()
+	  when exiting the program other than at the end of the main
+	  function.
+
+2014-09-27 [r1598]  Andrew M. Bishop <amb>
+
+	* doc/DATALIFE.txt, doc/USAGE.txt, doc/html/usage.html,
+	  extras/find-fixme/README.txt, extras/find-fixme/fixme-finder.c,
+	  src/errorlogx.c, src/files.c, src/logging.c, src/logging.h,
+	  src/nodesx.c, src/planetsplitter.c, src/prunex.c,
+	  src/relationsx.c, src/segmentsx.c, src/sorting.c, src/superx.c,
+	  src/typesx.h, src/waysx.c: Add a '--logmemory' option to
+	  planetsplitter which will report the maximum memory in use
+	  (allocated and mapped files) during each step of the processing.
+
+2014-09-27 [r1597]  Andrew M. Bishop <amb>
+
+	* src/nodes.h, src/relations.c, src/segments.c, src/ways.c,
+	  src/waysx.h: Be more consistent in the way that cache.h is
+	  included.
+
+2014-09-26 [r1596]  Andrew M. Bishop <amb>
+
+	* src/logging.c, src/logging.h: Make a function static in logging.c
+	  rather than global.
+
+2014-09-26 [r1592-1595]  Andrew M. Bishop <amb>
+
+	* src/planetsplitter.c: Free the segment list before generating the
+	  errorlog files (it isn't used).
+
+	* src/prunex.c: Change a comment and the style in which some data
+	  is freed.
+
+	* src/segmentsx.c: Free segmentsx->usedway in FreeSegmentList()
+	  rather than letting it leak.
+
+	* src/nodesx.c: Free segmentsx->firstnode in SaveNodeList() like
+	  DATALIFE.txt says it should be.
+
+2014-09-23 [r1591]  Andrew M. Bishop <amb>
+
+	* src/files.c, src/files.h, src/sorting.c: Allocate only the memory
+	  that is needed (but never more than the limit) when sorting files
+	  (i.e. don't just allocate the limit without checking).
+
+2014-09-18 [r1589-1590]  Andrew M. Bishop <amb>
+
+	* src/visualiser.c: Update comments for the functions (some were
+	  wrong, all were unclear).
+
+	* extras/find-fixme/osmparser.c: Remove unused macros.
+
+2014-08-27 [r1588]  Andrew M. Bishop <amb>
+
+	* web/translations/translation.de.txt: Add updated German
+	  translation submitted via http://www.routino.org/translations/ on
+	  2014-08-26.
+
+2014-07-26 [r1587]  Andrew M. Bishop <amb>
+
+	* src/profiles.c: Limit the property preferences to a factor of 100
+	  preference for a highway having a property compared to a highway
+	  not having the property (was 10000).
+
+2014-07-04 [r1586]  Andrew M. Bishop <amb>
+
+	* doc/NEWS.txt: Fix release date for 2.7.2.
+
 2014-06-26  Andrew M. Bishop <amb>
 
 	Version 2.7.2 released.
diff --git a/doc/DATALIFE.txt b/doc/DATALIFE.txt
index 15c3597..85447a7 100644
--- a/doc/DATALIFE.txt
+++ b/doc/DATALIFE.txt
@@ -6,13 +6,14 @@ Key (memory mapping):
   NSWR = Mapped into memory read/write
 
 Key (structure parameter usage):
-  C = Created (allocated; write-only)
-  D = Destroyed (de-allocated; read-only)
-  U = Used (read only)
-  R = Replaced (not used; write-only)
-  M = Modified (used and replaced; read and write)
+  C = Created   (allocated then written; write-only)
+  D = Destroyed (read then de-allocated; read-only)
+  U = Used      (read; read-only)
+  W = Written   (written; write-only)
+  M = Modified  (read then written; read/write)
+  T = Temporary (written then read; read/write)
   | = Preserved unmodified for later
-  * = Applies to super-segments
+  * = In this loop the current iteration of (super-)segments are in uppercase, the next iteration are in lowercase.
 
                               .............................
                               : Nodes        \
@@ -41,41 +42,51 @@ Function name (in order)      :      :   .   .   .   .   :   .   .   .   .   .
 |                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : | ...........
 v                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : v :
                               :......:...................:.......................:...........:...:
+(Parse XML etc)               :      :   .   .   .   . W :   .   .   .   .   .   :   .   . W : W :
+                              :......:...................:.......................:...........:...:
 SortNodeList                  :      : C .   .   .   . U :   .   .   .   .   .   :   .   . | : | :
-SortWayList                   :      : | .   .   .   . | :   .   .   .   .   .   : C .   . | : | :
-SortRelationList              :      : | .   .   .   . | :   .   .   .   .   .   : | .   . | : U :
-RemoveNonHighwayNodes         :      : M .   .   .   . U :   .   .   .   .   .   : | .   . | : | :
-SplitWays                     :      : U .   .   .   . | :   .   .   . C .   . C : | .   . U : | :
-SortWayNames                  :   W  : | .   .   .   . | :   .   .   . | .   . | : | .   . | : | :
-SortSegmentList               :      : | .   .   .   . | :   .   .   . U .   . | : | .   . | : | :
-ProcessSegments               : n w  : | .   .   .   . U :   .   . C . U .   . U : | .   . U : | :
-IndexSegments                 :  S   : | .   .   .   .   : C .   . | . U . C . | : | .   . | : | :
-ProcessRouteRelations         :   W  : | .   .   .   .   : | .   . | . | . | . | : U .   . | : U :
-ProcessTurnRelations          : Nsw  : D .   .   .   .   : U .   . | . U . U . | : D .   . | : U :
-CompactWayList                :      :   .   .   .   .   :   .   . D . | .   . | :   . C . M :   :
-IndexSegments                 :  S   :   .   .   .   .   : R .   .   . U . R . M :   . D . | :   :
+SortWayList                   :      : | .   .   .   . | :   .   .   .   .   .   : C .   . U : | :
+SortRelationList              :      : | .   .   .   . | :   .   .   .   .   .   : | .   .   : U :
+RemoveNonHighwayNodes         :      : M .   .   .   . U :   .   .   .   .   .   : | .   .   : | :
+SplitWays                     :      : U .   .   .   .   :   .   .   . W .   . W : U .   .   : | :
+SortWayNames                  :   W  : | .   .   .   .   :   .   .   . | .   . | : | .   .   : | :
+SortSegmentList               :      : | .   .   .   .   :   .   .   . U .   . | : | .   .   : | :
+ProcessSegments               : n    : U .   .   .   .   :   .   . C . U .   . U : U .   .   : | :
+IndexSegments                 :  S   : | .   .   .   .   : C .   . | . U . W . | : | .   .   : | :
+ProcessRouteRelations         :   W  : | .   .   .   .   : | .   . | . | . | . | : U .   .   : U :
+ProcessTurnRelations          : Nsw  : D .   .   .   .   : D .   . | . U . U . | : D .   .   : U :
+CompactWayList                :      :   .   .   .   .   :   .   . D . | .   . | :   . C . T :   :
+                              :......:...................:.......................:...........:...:
+SortNodeListGeographically    :      :   . C .   .   . T :   .   .   . | .   . | :   . | .   :   :
+SortSegmentListGeographically :      :   . U .   .   .   :   .   .   . M .   . | :   . | .   :   :
+IndexSegments                 :  S   :   . | .   .   .   : C .   .   . U . W . | :   . D .   :   :
+SortTurnRelationListGeogra... :  s   :   . D .   .   .   : U .   .   . U . U . | :   .   .   :   :
                               :......:...................:.......................:...........:...:
-StartPruning                  :      :   .   .   .   .   : | . C .   . U . U . | :   .   . | :   : \
-PruneStraightHighwayNodes     : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   . | :   :  | O
-PruneIsolatedRegions          : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   . | :   :  | p
-PruneShortSegments            : NSw  :   .   .   .   .   : U . U .   . U . U . | :   .   . | :   :  | t
-FinishPruning                 :      :   .   .   .   .   : | . D .   . | .   . | :   .   . | :   :  | i
-RemovePrunedNodes             :      :   .   . C .   .   : U .   .   . | .   . | :   .   . | :   :  | o
-RemovePrunedSegments          :      :   .   . | .   .   :   .   . C . U .   . | :   .   . | :   :  | n
-CompactWayList                :      :   .   . | .   .   :   .   . D . | .   . | :   . C . M :   :  | a
-RemovePrunedTurnRelations     :      :   .   . U .   .   :   .   .   . | .   . | :   . | .   :   :  | l
-IndexSegments                 :  S   :   .   . D .   .   : R .   .   . M . R . | :   . D .   :   : /
+StartPruning                  :      :   .   .   .   .   : | . C .   . U . U . | :   .   .   :   : <---+
+PruneStraightHighwayNodes     : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : \ o |
+PruneIsolatedRegions          : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : | n |
+PruneShortSegments            : NSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : / e | L
+FinishPruning                 :      :   .   .   .   .   : | . D .   . | .   . | :   .   .   :   :     | o
+RemovePrunedNodes             :      :   .   . C .   .   : D .   .   . | .   . | :   .   .   :   :     | o
+RemovePrunedSegments          :      :   .   . | .   .   :   .   . C . U .   . | :   .   .   :   :     | p
+CompactWayList                :      :   .   . | .   .   :   .   . D . | .   . | :   . C . T :   :     |
+RemovePrunedTurnRelations     :      :   .   . U .   .   :   .   .   . | .   . | :   . | .   :   :     |
+IndexSegments                 :  S   :   .   . D .   .   : C .   .   . M . W . | :   . D .   :   :     |
+                              :......:...................:.......................:...........:...: ----+
+ChooseSuperNodes              :  sw  :   .   .   . M .   : U .   .   . | . U . | :   .   .   :   :
+CreateSuperSegments           : nsw  :   .   .   . U .   : D .   .   .*Uw. U . | :   .   .   :   :
+DeduplicateSuperSegments      :   w  :   .   .   . | .   :   .   .   .*Uu.   . | :   .   .   :   :
                               :......:...................:.......................:...........:...:
-ChooseSuperNodes              :  sw  :   .   .   . M .   : U .   .   . | . U*. | :   .   .   :   : <-+ L
-CreateSuperSegments           : nsw  :   .   .   . U .   : U .   .   . R*. U*. | :   .   .   :   :   | o
-DeduplicateSuperSegments      :   w  :   .   .   . | .   :   .   .   . U*.   . | :   .   .   :   :   | o
-IndexSegments                 :  S   :   .   .   . | .   : C*.   .   . U*. C*. | :   .   .   :   :   | p
-                              :......:...................:.......................:...........:...: --+
+IndexSegments                 :  S   :   .   .   . | .   : C .   .   . U . W . | :   .   .   :   : <-+
+ChooseSuperNodes              :  sw  :   .   .   . M .   : U .   .   . | . U . | :   .   .   :   :   | L
+CreateSuperSegments           : nsw  :   .   .   . U .   : D .   .   .*Uw. U . | :   .   .   :   :   | o
+DeduplicateSuperSegments      :   w  :   .   .   . | .   :   .   .   .*Uu.   . | :   .   .   :   :   | o
+                              :......:...................:.......................:...........:...: --+ p
 MergeSuperSegments            :      :   .   .   . | .   :   .   .   . U .   . | :   .   .   :   :
                               :......:...................:.......................:...........:...:
-SortNodeListGeographically    :      :   . C .   . D . R :   .   .   . | .   . | :   .   .   :   :
-SortSegmentListGeographically :      :   . U .   .   .   :   .   .   . U .   . | :   .   .   :   :
-IndexSegments                 :  S   :   . | .   .   .   : R .   .   . U . R . | :   .   .   :   :
+SortNodeListGeographically    :      :   . C .   . D . T :   .   .   . | .   . | :   .   .   :   :
+SortSegmentListGeographically :      :   . U .   .   .   :   .   .   . M .   . | :   .   .   :   :
+IndexSegments                 :  S   :   . | .   .   .   : C .   .   . U . W . | :   .   .   :   :
 SortTurnRelationListGeogra... :  s   :   . D .   .   .   : U .   .   . U . U . | :   .   .   :   :
                               :......:...................:.......................:...........:...:
 SaveNodeList                  :      :   .   .   .   .   : D .   .   . | . | . | :   .   .   :   :
@@ -83,3 +94,13 @@ SaveSegmentList               :      :   .   .   .   .   :   .   .   . U . U . U
 SaveWayList                   :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
 SaveRelationList              :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
                               :......:...................:.......................:...........:...:
+                                     : m . m . m . m . m : m . m . m . m . m . m : m . m . m : m :
+                                     : a . a . a . a . m : a . a . a . m . m . m : a . a . m : m :
+                                     : l . l . l . l . a : l . l . l . a . a . a : l . l . a : a :
+                                     : l . l . l . l . p : l . l . l . p . p . p : l . l . p : p :
+                                     : o . o . o . o .   : o . o . o .   .   .   : o . o .   :   :
+                                     : c . c . c . c .   : c . c . c .   .   .   : c . c .   :   :
+
+
+Note: waysx->odata, relationsx->rridata, relationsx->rrodata and relationsx->tridata are only used
+by the error log creation functions which are optional (all use malloc and not mmap).
diff --git a/doc/NEWS.txt b/doc/NEWS.txt
index 7046f46..2c50b7d 100644
--- a/doc/NEWS.txt
+++ b/doc/NEWS.txt
@@ -1,5 +1,28 @@
-Version 2.7.2 of Routino released : Thu May 26 2014
----------------------------------------------------
+Version 2.7.3 of Routino released : Sat Nov 8 2014
+--------------------------------------------------
+
+Bug fixes:
+  Limit the property preference ratio to 100 instead of 10000.
+  Don't allocate memory for sorting that won't be used.
+
+planetsplitter:
+  Added an option to print out the allocated/mapped memory at each step.
+  Speed up database generation by compacting results after each pruning step.
+  Speed up database generation by sorting nodes geographically before pruning.
+  Reduce memory use while generating the database.  
+
+router:
+  Added the options to print out time and allocated/mapped memory at each step.
+
+Translations:
+  Updated German translations.
+
+
+Note: This version is compatible with databases from version 2.7.1 & 2.7.2.
+
+
+Version 2.7.2 of Routino released : Thu June 26 2014
+----------------------------------------------------
 
 Bug fixes:
   Make the visualiser display all segments including those crossing the border.
diff --git a/doc/README.txt b/doc/README.txt
index 4a9b2df..c401e49 100644
--- a/doc/README.txt
+++ b/doc/README.txt
@@ -128,6 +128,7 @@ Status
    Version 2.7 of Routino was released on 22nd March 2014.
    Version 2.7.1 of Routino was released on 17th May 2014.
    Version 2.7.2 of Routino was released on 26th June 2014.
+   Version 2.7.3 of Routino was released on 8th November 2014.
 
    The full version history is available in the NEWS.txt file.
 
diff --git a/doc/USAGE.txt b/doc/USAGE.txt
index 6979740..6405cf7 100644
--- a/doc/USAGE.txt
+++ b/doc/USAGE.txt
@@ -23,7 +23,7 @@ planetsplitter
                          [--sort-ram-size=<size>] [--sort-threads=<number>]
                          [--tmpdir=<dirname>]
                          [--tagging=<filename>]
-                         [--loggable] [--logtime]
+                         [--loggable] [--logtime] [--logmemory]
                          [--errorlog[=<name>]]
                          [--parse-only | --process-only]
                          [--append] [--keep] [--changes]
@@ -79,7 +79,12 @@ planetsplitter
           suitable for real-time display than logging.
 
    --logtime
-          Print the elapsed time for each processing step.
+          Print the elapsed time for each processing step (minutes,
+          seconds and milliseconds).
+
+   --logmemory
+          Print the maximum allocated and mapped memory for each
+          processing step (MBytes).
 
    --errorlog[=<name>]
           Log OSM parsing and processing errors to 'error.log' or the
@@ -204,7 +209,7 @@ router
                  [--dir=<dirname>] [--prefix=<name>]
                  [--profiles=<filename>] [--translations=<filename>]
                  [--exact-nodes-only]
-                 [--loggable | --quiet]
+                 [--quiet | [--loggable] [--logtime] [--logmemory]]
                  [--output-html]
                  [--output-gpx-track] [--output-gpx-route]
                  [--output-text] [--output-text-all]
@@ -272,14 +277,22 @@ router
           within a segment (quicker but less accurate unless the points
           are already near nodes).
 
+   --quiet
+          Don't generate any screen output while running (useful for
+          running in a script).
+
    --loggable
           Print progress messages that are suitable for logging to a file;
           normally an incrementing counter is printed which is more
           suitable for real-time display than logging.
 
-   --quiet
-          Don't generate any screen output while running (useful for
-          running in a script).
+   --logtime
+          Print the elapsed time for each processing step (minutes,
+          seconds and milliseconds).
+
+   --logmemory
+          Print the maximum allocated and mapped memory for each
+          processing step (MBytes).
 
    --language=<lang>
           Select the language specified from the file of translations. If
diff --git a/doc/html/readme.html b/doc/html/readme.html
index 446129f..4888484 100644
--- a/doc/html/readme.html
+++ b/doc/html/readme.html
@@ -206,13 +206,15 @@ Version 2.7 of Routino was released on 22nd March 2014.
 Version 2.7.1 of Routino was released on 17th May 2014.
 <br>
 Version 2.7.2 of Routino was released on 26th June 2014.
+<br>
+Version 2.7.3 of Routino was released on 8th November 2014.
 
 <p>
 
 The full version history is available in the NEWS.txt file.
 
 
-<h3 id="H_1_5_1" title="Changes_2.7">Changes in Versions 2.7</h3>
+<h3 id="H_1_5_1" title="Changes 2.7">Changes in Versions 2.7</h3>
 
 Version 2.7 - mostly web page usability improvements.
 
@@ -262,7 +264,7 @@ Version 2.7 - mostly web page usability improvements.
 <p>
 <b>Note:</b> Note: This version is compatible with databases from version 2.6.
 
-<h3 id="H_1_5_2" title="Changes_2.7.1">Changes in Versions 2.7.1</h3>
+<h3 id="H_1_5_2" title="Changes 2.7.1">Changes in Versions 2.7.1</h3>
 
 Version 2.7.1 - mostly bug fixes (some from version 2.7, but mostly older ones).
 
@@ -305,7 +307,7 @@ Version 2.7.1 - mostly bug fixes (some from version 2.7, but mostly older ones).
 <b>Note:</b> This version is not compatible with databases from previous versions.
 
 
-<h3 id="H_1_5_3" title="Changes_2.7.2">Changes in Versions 2.7.2</h3>
+<h3 id="H_1_5_3" title="Changes 2.7.2">Changes in Versions 2.7.2</h3>
 
 Version 2.7.2 - mostly bug fixes introduced in version 2.7.1 on 64-bit systems.
 
@@ -326,6 +328,32 @@ Version 2.7.2 - mostly bug fixes introduced in version 2.7.1 on 64-bit systems.
 <b>Note:</b> This version is compatible with databases from version 2.7.1.
 
 
+<h3 id="H_1_5_4" title="Changes 2.7.3">Changes in Versions 2.7.3</h3>
+
+Version 2.7.3 - Slightly reduced memory usage and large reduction in time to generate routing database on low memory systems.
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Limit the property preference ratio to 100 instead of 10000.
+    <br>Don't allocate memory for sorting that won't be used.
+
+  <dt>planetsplitter:
+    <dd>Added an option to print out the allocated/mapped memory at each step.
+    <br>Speed up database generation by compacting results after each pruning step.
+    <br>Speed up database generation by sorting nodes geographically before pruning.
+    <br>Reduce memory use while generating the database.  
+
+  <dt>router:
+    <dd>Added the options to print out time and allocated/mapped memory at each step.
+
+  <dt>Translations:
+    <dd>Updated German translations.
+</dl>
+
+<p>
+<b>Note:</b> This version is compatible with databases from version 2.7.1 & 2.7.2.
+
+
 
 <h2 id="H_1_6">License</h2>
 
diff --git a/doc/html/usage.html b/doc/html/usage.html
index cc70195..fce5a2c 100644
--- a/doc/html/usage.html
+++ b/doc/html/usage.html
@@ -68,7 +68,7 @@ Usage: planetsplitter [--help]
                       [--sort-ram-size=<size>] [--sort-threads=<number>]
                       [--tmpdir=<dirname>]
                       [--tagging=<filename>]
-                      [--loggable] [--logtime]
+                      [--loggable] [--logtime] [--logmemory]
                       [--errorlog[=<name>]]
                       [--parse-only | --process-only]
                       [--append] [--keep] [--changes]
@@ -116,7 +116,9 @@ Usage: planetsplitter [--help]
     an incrementing counter is printed which is more suitable for real-time
     display than logging.
   <dt>--logtime
-  <dd>Print the elapsed time for each processing step.
+  <dd>Print the elapsed time for each processing step (minutes, seconds and milliseconds).
+  <dt>--logmemory
+  <dd>Print the maximum allocated and mapped memory for each processing step (MBytes).
   <dt>--errorlog[=<name>]
   <dd>Log OSM parsing and processing errors to 'error.log' or the specified file
     name (the '--dir' and '--prefix' options are applied).  If the --append
@@ -230,7 +232,7 @@ Usage: router [--help | --help-profile | --help-profile-xml |
               [--dir=<dirname>] [--prefix=<name>]
               [--profiles=<filename>] [--translations=<filename>]
               [--exact-nodes-only]
-              [--loggable | --quiet]
+              [--quiet | [--loggable] [--logtime] [--logmemory]]
               [--output-html]
               [--output-gpx-track] [--output-gpx-route]
               [--output-text] [--output-text-all]
@@ -288,12 +290,16 @@ Usage: router [--help | --help-profile | --help-profile-xml |
   <dd>When processing the specified latitude and longitude points only select
     the nearest node instead of finding the nearest point within a segment
     (quicker but less accurate unless the points are already near nodes).
+  <dt>--quiet
+  <dd>Don't generate any screen output while running (useful for running in a script).
   <dt>--loggable
   <dd>Print progress messages that are suitable for logging to a file; normally
     an incrementing counter is printed which is more suitable for real-time
     display than logging.
-  <dt>--quiet
-  <dd>Don't generate any screen output while running (useful for running in a script).
+  <dt>--logtime
+  <dd>Print the elapsed time for each processing step (minutes, seconds and milliseconds).
+  <dt>--logmemory
+  <dd>Print the maximum allocated and mapped memory for each processing step (MBytes).
   <dt>--language=<lang>
   <dd>Select the language specified from the file of translations.  If this
     option is not given and the file exists then the first language in the file
diff --git a/extras/find-fixme/README.txt b/extras/find-fixme/README.txt
index 7271182..0286bab 100644
--- a/extras/find-fixme/README.txt
+++ b/extras/find-fixme/README.txt
@@ -25,7 +25,7 @@ Usage: fixme-finder [--help]
                     [--sort-ram-size=<size>] [--sort-threads=<number>]
                     [--tmpdir=<dirname>]
                     [--tagging=<filename>]
-                    [--loggable] [--logtime]
+                    [--loggable] [--logtime] [--logmemory]
                     [<filename.osm> ...
                      | <filename.pbf> ...
                      | <filename.o5m> ...
@@ -49,6 +49,7 @@ Usage: fixme-finder [--help]
 
 --loggable                Print progress messages suitable for logging to file.
 --logtime                 Print the elapsed time for each processing step.
+--logmemory               Print the max allocated/mapped memory for each step.
 
 <filename.osm>, <filename.pbf>, <filename.o5m>
                           The name(s) of the file(s) to read and parse.
diff --git a/extras/find-fixme/fixme-dumper.c b/extras/find-fixme/fixme-dumper.c
index 2be64d1..85b271e 100644
--- a/extras/find-fixme/fixme-dumper.c
+++ b/extras/find-fixme/fixme-dumper.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2013 Andrew M. Bishop
+ This file Copyright 2013-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -172,7 +172,7 @@ int main(int argc,char** argv)
          }
    }
 
- return(0);
+ exit(EXIT_SUCCESS);
 }
 
 
diff --git a/extras/find-fixme/fixme-finder.c b/extras/find-fixme/fixme-finder.c
index f1427f5..ebdb1a4 100644
--- a/extras/find-fixme/fixme-finder.c
+++ b/extras/find-fixme/fixme-finder.c
@@ -99,6 +99,8 @@ int main(int argc,char** argv)
        option_loggable=1;
     else if(!strcmp(argv[arg],"--logtime"))
        option_logtime=1;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
     else if(argv[arg][0]=='-' && argv[arg][1]=='-')
        print_usage(0,argv[arg],NULL);
     else
@@ -267,9 +269,12 @@ int main(int argc,char** argv)
  FreeWayList(OSMWays,0);
  FreeRelationList(OSMRelations,0);
 
+ printf("\n");
+ fflush(stdout);
+
  printf_program_end();
 
- return(0);
+ exit(EXIT_SUCCESS);
 }
 
 
@@ -295,7 +300,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
 #endif
          "                    [--tmpdir=<dirname>]\n"
          "                    [--tagging=<filename>]\n"
-         "                    [--loggable] [--logtime]\n"
+         "                    [--loggable] [--logtime] [--logmemory]\n"
          "                    [<filename.osm> ...\n"
          "                     | <filename.pbf> ...\n"
          "                     | <filename.o5m> ..."
@@ -345,6 +350,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
             "\n"
             "--loggable                Print progress messages suitable for logging to file.\n"
             "--logtime                 Print the elapsed time for each processing step.\n"
+            "--logmemory               Print the max allocated/mapped memory for each step.\n"
             "\n"
             "<filename.osm>, <filename.pbf>, <filename.o5m>\n"
             "                          The name(s) of the file(s) to read and parse.\n"
diff --git a/extras/find-fixme/osmparser.c b/extras/find-fixme/osmparser.c
index 60af70b..782be96 100644
--- a/extras/find-fixme/osmparser.c
+++ b/extras/find-fixme/osmparser.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -36,14 +36,6 @@
 #include "logging.h"
 
 
-/* Macros */
-
-/*+ Checks if a value in the XML is one of the allowed values for true. +*/
-#define ISTRUE(xx)  (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1"))
-
-/*+ Checks if a value in the XML is one of the allowed values for false. +*/
-#define ISFALSE(xx) (!strcmp(xx,"false") || !strcmp(xx,"no") || !strcmp(xx,"0"))
-
 /* Local variables */
 
 static NodesX     *nodes;
diff --git a/extras/tagmodifier/tagmodifier.c b/extras/tagmodifier/tagmodifier.c
index de0b91c..2f884eb 100644
--- a/extras/tagmodifier/tagmodifier.c
+++ b/extras/tagmodifier/tagmodifier.c
@@ -589,7 +589,7 @@ int main(int argc,char **argv)
     if(!ExistsFile(tagging))
       {
        fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
-       return(1);
+       exit(EXIT_FAILURE);
       }
    }
  else
@@ -599,14 +599,14 @@ int main(int argc,char **argv)
     else
       {
        fprintf(stderr,"Error: The '--tagging' option was not used and the default 'tagging.xml' does not exist.\n");
-       return(1);
+       exit(EXIT_FAILURE);
       }
    }
 
  if(ParseXMLTaggingRules(tagging))
    {
     fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
-    return(1);
+    exit(EXIT_FAILURE);
    }
 
  /* Open the input file */
diff --git a/src/errorlogx.c b/src/errorlogx.c
index c7c9508..c961505 100644
--- a/src/errorlogx.c
+++ b/src/errorlogx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2013 Andrew M. Bishop
+ This file Copyright 2013-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -334,6 +334,7 @@ static void reindex_nodes(NodesX *nodesx)
  nodesx->number=nodesx->knumber;
 
  nodesx->idata=(node_t*)malloc(nodesx->number*sizeof(node_t));
+ log_malloc(nodesx->idata,nodesx->number*sizeof(node_t));
 
  /* Get the node id for each node in the file. */
 
@@ -368,6 +369,9 @@ static void reindex_ways(WaysX *waysx)
  waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
  waysx->odata=(off_t*)malloc(waysx->number*sizeof(off_t));
 
+ log_malloc(waysx->idata,waysx->number*sizeof(way_t));
+ log_malloc(waysx->odata,waysx->number*sizeof(off_t));
+
  /* Get the way id and the offset for each way in the file */
 
  fd=ReOpenFileBuffered(waysx->filename);
@@ -413,6 +417,9 @@ static void reindex_relations(RelationsX *relationsx)
  relationsx->rridata=(relation_t*)malloc(relationsx->rrnumber*sizeof(relation_t));
  relationsx->rrodata=(off_t*)malloc(relationsx->rrnumber*sizeof(off_t));
 
+ log_malloc(relationsx->rridata,relationsx->rrnumber*sizeof(relation_t));
+ log_malloc(relationsx->rrodata,relationsx->rrnumber*sizeof(off_t));
+
  /* Get the relation id and the offset for each relation in the file */
 
  fd=ReOpenFileBuffered(relationsx->rrfilename);
@@ -444,6 +451,8 @@ static void reindex_relations(RelationsX *relationsx)
 
  relationsx->tridata=(relation_t*)malloc(relationsx->trnumber*sizeof(relation_t));
 
+ log_malloc(relationsx->tridata,relationsx->trnumber*sizeof(relation_t));
+
  /* Get the relation id and the offset for each relation in the file */
 
  fd=ReOpenFileBuffered(relationsx->trfilename);
diff --git a/src/filedumper.c b/src/filedumper.c
index 9aded19..3a36036 100644
--- a/src/filedumper.c
+++ b/src/filedumper.c
@@ -483,7 +483,7 @@ int main(int argc,char** argv)
          }
    }
 
- return(0);
+ exit(EXIT_SUCCESS);
 }
 
 
diff --git a/src/filedumperx.c b/src/filedumperx.c
index 6a77314..8f6300f 100644
--- a/src/filedumperx.c
+++ b/src/filedumperx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -115,7 +115,7 @@ int main(int argc,char** argv)
          }
    }
 
- return(0);
+ exit(EXIT_SUCCESS);
 }
 
 
diff --git a/src/files.c b/src/files.c
index 94fee7d..586c256 100644
--- a/src/files.c
+++ b/src/files.c
@@ -142,6 +142,8 @@ void *MapFile(const char *filename)
     exit(EXIT_FAILURE);
    }
 
+ log_mmap(size);
+
  /* Store the information about the mapped file */
 
  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
@@ -204,6 +206,8 @@ void *MapFileWriteable(const char *filename)
     exit(EXIT_FAILURE);
    }
 
+ log_mmap(size);
+
  /* Store the information about the mapped file */
 
  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
@@ -249,6 +253,8 @@ void *UnmapFile(const void *address)
 
  munmap(mappedfiles[i].address,mappedfiles[i].length);
 
+ log_munmap(mappedfiles[i].length);
+
  /* Shuffle the list of files */
 
  nmappedfiles--;
@@ -619,6 +625,28 @@ off_t SizeFile(const char *filename)
 
 
 /*++++++++++++++++++++++++++++++++++++++
+  Get the size of a file from a file descriptor.
+
+  off_t SizeFileFD Returns the file size if OK or exits in case of an error.
+
+  int fd The file descriptor to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+off_t SizeFileFD(int fd)
+{
+ struct stat buf;
+
+ if(fstat(fd,&buf))
+   {
+    fprintf(stderr,"Cannot stat file descriptor '%d' [%s].\n",fd,strerror(errno));
+    exit(EXIT_FAILURE);
+   }
+
+ return(buf.st_size);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
   Check if a file exists.
 
   int ExistsFile Returns 1 if the file exists and 0 if not.
diff --git a/src/files.h b/src/files.h
index 1d76dbd..726457f 100644
--- a/src/files.h
+++ b/src/files.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -67,6 +67,7 @@ int OpenFile(const char *filename);
 void CloseFile(int fd);
 
 off_t SizeFile(const char *filename);
+off_t SizeFileFD(int fd);
 int ExistsFile(const char *filename);
 
 int DeleteFile(const char *filename);
diff --git a/src/logging.c b/src/logging.c
index 0a3c027..2f3c560 100644
--- a/src/logging.c
+++ b/src/logging.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -35,9 +35,22 @@
 /*+ The option to print the output in a way that allows logging to a file. +*/
 int option_loggable=0;
 
-/*+ The option to print timestamps with the output. +*/
+/*+ The option to print elapsed time with the output. +*/
 int option_logtime=0;
 
+/*+ The option to print memory usage with the output. +*/
+int option_logmemory=0;
+
+
+/* Local data types */
+
+/*+ A structure to contain the list of allocated memory. +*/
+struct mallocinfo
+{
+ void  *address;            /*+ The address of the allocated memory. +*/
+ size_t size;               /*+ The size of the allocated memory. +*/
+};
+
 
 /* Local functions */
 
@@ -45,6 +58,9 @@ static void vfprintf_first(FILE *file,const char *format,va_list ap);
 static void vfprintf_middle(FILE *file,const char *format,va_list ap);
 static void vfprintf_last(FILE *file,const char *format,va_list ap);
 
+static void fprintf_elapsed_time(FILE *file,struct timeval *start);
+static void fprintf_max_memory(FILE *file,size_t max_alloc,size_t max_mmap);
+
 
 /* Local variables */
 
@@ -54,9 +70,24 @@ static struct timeval program_start_time;
 /*+ The time that printf_first() was called. +*/
 static struct timeval function_start_time;
 
+/*+ The list of allocated memory. +*/
+static struct mallocinfo *mallocedmem;
+
+/*+ The number of allocated memory blocks. +*/
+static int nmallocedmem=0;
+
 /*+ The length of the string printed out last time. +*/
 static int printed_length=0;
 
+/*+ The maximum amount of memory allocated and memory mapped since starting the program. +*/
+static size_t program_max_alloc=0,program_max_mmap=0;
+
+/*+ The maximum amount of memory allocated and memory mapped since starting the function. +*/
+static size_t function_max_alloc=0,function_max_mmap=0;
+
+/*+ The current amount of memory allocated and memory mapped. +*/
+static size_t current_alloc=0,current_mmap=0;
+
 
 /*++++++++++++++++++++++++++++++++++++++
   Record the time that the program started.
@@ -65,6 +96,8 @@ static int printed_length=0;
 void printf_program_start(void)
 {
  gettimeofday(&program_start_time,NULL);
+
+ program_max_alloc=program_max_mmap=0;
 }
 
 
@@ -74,11 +107,36 @@ void printf_program_start(void)
 
 void printf_program_end(void)
 {
- if(option_logtime)
+ if(option_logtime || option_logmemory)
    {
+    if(option_logtime)
+       fprintf_elapsed_time(stdout,&program_start_time);
+
+    if(option_logmemory)
+       fprintf_max_memory(stdout,program_max_alloc,program_max_mmap);
+
+    printf("Finish Program\n");
+
+    if(option_logtime==2)
+       printf("[ m:ss.micros] ");
+    else if(option_logtime==1)
+       printf("[ m:ss.mil] ");
+
+    if(option_logmemory)
+       printf("[RAM,FILE MB] ");
+
+    if(option_logtime)
+       printf("elapsed time");
+
+    if(option_logmemory)
+      {
+       if(option_logtime)
+          printf(", ");
+       printf("maximum memory");
+      }
+
     printf("\n");
-    fprintf_elapsed_time(stdout,&program_start_time);
-    printf("Complete\n");
+
     fflush(stdout);
    }
 }
@@ -99,6 +157,12 @@ void printf_first(const char *format, ...)
  if(option_logtime)
     gettimeofday(&function_start_time,NULL);
 
+ if(option_logmemory)
+   {
+    function_max_alloc=current_alloc;
+    function_max_mmap=current_mmap;
+   }
+
  if(option_loggable)
     return;
 
@@ -170,6 +234,12 @@ void fprintf_first(FILE *file,const char *format, ...)
  if(option_logtime)
     gettimeofday(&function_start_time,NULL);
 
+ if(option_logmemory)
+   {
+    function_max_alloc=current_alloc;
+    function_max_mmap=current_mmap;
+   }
+
  if(option_loggable)
     return;
 
@@ -229,6 +299,125 @@ void fprintf_last(FILE *file,const char *format, ...)
 
 
 /*++++++++++++++++++++++++++++++++++++++
+  Record the memory allocations (record the amount in use).
+
+  void *address The address that has been allocated.
+
+  size_t size The size of the memory that has been allocated.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_malloc(void *address,size_t size)
+{
+ int i;
+
+ if(!option_logmemory)
+    return;
+
+ /* Store the information about the allocated memory */
+
+ for(i=0;i<nmallocedmem;i++)
+    if(mallocedmem[i].address==address)
+      {
+       size=size-mallocedmem[i].size;
+       mallocedmem[i].size+=size;
+       break;
+      }
+
+ if(i==nmallocedmem)
+   {
+    mallocedmem=(struct mallocinfo*)realloc((void*)mallocedmem,(nmallocedmem+1)*sizeof(struct mallocinfo));
+
+    mallocedmem[nmallocedmem].address=address;
+    mallocedmem[nmallocedmem].size=size;
+
+    nmallocedmem++;
+   }
+
+ /* Increase the sum of allocated memory */
+
+ current_alloc+=size;
+
+ if(current_alloc>function_max_alloc)
+    function_max_alloc=current_alloc;
+
+ if(current_alloc>program_max_alloc)
+    program_max_alloc=current_alloc;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the memory de-allocations.
+
+  void *address The address that has been freed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_free(void *address)
+{
+ size_t size=0;
+ int i;
+
+ if(!option_logmemory)
+    return;
+
+ /* Remove the information about the allocated memory */
+
+ for(i=0;i<nmallocedmem;i++)
+    if(mallocedmem[i].address==address)
+      {
+       size=mallocedmem[i].size;
+       break;
+      }
+
+ logassert(i!=nmallocedmem,"Memory freed with log_free() was not allocated with log_[cm]alloc()");
+
+ nmallocedmem--;
+
+ if(nmallocedmem>i)
+    memmove(&mallocedmem[i],&mallocedmem[i+1],(nmallocedmem-i)*sizeof(struct mallocinfo));
+
+ /* Reduce the sum of allocated memory */
+
+ current_alloc-=size;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the amount of memory that has been mapped into files.
+
+  size_t size The size of the file that has been mapped.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_mmap(size_t size)
+{
+ if(!option_logmemory)
+    return;
+
+ current_mmap+=size;
+
+ if(current_mmap>function_max_mmap)
+    function_max_mmap=current_mmap;
+
+ if(current_mmap>program_max_mmap)
+    program_max_mmap=current_mmap;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the amount of memory that has been unmapped from files.
+
+  size_t size The size of the file that has been unmapped.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_munmap(size_t size)
+{
+ if(!option_logmemory)
+    return;
+
+ current_mmap-=size;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
   Do the work to print the first message in an overwriting sequence.
 
   FILE *file The file to write to.
@@ -245,6 +434,9 @@ static void vfprintf_first(FILE *file,const char *format,va_list ap)
  if(option_logtime)
     fprintf_elapsed_time(file,&function_start_time);
 
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
  retval=vfprintf(file,format,ap);
  fflush(file);
 
@@ -272,6 +464,9 @@ static void vfprintf_middle(FILE *file,const char *format,va_list ap)
  if(option_logtime)
     fprintf_elapsed_time(file,&function_start_time);
 
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
  retval=vfprintf(file,format,ap);
  fflush(file);
 
@@ -307,6 +502,9 @@ static void vfprintf_last(FILE *file,const char *format,va_list ap)
  if(option_logtime)
     fprintf_elapsed_time(file,&function_start_time);
 
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
  retval=vfprintf(file,format,ap);
 
  if(retval>0)
@@ -326,7 +524,7 @@ static void vfprintf_last(FILE *file,const char *format,va_list ap)
   struct timeval *start The start time from which the elapsed time is to be printed.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void fprintf_elapsed_time(FILE *file,struct timeval *start)
+static void fprintf_elapsed_time(FILE *file,struct timeval *start)
 {
  struct timeval finish,elapsed;
 
@@ -340,7 +538,26 @@ void fprintf_elapsed_time(FILE *file,struct timeval *start)
     elapsed.tv_usec+=1000000;
    }
 
- fprintf(file,"[%2ld:%02ld.%03ld] ",elapsed.tv_sec/60,elapsed.tv_sec%60,elapsed.tv_usec/1000);
+ if(option_logtime==2)
+    fprintf(file,"[%2ld:%02ld.%06ld] ",elapsed.tv_sec/60,elapsed.tv_sec%60,elapsed.tv_usec);
+ else
+    fprintf(file,"[%2ld:%02ld.%03ld] ",elapsed.tv_sec/60,elapsed.tv_sec%60,elapsed.tv_usec/1000);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the maximum used memory without a following newline.
+
+  FILE *file The file to print to.
+
+  size_t max_alloc The maximum amount of allocated memory.
+
+  size_t max_mmap The maximum amount of memory mapped memory.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void fprintf_max_memory(FILE *file,size_t max_alloc,size_t max_mmap)
+{
+ fprintf(file,"[%3d, %3d MB] ",max_alloc/(1024*1024),max_mmap/(1024*1024));
 }
 
 
diff --git a/src/logging.h b/src/logging.h
index cc61bf6..dbe83f0 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -47,6 +47,7 @@ typedef struct _ErrorLogObject
 
 extern int option_loggable;
 extern int option_logtime;
+extern int option_logmemory;
 
 
 /* Runtime progress logging functions in logging.c */
@@ -77,7 +78,11 @@ void fprintf_last(FILE *file,const char *format, ...);
 
 #endif
 
-void fprintf_elapsed_time(FILE *file,struct timeval *start);
+void log_malloc(void *address,size_t size);
+void log_free(void *address);
+
+void log_mmap(size_t size);
+void log_munmap(size_t size);
 
 
 /* Error logging functions in logerror.c */
diff --git a/src/nodes.c b/src/nodes.c
index e021f0b..a3b7f26 100644
--- a/src/nodes.c
+++ b/src/nodes.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -78,12 +78,14 @@ Nodes *LoadNodeList(const char *filename)
  sizeoffsets=(nodes->file.latbins*nodes->file.lonbins+1)*sizeof(index_t);
 
  nodes->offsets=(index_t*)malloc(sizeoffsets);
+ log_malloc(nodes->offsets,sizeoffsets);
 
  SlimFetch(nodes->fd,nodes->offsets,sizeoffsets,sizeof(NodesFile));
 
  nodes->nodesoffset=sizeof(NodesFile)+sizeoffsets;
 
  nodes->cache=NewNodeCache();
+ log_malloc(nodes->cache,sizeof(*nodes->cache));
 
 #endif
 
@@ -107,8 +109,10 @@ void DestroyNodeList(Nodes *nodes)
 
  nodes->fd=SlimUnmapFile(nodes->fd);
 
+ log_free(nodes->offsets);
  free(nodes->offsets);
 
+ log_free(nodes->cache);
  DeleteNodeCache(nodes->cache);
 
 #endif
@@ -150,6 +154,26 @@ index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitu
  index_t    bestn=NO_NODE;
  distance_t bestd=INF_DISTANCE;
 
+ /* Find the maximum distance to search */
+
+ double dlat=DeltaLat(longitude,distance);
+ double dlon=DeltaLon(latitude ,distance);
+
+ double minlat=latitude -dlat;
+ double maxlat=latitude +dlat;
+ double minlon=longitude-dlon;
+ double maxlon=longitude+dlon;
+
+ ll_bin_t minlatbin=latlong_to_bin(radians_to_latlong(minlat))-nodes->file.latzero;
+ ll_bin_t maxlatbin=latlong_to_bin(radians_to_latlong(maxlat))-nodes->file.latzero;
+ ll_bin_t minlonbin=latlong_to_bin(radians_to_latlong(minlon))-nodes->file.lonzero;
+ ll_bin_t maxlonbin=latlong_to_bin(radians_to_latlong(maxlon))-nodes->file.lonzero;
+
+ ll_off_t minlatoff=latlong_to_off(radians_to_latlong(minlat));
+ ll_off_t maxlatoff=latlong_to_off(radians_to_latlong(maxlat));
+ ll_off_t minlonoff=latlong_to_off(radians_to_latlong(minlon));
+ ll_off_t maxlonoff=latlong_to_off(radians_to_latlong(maxlon));
+
  /* Start with the bin containing the location, then spiral outwards. */
 
  do
@@ -161,70 +185,48 @@ index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitu
 
     for(latb=latbin-delta;latb<=latbin+delta;latb++)
       {
-       if(latb<0 || latb>=nodes->file.latbins)
+       if(latb<0 || latb>=nodes->file.latbins || latb<minlatbin || latb>maxlatbin)
           continue;
 
        for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
          {
-          if(lonb<0 || lonb>=nodes->file.lonbins)
+          if(lonb<0 || lonb>=nodes->file.lonbins || lonb<minlonbin || lonb>maxlonbin)
              continue;
 
           if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
              continue;
 
+          /* Check every node in this grid square. */
+
           llbin=lonb*nodes->file.latbins+latb;
 
-          /* Check if this grid square has any hope of being close enough */
+          index1=LookupNodeOffset(nodes,llbin);
+          index2=LookupNodeOffset(nodes,llbin+1);
 
-          if(delta>0)
+          for(i=index1;i<index2;i++)
             {
-             double lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb));
-             double lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb));
-             double lat2=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb+1));
-             double lon2=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb+1));
-
-             if(latb==latbin)
-               {
-                distance_t dist1=Distance(latitude,lon1,latitude,longitude);
-                distance_t dist2=Distance(latitude,lon2,latitude,longitude);
-
-                if(dist1>distance && dist2>distance)
-                   continue;
-               }
-             else if(lonb==lonbin)
-               {
-                distance_t dist1=Distance(lat1,longitude,latitude,longitude);
-                distance_t dist2=Distance(lat2,longitude,latitude,longitude);
+             Node *nodep=LookupNode(nodes,i,3);
+             double lat,lon;
+             distance_t dist;
 
-                if(dist1>distance && dist2>distance)
-                   continue;
-               }
-             else
-               {
-                distance_t dist1=Distance(lat1,lon1,latitude,longitude);
-                distance_t dist2=Distance(lat2,lon1,latitude,longitude);
-                distance_t dist3=Distance(lat2,lon2,latitude,longitude);
-                distance_t dist4=Distance(lat1,lon2,latitude,longitude);
+             if(latb==minlatbin && nodep->latoffset<minlatoff)
+                continue;
 
-                if(dist1>distance && dist2>distance && dist3>distance && dist4>distance)
-                   continue;
-               }
-            }
+             if(latb==maxlatbin && nodep->latoffset>maxlatoff)
+                continue;
 
-          /* Check every node in this grid square. */
+             if(lonb==minlonbin && nodep->lonoffset<minlonoff)
+                continue;
 
-          index1=LookupNodeOffset(nodes,llbin);
-          index2=LookupNodeOffset(nodes,llbin+1);
+             if(lonb==maxlonbin && nodep->lonoffset>maxlonoff)
+                continue;
 
-          for(i=index1;i<index2;i++)
-            {
-             Node *nodep=LookupNode(nodes,i,3);
-             double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
-             double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+             lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+             lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
 
-             distance_t dist=Distance(lat,lon,latitude,longitude);
+             dist=Distance(lat,lon,latitude,longitude);
 
-             if(dist<distance)
+             if(dist<bestd)
                {
                 Segment *segmentp;
 
@@ -237,7 +239,7 @@ index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitu
                    if(IsNormalSegment(segmentp) && valid_segment_for_profile(ways,segmentp,profile))
                      {
                       bestn=i;
-                      bestd=distance=dist;
+                      bestd=dist;
 
                       break;
                      }
@@ -306,6 +308,26 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
  distance_t bestd=INF_DISTANCE,bestd1=INF_DISTANCE,bestd2=INF_DISTANCE;
  index_t    bests=NO_SEGMENT;
 
+ /* Find the maximum distance to search */
+
+ double dlat=DeltaLat(longitude,distance);
+ double dlon=DeltaLon(latitude ,distance);
+
+ double minlat=latitude -dlat;
+ double maxlat=latitude +dlat;
+ double minlon=longitude-dlon;
+ double maxlon=longitude+dlon;
+
+ ll_bin_t minlatbin=latlong_to_bin(radians_to_latlong(minlat))-nodes->file.latzero;
+ ll_bin_t maxlatbin=latlong_to_bin(radians_to_latlong(maxlat))-nodes->file.latzero;
+ ll_bin_t minlonbin=latlong_to_bin(radians_to_latlong(minlon))-nodes->file.lonzero;
+ ll_bin_t maxlonbin=latlong_to_bin(radians_to_latlong(maxlon))-nodes->file.lonzero;
+
+ ll_off_t minlatoff=latlong_to_off(radians_to_latlong(minlat));
+ ll_off_t maxlatoff=latlong_to_off(radians_to_latlong(maxlat));
+ ll_off_t minlonoff=latlong_to_off(radians_to_latlong(minlon));
+ ll_off_t maxlonoff=latlong_to_off(radians_to_latlong(maxlon));
+
  /* Start with the bin containing the location, then spiral outwards. */
 
  do
@@ -317,68 +339,45 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
 
     for(latb=latbin-delta;latb<=latbin+delta;latb++)
       {
-       if(latb<0 || latb>=nodes->file.latbins)
+       if(latb<0 || latb>=nodes->file.latbins || latb<minlatbin || latb>maxlatbin)
           continue;
 
        for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
          {
-          if(lonb<0 || lonb>=nodes->file.lonbins)
+          if(lonb<0 || lonb>=nodes->file.lonbins || lonb<minlonbin || lonb>maxlonbin)
              continue;
 
           if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
              continue;
 
-          llbin=lonb*nodes->file.latbins+latb;
-
-          /* Check if this grid square has any hope of being close enough */
-
-          if(delta>0)
-            {
-             double lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb));
-             double lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb));
-             double lat2=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb+1));
-             double lon2=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb+1));
-
-             if(latb==latbin)
-               {
-                distance_t dist1=Distance(latitude,lon1,latitude,longitude);
-                distance_t dist2=Distance(latitude,lon2,latitude,longitude);
-
-                if(dist1>distance && dist2>distance)
-                   continue;
-               }
-             else if(lonb==lonbin)
-               {
-                distance_t dist1=Distance(lat1,longitude,latitude,longitude);
-                distance_t dist2=Distance(lat2,longitude,latitude,longitude);
-
-                if(dist1>distance && dist2>distance)
-                   continue;
-               }
-             else
-               {
-                distance_t dist1=Distance(lat1,lon1,latitude,longitude);
-                distance_t dist2=Distance(lat2,lon1,latitude,longitude);
-                distance_t dist3=Distance(lat2,lon2,latitude,longitude);
-                distance_t dist4=Distance(lat1,lon2,latitude,longitude);
-
-                if(dist1>distance && dist2>distance && dist3>distance && dist4>distance)
-                   continue;
-               }
-            }
-
           /* Check every node in this grid square. */
 
+          llbin=lonb*nodes->file.latbins+latb;
+
           index1=LookupNodeOffset(nodes,llbin);
           index2=LookupNodeOffset(nodes,llbin+1);
 
           for(i=index1;i<index2;i++)
             {
              Node *nodep=LookupNode(nodes,i,3);
-             double lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
-             double lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+             double lat1,lon1;
              distance_t dist1;
 
+             if(latb==minlatbin && nodep->latoffset<minlatoff)
+                continue;
+
+             if(latb==maxlatbin && nodep->latoffset>maxlatoff)
+                continue;
+
+             if(lonb==minlonbin && nodep->lonoffset<minlonoff)
+                continue;
+
+             if(lonb==maxlonbin && nodep->lonoffset>maxlonoff)
+                continue;
+
+             lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+             lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+
              dist1=Distance(lat1,lon1,latitude,longitude);
 
              if(dist1<distance)
@@ -463,9 +462,9 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
                    segmentp=NextSegment(segments,segmentp,i);
                   }
                 while(segmentp);
-               }
 
-            } /* dist1 < distance */
+               } /* dist1 < distance */
+            }
 
           count++;
          }
diff --git a/src/nodes.h b/src/nodes.h
index 01832aa..6dc7064 100644
--- a/src/nodes.h
+++ b/src/nodes.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -27,8 +27,8 @@
 #include <sys/types.h>
 
 #include "types.h"
-#include "cache.h"
 
+#include "cache.h"
 #include "files.h"
 #include "profiles.h"
 
diff --git a/src/nodesx.c b/src/nodesx.c
index 7474ba7..186fcb4 100644
--- a/src/nodesx.c
+++ b/src/nodesx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -102,6 +102,7 @@ NodesX *NewNodeList(int append,int readonly)
 
 #if SLIM
  nodesx->cache=NewNodeXCache();
+ log_malloc(nodesx->cache,sizeof(*nodesx->cache));
 #endif
 
  return(nodesx);
@@ -127,18 +128,31 @@ void FreeNodeList(NodesX *nodesx,int keep)
  free(nodesx->filename_tmp);
 
  if(nodesx->idata)
+   {
+    log_free(nodesx->idata);
     free(nodesx->idata);
+   }
 
  if(nodesx->gdata)
+   {
+    log_free(nodesx->gdata);
     free(nodesx->gdata);
+   }
 
  if(nodesx->pdata)
+   {
+    log_free(nodesx->pdata);
     free(nodesx->pdata);
+   }
 
  if(nodesx->super)
+   {
+    log_free(nodesx->super);
     free(nodesx->super);
+   }
 
 #if SLIM
+ log_free(nodesx->cache);
  DeleteNodeXCache(nodesx->cache);
 #endif
 
@@ -278,6 +292,7 @@ void SortNodeList(NodesX *nodesx)
  /* Allocate the array of indexes */
 
  nodesx->idata=(node_t*)malloc(nodesx->number*sizeof(node_t));
+ log_malloc(nodesx->idata,nodesx->number*sizeof(node_t));
 
  logassert(nodesx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -379,11 +394,12 @@ void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
 
  /* Print the start message */
 
- printf_first("Checking Ways for unused Nodes: Ways=0");
+ printf_first("Checking Ways for unused Nodes: Ways=0 Highway Nodes=0");
 
  /* Allocate the node usage bitmask */
 
  usednode=AllocBitMask(nodesx->number);
+ log_malloc(usednode,LengthBitMask(nodesx->number)*sizeof(BitMask));
 
  logassert(usednode,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
@@ -410,7 +426,12 @@ void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
        waysize-=sizeof(node_t);
 
        if(index!=NO_NODE)
+         {
+          if(!IsBitSet(usednode,index))
+             highway++;
+
           SetBit(usednode,index);
+         }
       }
 
     waysize-=sizeof(node_t)+sizeof(WayX);
@@ -418,22 +439,37 @@ void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
     SkipFileBuffered(waysx->fd,waysize);
 
     if(!((i+1)%1000))
-       printf_middle("Checking Ways for unused Nodes: Ways=%"Pindex_t,i+1);
+       printf_middle("Checking Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,i+1,highway);
    }
 
+ /* Free the now-unneeded index */
+
+ log_free(nodesx->idata);
+ free(nodesx->idata);
+ nodesx->idata=NULL;
+
  /* Close the file */
 
  waysx->fd=CloseFileBuffered(waysx->fd);
 
  /* Print the final message */
 
- printf_last("Checked Ways for unused Nodes: Ways=%"Pindex_t,waysx->number);
+ printf_last("Checked Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,waysx->number,highway);
 
 
  /* Print the start message */
 
  printf_first("Removing unused Nodes: Nodes=0");
 
+ /* Allocate the array of indexes */
+
+ nodesx->idata=(node_t*)malloc(highway*sizeof(node_t));
+ log_malloc(nodesx->idata,highway*sizeof(node_t));
+
+ logassert(nodesx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ highway=0;
+
  /* Re-open the file read-only and a new file writeable */
 
  nodesx->fd=ReOpenFileBuffered(nodesx->filename_tmp);
@@ -475,6 +511,7 @@ void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
 
  /* Free the now-unneeded index */
 
+ log_free(usednode);
  free(usednode);
 
  /* Print the final message */
@@ -507,6 +544,7 @@ void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx)
  /* Allocate the array of indexes */
 
  nodesx->pdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->pdata,nodesx->number*sizeof(index_t));
 
  logassert(nodesx->pdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -550,6 +588,15 @@ void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx)
  nodesx->fd=CloseFileBuffered(nodesx->fd);
  CloseFileBuffered(fd);
 
+ /* Free the no-longer required memory */
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+    segmentsx->firstnode=NULL;
+   }
+
  /* Print the final message */
 
  printf_last("Deleted Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
@@ -584,6 +631,7 @@ void SortNodeListGeographically(NodesX *nodesx)
  /* Allocate the memory for the geographical index array */
 
  nodesx->gdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->gdata,nodesx->number*sizeof(index_t));
 
  logassert(nodesx->gdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -608,23 +656,30 @@ void SortNodeListGeographically(NodesX *nodesx)
  nodesx->fd=CloseFileBuffered(nodesx->fd);
  CloseFileBuffered(fd);
 
- /* Free the memory */
+ /* Work out the number of bins */
 
- free(nodesx->super);
- nodesx->super=NULL;
+ if(nodesx->super)
+   {
+    lat_min_bin=latlong_to_bin(lat_min);
+    lon_min_bin=latlong_to_bin(lon_min);
+    lat_max_bin=latlong_to_bin(lat_max);
+    lon_max_bin=latlong_to_bin(lon_max);
 
- /* Work out the number of bins */
+    nodesx->latzero=lat_min_bin;
+    nodesx->lonzero=lon_min_bin;
 
- lat_min_bin=latlong_to_bin(lat_min);
- lon_min_bin=latlong_to_bin(lon_min);
- lat_max_bin=latlong_to_bin(lat_max);
- lon_max_bin=latlong_to_bin(lon_max);
+    nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
+    nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
+   }
 
- nodesx->latzero=lat_min_bin;
- nodesx->lonzero=lon_min_bin;
+ /* Free the memory */
 
- nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
- nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
+ if(nodesx->super)
+   {
+    log_free(nodesx->super);
+    free(nodesx->super);
+    nodesx->super=NULL;
+   }
 
  /* Print the final message */
 
@@ -646,7 +701,7 @@ static int update_id(NodeX *nodex,index_t index)
 {
  nodex->id=index;
 
- if(IsBitSet(sortnodesx->super,index))
+ if(sortnodesx->super && IsBitSet(sortnodesx->super,index))
     nodex->flags|=NODE_SUPER;
 
  return(1);
@@ -717,14 +772,17 @@ static int index_by_lat_long(NodeX *nodex,index_t index)
 {
  sortnodesx->gdata[nodex->id]=index;
 
- if(nodex->latitude<lat_min)
-    lat_min=nodex->latitude;
- if(nodex->latitude>lat_max)
-    lat_max=nodex->latitude;
- if(nodex->longitude<lon_min)
-    lon_min=nodex->longitude;
- if(nodex->longitude>lon_max)
-    lon_max=nodex->longitude;
+ if(sortnodesx->super)
+   {
+    if(nodex->latitude<lat_min)
+       lat_min=nodex->latitude;
+    if(nodex->latitude>lat_max)
+       lat_max=nodex->latitude;
+    if(nodex->longitude<lon_min)
+       lon_min=nodex->longitude;
+    if(nodex->longitude>lon_max)
+       lon_max=nodex->longitude;
+   }
 
  return(1);
 }
@@ -840,6 +898,12 @@ void SaveNodeList(NodesX *nodesx,const char *filename,SegmentsX *segmentsx)
 
  CloseFileBuffered(fd);
 
+ /* Free the memory in the segments */
+
+ log_free(segmentsx->firstnode);
+ free(segmentsx->firstnode);
+ segmentsx->firstnode=NULL;
+
  /* Print the final message */
 
  printf_last("Wrote Nodes: Nodes=%"Pindex_t,nodesx->number);
diff --git a/src/optimiser.c b/src/optimiser.c
index 7c766a4..e61571e 100644
--- a/src/optimiser.c
+++ b/src/optimiser.c
@@ -371,7 +371,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
 #if !DEBUG
  if(!option_quiet)
-    printf_first("Routing: Super-Nodes checked = 0");
+    printf_first("Finding Middle Route: Super-Nodes checked = 0");
 #endif
 
  /* Set up the finish conditions */
@@ -628,22 +628,12 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
              InsertInQueue(queue,result2,potential_score);
          }
 
-#if !DEBUG
-       if(!option_quiet && !(results->number%1000))
-          printf_middle("Routing: Super-Nodes checked = %d",results->number);
-#endif
-
       endloop:
 
        segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */
       }
    }
 
-#if !DEBUG
- if(!option_quiet)
-    printf_last("Routing: Super-Nodes checked = %d",results->number);
-#endif
-
  FreeQueueList(queue);
 
  /* Check it worked */
@@ -654,6 +644,11 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
     printf("    Failed\n");
 #endif
 
+#if !DEBUG
+    if(!option_quiet)
+       printf_last("Found Middle Route: Super-Nodes checked = %d - Fail",results->number);
+#endif
+
     FreeResultsList(results);
     return(NULL);
    }
@@ -683,6 +678,11 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
    }
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Found Middle Route: Super-Nodes checked = %d",results->number);
+#endif
+
  return(results);
 }
 
@@ -936,6 +936,11 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
  printf("  FindStartRoutes(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Finding Start Route: Nodes checked = 0");
+#endif
+
  /* Create the list of results and insert the first node into the queue */
 
  results=NewResultsList(8);
@@ -1153,6 +1158,11 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
     printf("    Failed (%d results, %d super)\n",results->number,nsuper);
 #endif
 
+#if !DEBUG
+    if(!option_quiet)
+       printf_last("Found Start Route: Nodes checked = %d - Fail",results->number);
+#endif
+
     FreeResultsList(results);
     return(NULL);
    }
@@ -1199,6 +1209,11 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
    }
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Found Start Route: Nodes checked = %d",results->number);
+#endif
+
  return(results);
 }
 
@@ -1235,6 +1250,11 @@ Results *ExtendStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations
  printf("  ExtendStartRoutes(...,[begin has %d nodes],finish_node=%"Pindex_t")\n",begin->number,finish_node);
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Extending Start Route: Nodes checked = 0");
+#endif
+
  /* Check the list of results and insert the super nodes into the queue */
 
  queue=NewQueueList(8);
@@ -1448,6 +1468,11 @@ Results *ExtendStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations
    }
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Extended Start Route: Nodes checked = %d",results->number);
+#endif
+
  return(results);
 }
 
@@ -1480,6 +1505,11 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
  printf("  FindFinishRoutes(...,finish_node=%"Pindex_t")\n",finish_node);
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Finding Finish Route: Nodes checked = 0");
+#endif
+
  /* Create the results and insert the finish node into the queue */
 
  results=NewResultsList(8);
@@ -1676,6 +1706,11 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
     printf("    Failed\n");
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Found Finish Route: Nodes checked = %d - Fail",results->number);
+#endif
+
     FreeResultsList(results);
     return(NULL);
    }
@@ -1747,6 +1782,11 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
    }
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Found Finish Route: Nodes checked = %d",results->number);
+#endif
+
  return(results2);
 }
 
@@ -1780,6 +1820,11 @@ Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *rel
  printf("  CombineRoutes(...,[begin has %d nodes],[middle has %d nodes])\n",begin->number,middle->number);
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Finding Combined Route: Nodes = 0");
+#endif
+
  combined=NewResultsList(10);
 
  combined->start_node=begin->start_node;
@@ -1837,7 +1882,15 @@ Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *rel
        Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres1->node,comres1->segment,midres->next->node);
 
        if(!results)
+         {
+#if !DEBUG
+          if(!option_quiet)
+             printf_last("Found Combined Route: Nodes = %d - Fail",combined->number);
+#endif
+
+          FreeResultsList(combined);
           return(NULL);
+         }
 
        result=FindResult(results,midres->node,comres1->segment);
 
@@ -1892,6 +1945,11 @@ Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *rel
    }
 #endif
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Found Combined Route: Nodes = %d",combined->number);
+#endif
+
  return(combined);
 }
 
diff --git a/src/planetsplitter.c b/src/planetsplitter.c
index 22bf6d3..f4a7910 100644
--- a/src/planetsplitter.c
+++ b/src/planetsplitter.c
@@ -108,6 +108,8 @@ int main(int argc,char** argv)
        option_loggable=1;
     else if(!strcmp(argv[arg],"--logtime"))
        option_logtime=1;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
     else if(!strcmp(argv[arg],"--errorlog"))
        errorlog="error.log";
     else if(!strncmp(argv[arg],"--errorlog=",11))
@@ -313,7 +315,7 @@ if(!option_process_only)
     FreeWayList(OSMWays,1);
     FreeRelationList(OSMRelations,1);
 
-    return(0);
+    exit(EXIT_SUCCESS);
    }
 
 
@@ -335,11 +337,11 @@ if(!option_process_only)
  printf("\nProcess OSM Data\n================\n\n");
  fflush(stdout);
 
- /* Remove non-highway nodes by looking through the ways */
+ /* Remove non-highway nodes by looking through the ways (must be before splitting the ways) */
 
  RemoveNonHighwayNodes(OSMNodes,OSMWays,option_keep||option_changes);
 
- /* Separate the segments and way names and sort them. */
+ /* Separate the segments and way names and sort them (must be before processing the segments) */
 
  OSMSegments=SplitWays(OSMWays,OSMNodes,option_keep||option_changes);
 
@@ -347,7 +349,7 @@ if(!option_process_only)
 
  SortSegmentList(OSMSegments);
 
- /* Process the segments and index them */
+ /* Process the segments and index them (must be before processing relations) */
 
  ProcessSegments(OSMSegments,OSMNodes,OSMWays);
 
@@ -359,42 +361,78 @@ if(!option_process_only)
 
  ProcessTurnRelations(OSMRelations,OSMNodes,OSMSegments,OSMWays,option_keep||option_changes);
 
- /* Compact the ways (must be after processing turn relations) */
+ /* Compact the ways */
 
  CompactWayList(OSMWays,OSMSegments);
 
- /* Index the segments */
+ /* Sort the nodes and segments geographically */
+
+ SortNodeListGeographically(OSMNodes);
+
+ SortSegmentListGeographically(OSMSegments,OSMNodes);
+
+ /* Re-index the segments */
 
  IndexSegments(OSMSegments,OSMNodes,OSMWays);
 
- /* Prune unwanted nodes/segments. */
+ /* Sort the turn relations geographically */
+
+ SortTurnRelationListGeographically(OSMRelations,OSMNodes,OSMSegments);
+
+ /* Prune unwanted nodes/segments */
 
  if(option_prune_straight || option_prune_isolated || option_prune_short)
    {
     printf("\nPrune Unneeded Data\n===================\n\n");
     fflush(stdout);
 
-    StartPruning(OSMNodes,OSMSegments,OSMWays);
-
     if(option_prune_straight)
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
+
        PruneStraightHighwayNodes(OSMNodes,OSMSegments,OSMWays,option_prune_straight);
 
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
+
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
+
     if(option_prune_isolated)
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
+
        PruneIsolatedRegions(OSMNodes,OSMSegments,OSMWays,option_prune_isolated);
 
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
+
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
+
     if(option_prune_short)
-       PruneShortSegments(OSMNodes,OSMSegments,OSMWays,option_prune_short);
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
 
-    FinishPruning(OSMNodes,OSMSegments,OSMWays);
+       PruneShortSegments(OSMNodes,OSMSegments,OSMWays,option_prune_short);
 
-    /* Remove the pruned nodes, segments, ways and relations and update the indexes */
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
 
-    RemovePrunedNodes(OSMNodes,OSMSegments);
-    RemovePrunedSegments(OSMSegments,OSMWays);
-    CompactWayList(OSMWays,OSMSegments);
-    RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
 
-    IndexSegments(OSMSegments,OSMNodes,OSMWays);
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
    }
 
  /* Repeated iteration on Super-Nodes and Super-Segments */
@@ -422,6 +460,10 @@ if(!option_process_only)
       {
        SegmentsX *SuperSegments2;
 
+       /* Index the super-segments */
+
+       IndexSegments(SuperSegments,OSMNodes,OSMWays);
+
        /* Select the super-nodes */
 
        ChooseSuperNodes(OSMNodes,SuperSegments,OSMWays);
@@ -441,10 +483,6 @@ if(!option_process_only)
 
     DeduplicateSuperSegments(SuperSegments,OSMWays);
 
-    /* Index the segments */
-
-    IndexSegments(SuperSegments,OSMNodes,OSMWays);
-
     /* Check for end condition */
 
     if(SuperSegments->number==nsuper)
@@ -512,6 +550,10 @@ if(!option_process_only)
 
  SaveRelationList(OSMRelations,FileName(dirname,prefix,"relations.mem"));
 
+ /* Free the memory (delete the temporary files) */
+
+ FreeSegmentList(OSMSegments);
+
  /* Close the error log file and process the data */
 
  if(errorlog)
@@ -543,11 +585,12 @@ if(!option_process_only)
  FreeWayList(OSMWays,0);
  FreeRelationList(OSMRelations,0);
 
- FreeSegmentList(OSMSegments);
+ printf("\n");
+ fflush(stdout);
 
  printf_program_end();
 
- return(0);
+ exit(EXIT_SUCCESS);
 }
 
 
@@ -573,7 +616,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
 #endif
          "                      [--tmpdir=<dirname>]\n"
          "                      [--tagging=<filename>]\n"
-         "                      [--loggable] [--logtime]\n"
+         "                      [--loggable] [--logtime] [--logmemory]\n"
          "                      [--errorlog[=<name>]]\n"
          "                      [--parse-only | --process-only]\n"
          "                      [--append] [--keep] [--changes]\n"
@@ -634,6 +677,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
             "\n"
             "--loggable                Print progress messages suitable for logging to file.\n"
             "--logtime                 Print the elapsed time for each processing step.\n"
+            "--logmemory               Print the max allocated/mapped memory for each step.\n"
             "--errorlog[=<name>]       Log parsing errors to 'error.log' or the given name\n"
             "                          (the '--dir' and '--prefix' options are applied).\n"
             "\n"
diff --git a/src/profiles.c b/src/profiles.c
index 3ce66bb..26accad 100644
--- a/src/profiles.c
+++ b/src/profiles.c
@@ -750,11 +750,11 @@ int UpdateProfile(Profile *profile,Ways *ways)
     profile->props_yes[i] =sqrt(profile->props_yes[i]);
     profile->props_no [i] =sqrt(profile->props_no[i] );
 
-    if(profile->props_yes[i]<0.0001)
-       profile->props_yes[i]=0.0001;
+    if(profile->props_yes[i]<0.01)
+       profile->props_yes[i]=0.01;
 
-    if(profile->props_no[i]<0.0001)
-       profile->props_no[i]=0.0001;
+    if(profile->props_no[i]<0.01)
+       profile->props_no[i]=0.01;
    }
 
  /* Find the fastest preferred speed */
diff --git a/src/prunex.c b/src/prunex.c
index f09798e..140cef2 100644
--- a/src/prunex.c
+++ b/src/prunex.c
@@ -77,8 +77,9 @@ void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  /* Allocate the array of next segment */
 
  segmentsx->next1=(index_t*)calloc(segmentsx->number,sizeof(index_t));
+ log_malloc(segmentsx->next1,segmentsx->number*sizeof(index_t));
 
- logassert(segmentsx->next1,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+ logassert(segmentsx->next1,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
 
  /* Open the file read-only */
 
@@ -129,9 +130,11 @@ void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 {
  if(segmentsx->next1)
+   {
+    log_free(segmentsx->next1);
     free(segmentsx->next1);
-
- segmentsx->next1=NULL;
+    segmentsx->next1=NULL;
+   }
 }
 
 
@@ -184,14 +187,17 @@ void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,dista
  connected=AllocBitMask(segmentsx->number);
  region   =AllocBitMask(segmentsx->number);
 
+ log_malloc(connected,LengthBitMask(segmentsx->number)*sizeof(BitMask));
+ log_malloc(region   ,LengthBitMask(segmentsx->number)*sizeof(BitMask));
+
  logassert(connected,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
- logassert(region,"Failed to allocate memory (try using slim mode?)");    /* Check AllocBitMask() worked */
+ logassert(region   ,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
  regionsegments=(index_t*)malloc((nallocregionsegments=1024)*sizeof(index_t));
  othersegments =(index_t*)malloc((nallocothersegments =1024)*sizeof(index_t));
 
  logassert(regionsegments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
- logassert(othersegments,"Failed to allocate memory (try using slim mode?)");  /* Check malloc() worked */
+ logassert(othersegments ,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
  /* Loop through the transport types */
 
@@ -390,6 +396,9 @@ void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,dista
 
  /* Unmap from memory / close the files */
 
+ log_free(region);
+ log_free(connected);
+
  free(region);
  free(connected);
 
@@ -909,12 +918,14 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
 
  checked=AllocBitMask(nodesx->number);
 
+ log_malloc(checked,LengthBitMask(nodesx->number)*sizeof(BitMask));
+
  logassert(checked,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
  nodes   =(index_t*)malloc((nalloc=1024)*sizeof(index_t));
  segments=(index_t*)malloc( nalloc      *sizeof(index_t));
 
- logassert(nodes,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
+ logassert(nodes   ,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
  logassert(segments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
  lats=(double*)malloc(nalloc*sizeof(double));
@@ -1245,6 +1256,7 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
 
  /* Unmap from memory / close the files */
 
+ log_free(checked);
  free(checked);
 
  free(nodes);
diff --git a/src/relations.c b/src/relations.c
index 94ec1d8..06a2e53 100644
--- a/src/relations.c
+++ b/src/relations.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -26,7 +26,6 @@
 #include "relations.h"
 #include "fakes.h"
 
-#include "cache.h"
 #include "files.h"
 
 
@@ -67,6 +66,7 @@ Relations *LoadRelationList(const char *filename)
  relations->troffset=sizeof(RelationsFile);
 
  relations->cache=NewTurnRelationCache();
+ log_malloc(relations->cache,sizeof(*relations->cache));
 
 #endif
 
@@ -103,6 +103,7 @@ void DestroyRelationList(Relations *relations)
 
  relations->fd=SlimUnmapFile(relations->fd);
 
+ log_free(relations->cache);
  DeleteTurnRelationCache(relations->cache);
 
 #endif
diff --git a/src/relationsx.c b/src/relationsx.c
index 4c9a61c..9455dd5 100644
--- a/src/relationsx.c
+++ b/src/relationsx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2013 Andrew M. Bishop
+ This file Copyright 2010-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -57,6 +57,7 @@ static int sort_turn_by_id(TurnRelX *a,TurnRelX *b);
 static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index);
 
 static int geographically_index(TurnRelX *relationx,index_t index);
+static int geographically_index_convert_segments(TurnRelX *relationx,index_t index);
 static int sort_by_via(TurnRelX *a,TurnRelX *b);
 
 
@@ -167,10 +168,16 @@ void FreeRelationList(RelationsX *relationsx,int keep)
  free(relationsx->rrfilename_tmp);
 
  if(relationsx->rridata)
+   {
+    log_free(relationsx->rridata);
     free(relationsx->rridata);
+   }
 
  if(relationsx->rrodata)
+   {
+    log_free(relationsx->rrodata);
     free(relationsx->rrodata);
+   }
 
 
  /* Turn Restriction relations */
@@ -184,7 +191,10 @@ void FreeRelationList(RelationsX *relationsx,int keep)
  free(relationsx->trfilename_tmp);
 
  if(relationsx->tridata)
+   {
+    log_free(relationsx->tridata);
     free(relationsx->tridata);
+   }
 
 
  free(relationsx);
@@ -1116,12 +1126,18 @@ void ProcessTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segme
 
  /* Free the now-unneeded indexes */
 
+ log_free(nodesx->idata);
  free(nodesx->idata);
  nodesx->idata=NULL;
 
+ log_free(waysx->idata);
  free(waysx->idata);
  waysx->idata=NULL;
 
+ log_free(segmentsx->firstnode);
+ free(segmentsx->firstnode);
+ segmentsx->firstnode=NULL;
+
  /* Unmap from memory / close the files */
 
 #if !SLIM
@@ -1219,6 +1235,7 @@ void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
 
 void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
 {
+ static int which=1;
  int trfd;
 
  if(segmentsx->number==0)
@@ -1251,9 +1268,16 @@ void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,Se
  sortnodesx=nodesx;
  sortsegmentsx=segmentsx;
 
- filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index,
-                                                       (int (*)(const void*,const void*))sort_by_via,
-                                                       NULL);
+ if(which==1)
+    filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index,
+                                                          (int (*)(const void*,const void*))sort_by_via,
+                                                          NULL);
+ else
+    filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index_convert_segments,
+                                                          (int (*)(const void*,const void*))sort_by_via,
+                                                          NULL);
+
+ which++;
 
  /* Close the files */
 
@@ -1272,6 +1296,7 @@ void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,Se
 
  if(nodesx->gdata)
    {
+    log_free(nodesx->gdata);
     free(nodesx->gdata);
     nodesx->gdata=NULL;
    }
@@ -1294,6 +1319,26 @@ void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,Se
 
 static int geographically_index(TurnRelX *relationx,index_t index)
 {
+ relationx->from=sortnodesx->gdata[relationx->from];
+ relationx->via =sortnodesx->gdata[relationx->via];
+ relationx->to  =sortnodesx->gdata[relationx->to];
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the turn relation indexes and replace them with segments.
+
+  int geographically_index_convert_segments Return 1 if the value is to be kept, otherwise 0.
+
+  TurnRelX *relationx The extended turn relation.
+
+  index_t index The number of unsorted turn relations that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int geographically_index_convert_segments(TurnRelX *relationx,index_t index)
+{
  SegmentX *segmentx;
  index_t from_node,via_node,to_node;
 
diff --git a/src/results.c b/src/results.c
index e46d9d4..6e038a3 100644
--- a/src/results.c
+++ b/src/results.c
@@ -54,6 +54,9 @@ Results *NewResultsList(uint8_t log2bins)
  results->count=(uint8_t*)calloc(results->nbins,sizeof(uint8_t));
  results->point=(Result**)calloc(results->nbins,sizeof(Result*));
 
+ log_malloc(results->count,results->nbins*sizeof(uint8_t));
+ log_malloc(results->point,results->nbins*sizeof(Result*));
+
  results->ndata1=0;
  results->nallocdata1=0;
  results->ndata2=results->nbins>>2;
@@ -111,12 +114,17 @@ void FreeResultsList(Results *results)
  uint32_t i;
 
  for(i=0;i<results->nallocdata1;i++)
+   {
+    log_free(results->data[i]);
     free(results->data[i]);
+   }
 
  free(results->data);
 
+ log_free(results->point);
  free(results->point);
 
+ log_free(results->count);
  free(results->count);
 
  free(results);
@@ -153,6 +161,9 @@ Result *InsertResult(Results *results,index_t node,index_t segment)
     results->count=(uint8_t*)realloc((void*)results->count,results->nbins*sizeof(uint8_t));
     results->point=(Result**)realloc((void*)results->point,results->nbins*sizeof(Result*));
 
+    log_malloc(results->count,results->nbins*sizeof(uint8_t));
+    log_malloc(results->point,results->nbins*sizeof(Result*));
+
     for(i=0;i<results->nbins/2;i++)
       {
        Result *r=results->point[i];
@@ -199,6 +210,7 @@ Result *InsertResult(Results *results,index_t node,index_t segment)
        results->nallocdata1++;
        results->data=(Result**)realloc((void*)results->data,results->nallocdata1*sizeof(Result*));
        results->data[results->nallocdata1-1]=(Result*)malloc(results->ndata2*sizeof(Result));
+       log_malloc(results->data[results->nallocdata1-1],results->ndata2*sizeof(Result));
       }
    }
 
diff --git a/src/router.c b/src/router.c
index a7f3d42..46c68a9 100644
--- a/src/router.c
+++ b/src/router.c
@@ -94,6 +94,10 @@ int main(int argc,char** argv)
  waypoint_t start_waypoint,finish_waypoint=NO_WAYPOINT;
  waypoint_t first_waypoint=NWAYPOINTS,last_waypoint=1,inc_dec_waypoint,waypoint;
 
+#if !DEBUG
+ printf_program_start();
+#endif
+
  /* Parse the command line arguments */
 
  if(argc<2)
@@ -131,6 +135,10 @@ int main(int argc,char** argv)
        option_quiet=1;
     else if(!strcmp(argv[arg],"--loggable"))
        option_loggable=1;
+    else if(!strcmp(argv[arg],"--logtime"))
+       option_logtime=2;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
     else if(!strcmp(argv[arg],"--output-html"))
        option_html=1;
     else if(!strcmp(argv[arg],"--output-gpx-track"))
@@ -162,6 +170,8 @@ int main(int argc,char** argv)
     argv[arg]=NULL;
    }
 
+ /* Check the specified command line options */
+
  if(option_stdout && (option_html+option_gpx_track+option_gpx_route+option_text+option_text_all)!=1)
    {
     fprintf(stderr,"Error: The '--output-stdout' option requires exactly one other output option (but not '--output-none').\n");
@@ -371,25 +381,25 @@ int main(int argc,char** argv)
    {
     PrintProfile(profile);
 
-    return(0);
+    exit(EXIT_SUCCESS);
    }
  else if(help_profile_xml)
    {
     PrintProfilesXML();
 
-    return(0);
+    exit(EXIT_SUCCESS);
    }
  else if(help_profile_json)
    {
     PrintProfilesJSON();
 
-    return(0);
+    exit(EXIT_SUCCESS);
    }
  else if(help_profile_pl)
    {
     PrintProfilesPerl();
 
-    return(0);
+    exit(EXIT_SUCCESS);
    }
 
  /* Check the waypoints are valid */
@@ -438,6 +448,11 @@ int main(int argc,char** argv)
 
  /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Loading Files:");
+#endif
+
  OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem"));
 
  OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem"));
@@ -446,6 +461,13 @@ int main(int argc,char** argv)
 
  OSMRelations=LoadRelationList(FileName(dirname,prefix,"relations.mem"));
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Loaded Files: nodes, segments, ways & relations");
+#endif
+
+ /* Check the profile compared to the types of ways available */
+
  if(UpdateProfile(profile,OSMWays))
    {
     fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
@@ -485,6 +507,11 @@ int main(int argc,char** argv)
     if(point_used[waypoint]!=3)
        continue;
 
+#if !DEBUG
+    if(!option_quiet)
+       printf_first("Finding Closest Point: Waypoint %d",waypoint);
+#endif
+
     /* Find the closest point */
 
     start_node=finish_node;
@@ -506,6 +533,11 @@ int main(int argc,char** argv)
           finish_node=NO_NODE;
       }
 
+#if !DEBUG
+    if(!option_quiet)
+       printf_last("Found Closest Point: Waypoint %d",waypoint);
+#endif
+
     if(finish_node==NO_NODE)
       {
        fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint);
@@ -568,9 +600,19 @@ int main(int argc,char** argv)
 
  /* Print out the combined route */
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Generating Result Outputs");
+#endif
+
  if(!option_none)
     PrintRoute(results,nresults,OSMNodes,OSMSegments,OSMWays,profile);
 
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Generated Result Outputs");
+#endif
+
  /* Destroy the remaining results lists and data structures */
 
 #ifdef DEBUG_MEMORY_LEAK
@@ -585,7 +627,12 @@ int main(int argc,char** argv)
 
 #endif
 
- return(0);
+#if !DEBUG
+ if(!option_quiet)
+    printf_program_end();
+#endif
+
+ exit(EXIT_SUCCESS);
 }
 
 
@@ -790,7 +837,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
          "              [--dir=<dirname>] [--prefix=<name>]\n"
          "              [--profiles=<filename>] [--translations=<filename>]\n"
          "              [--exact-nodes-only]\n"
-         "              [--loggable | --quiet]\n"
+         "              [--quiet | [--loggable] [--logtime] [--logmemory]]\n"
          "              [--language=<lang>]\n"
          "              [--output-html]\n"
          "              [--output-gpx-track] [--output-gpx-route]\n"
@@ -842,8 +889,10 @@ static void print_usage(int detail,const char *argerr,const char *err)
             "\n"
             "--exact-nodes-only      Only route between nodes (don't find closest segment).\n"
             "\n"
-            "--loggable              Print progress messages suitable for logging to file.\n"
             "--quiet                 Don't print any screen output when running.\n"
+            "--loggable              Print progress messages suitable for logging to file.\n"
+            "--logtime               Print the elapsed time for each processing step.\n"
+            "--logmemory             Print the max allocated/mapped memory for each step.\n"
             "\n"
             "--language=<lang>       Use the translations for specified language.\n"
             "--output-html           Write an HTML description of the route.\n"
diff --git a/src/segments.c b/src/segments.c
index c45963a..fb83b5f 100644
--- a/src/segments.c
+++ b/src/segments.c
@@ -28,7 +28,6 @@
 #include "segments.h"
 #include "ways.h"
 
-#include "cache.h"
 #include "fakes.h"
 #include "files.h"
 #include "profiles.h"
@@ -69,6 +68,7 @@ Segments *LoadSegmentList(const char *filename)
  SlimFetch(segments->fd,&segments->file,sizeof(SegmentsFile),0);
 
  segments->cache=NewSegmentCache();
+ log_malloc(segments->cache,sizeof(*segments->cache));
 
 #endif
 
@@ -92,6 +92,7 @@ void DestroySegmentList(Segments *segments)
 
  segments->fd=SlimUnmapFile(segments->fd);
 
+ log_free(segments->cache);
  DeleteSegmentCache(segments->cache);
 
 #endif
@@ -218,7 +219,7 @@ distance_t Distance(double lat1,double lon1,double lat2,double lon2)
 
  a1 = sin (dlat / 2);
  a2 = sin (dlon / 2);
- a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
+ a = a1 * a1 + cos (lat1) * cos (lat2) * a2 * a2;
  sa = sqrt (a);
  if (sa <= 1.0)
    {c = 2 * asin (sa);}
@@ -231,6 +232,68 @@ distance_t Distance(double lat1,double lon1,double lat2,double lon2)
 
 
 /*++++++++++++++++++++++++++++++++++++++
+  Calculate the change in latitude (same longitude) between two locations a known distance apart.
+
+  double DeltaLat Returns the difference in latitude between the locations.
+
+  double lon The longitude of the locations.
+
+  distance_t distance The distance between the locations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double DeltaLat(double lon,distance_t distance)
+{
+ double dlat;
+
+ double c,d;
+
+ if(distance==0)
+   return 0;
+
+ d = distance_to_km(distance);
+
+ c = d / 6378.137;
+
+ dlat = c;
+
+ return dlat;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the change in longitude (same latitude) between two locations a known distance apart.
+
+  double DeltaLon Returns the difference in longitude between the locations.
+
+  double lat The latitude of the locations.
+
+  distance_t distance The distance between the locations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double DeltaLon(double lat,distance_t distance)
+{
+ double dlon;
+
+ double a2,sa,c,d;
+
+ if(distance==0)
+   return 0;
+
+ d = distance_to_km(distance);
+
+ c = d / 6378.137;
+
+ sa = sin(c/2);
+
+ a2 = sa / cos(lat);
+
+ dlon = 2*asin(a2);
+
+ return dlon;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
   Calculate the duration of travel on a segment.
 
   duration_t Duration Returns the duration of travel.
diff --git a/src/segments.h b/src/segments.h
index 1f99190..3b51605 100644
--- a/src/segments.h
+++ b/src/segments.h
@@ -95,6 +95,9 @@ index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,ind
 
 distance_t Distance(double lat1,double lon1,double lat2,double lon2);
 
+double DeltaLat(double lon,distance_t distance);
+double DeltaLon(double lat,distance_t distance);
+
 duration_t Duration(Segment *segmentp,Way *wayp,Profile *profile);
 
 double TurnAngle(Nodes *nodes,Segment *segment1p,Segment *segment2p,index_t node);
diff --git a/src/segmentsx.c b/src/segmentsx.c
index e70bb46..c54aac7 100644
--- a/src/segmentsx.c
+++ b/src/segmentsx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -85,6 +85,7 @@ SegmentsX *NewSegmentList(void)
 
 #if SLIM
  segmentsx->cache=NewSegmentXCache();
+ log_malloc(segmentsx->cache,sizeof(*segmentsx->cache));
 #endif
 
  return(segmentsx);
@@ -103,13 +104,26 @@ void FreeSegmentList(SegmentsX *segmentsx)
 
  free(segmentsx->filename_tmp);
 
+ if(segmentsx->usedway)
+   {
+    log_free(segmentsx->usedway);
+    free(segmentsx->usedway);
+   }
+
  if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
     free(segmentsx->firstnode);
+   }
 
  if(segmentsx->next1)
+   {
+    log_free(segmentsx->next1);
     free(segmentsx->next1);
+   }
 
 #if SLIM
+ log_free(segmentsx->cache);
  DeleteSegmentXCache(segmentsx->cache);
 #endif
 
@@ -384,18 +398,16 @@ void ProcessSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
 #if !SLIM
  nodesx->data=MapFile(nodesx->filename_tmp);
- waysx->data=MapFile(waysx->filename_tmp);
 #else
  nodesx->fd=SlimMapFile(nodesx->filename_tmp);
- waysx->fd=SlimMapFile(waysx->filename_tmp);
 
  InvalidateNodeXCache(nodesx->cache);
- InvalidateWayXCache(waysx->cache);
 #endif
 
  /* Allocate the way usage bitmask */
 
  segmentsx->usedway=AllocBitMask(waysx->number);
+ log_malloc(segmentsx->usedway,LengthBitMask(waysx->number)*sizeof(BitMask));
 
  logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
@@ -411,36 +423,39 @@ void ProcessSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
  while(!ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX)))
    {
-    NodeX *nodex1=LookupNodeX(nodesx,segmentx.node1,1);
-    NodeX *nodex2=LookupNodeX(nodesx,segmentx.node2,2);
-
     if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
       {
+       node_t id1=nodesx->idata[segmentx.node1];
+       node_t id2=nodesx->idata[segmentx.node2];
+
        if(prevway==segmentx.way)
          {
-          WayX *wayx=LookupWayX(waysx,segmentx.way,1);
+          way_t id=waysx->idata[segmentx.way];
 
-          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" in way %"Pway_t" is duplicated.\n",logerror_node(nodex1->id),logerror_node(nodex2->id),logerror_way(wayx->id));
+          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" in way %"Pway_t" is duplicated.\n",logerror_node(id1),logerror_node(id2),logerror_way(id));
          }
        else
          {
           if(!(prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
-             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated.\n",logerror_node(nodex1->id),logerror_node(nodex2->id));
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated.\n",logerror_node(id1),logerror_node(id2));
 
           if(!(prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
-             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the area).\n",logerror_node(nodex1->id),logerror_node(nodex2->id));
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the area).\n",logerror_node(id1),logerror_node(id2));
 
           if((prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
-             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the non-area).\n",logerror_node(nodex1->id),logerror_node(nodex2->id));
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the non-area).\n",logerror_node(id1),logerror_node(id2));
 
           if((prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
-             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (both are areas).\n",logerror_node(nodex1->id),logerror_node(nodex2->id));
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (both are areas).\n",logerror_node(id1),logerror_node(id2));
          }
 
        duplicate++;
       }
     else
       {
+       NodeX *nodex1=LookupNodeX(nodesx,segmentx.node1,1);
+       NodeX *nodex2=LookupNodeX(nodesx,segmentx.node2,2);
+
        prevnode1=segmentx.node1;
        prevnode2=segmentx.node2;
        prevway=segmentx.way;
@@ -479,10 +494,8 @@ void ProcessSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
 #if !SLIM
  nodesx->data=UnmapFile(nodesx->data);
- waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=SlimUnmapFile(nodesx->fd);
- waysx->fd=SlimUnmapFile(waysx->fd);
 #endif
 
  /* Print the final message */
@@ -518,10 +531,8 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
  /* Allocate the array of indexes */
 
- if(segmentsx->firstnode)
-    free(segmentsx->firstnode);
-
  segmentsx->firstnode=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(segmentsx->firstnode,nodesx->number*sizeof(index_t));
 
  logassert(segmentsx->firstnode,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -596,12 +607,14 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
  if(nodesx->pdata)
    {
+    log_free(nodesx->pdata);
     free(nodesx->pdata);
     nodesx->pdata=NULL;
    }
 
  if(waysx->cdata)
    {
+    log_free(waysx->cdata);
     free(waysx->cdata);
     waysx->cdata=NULL;
    }
@@ -635,6 +648,7 @@ void RemovePrunedSegments(SegmentsX *segmentsx,WaysX *waysx)
  /* Allocate the way usage bitmask */
 
  segmentsx->usedway=AllocBitMask(waysx->number);
+ log_malloc(segmentsx->usedway,LengthBitMask(waysx->number)*sizeof(BitMask));
 
  logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
@@ -997,7 +1011,7 @@ static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2)
 
  a1 = sin (dlat / 2);
  a2 = sin (dlon / 2);
- a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
+ a = a1 * a1 + cos (lat1) * cos (lat2) * a2 * a2;
  sa = sqrt (a);
  if (sa <= 1.0)
    {c = 2 * asin (sa);}
diff --git a/src/sorting.c b/src/sorting.c
index 51ec0bb..7141d60 100644
--- a/src/sorting.c
+++ b/src/sorting.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2009-2013 Andrew M. Bishop
+ This file Copyright 2009-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -121,7 +121,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_funct
  int *fds=NULL,*heap=NULL;
  int nfiles=0,ndata=0;
  index_t count_out=0,count_in=0,total=0;
- size_t nitems=option_filesort_ramsize/(option_filesort_threads*(itemsize+sizeof(void*)));
+ size_t nitems;
  void *data,**datap;
  thread_data *threads;
  size_t item;
@@ -132,6 +132,16 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_funct
 
  /* Allocate the RAM buffer and other bits */
 
+ nitems=SizeFileFD(fd_in)/itemsize;
+
+ if(nitems==0)
+    return(0);
+
+ if((nitems*(itemsize+sizeof(void*)))<option_filesort_ramsize)
+    nitems=1+nitems/option_filesort_threads;
+ else
+    nitems=option_filesort_ramsize/(option_filesort_threads*(itemsize+sizeof(void*)));
+
  threads=(thread_data*)malloc(option_filesort_threads*sizeof(thread_data));
 
  for(i=0;i<option_filesort_threads;i++)
@@ -141,6 +151,9 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_funct
     threads[i].data=malloc(nitems*itemsize);
     threads[i].datap=malloc(nitems*sizeof(void*));
 
+    log_malloc(threads[i].data,nitems*itemsize);
+    log_malloc(threads[i].datap,nitems*sizeof(void*));
+
     threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
 
     threads[i].itemsize=itemsize;
@@ -435,6 +448,9 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_funct
 
  for(i=0;i<option_filesort_threads;i++)
    {
+    log_free(threads[i].data);
+    log_free(threads[i].datap);
+
     free(threads[i].data);
     free(threads[i].datap);
 
@@ -484,7 +500,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_
  int *fds=NULL,*heap=NULL;
  int nfiles=0,ndata=0;
  index_t count_out=0,count_in=0,total=0;
- size_t datasize=option_filesort_ramsize/option_filesort_threads;
+ size_t datasize;
  FILESORT_VARINT nextitemsize,largestitemsize=0;
  void *data,**datap;
  thread_data *threads;
@@ -496,6 +512,16 @@ index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_
 
  /* Allocate the RAM buffer and other bits */
 
+ datasize=SizeFileFD(fd_in);
+
+ if(datasize==0)
+    return(0);
+
+ if((datasize*2)<option_filesort_ramsize) /* estimate that data and pointer are same size */
+    datasize=(datasize*2)/option_filesort_threads;
+ else
+    datasize=option_filesort_ramsize/option_filesort_threads;
+
  threads=(thread_data*)malloc(option_filesort_threads*sizeof(thread_data));
 
  for(i=0;i<option_filesort_threads;i++)
@@ -505,6 +531,8 @@ index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_
     threads[i].data=malloc(datasize);
     threads[i].datap=NULL;
 
+    log_malloc(threads[i].data,datasize);
+
     threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
 
     threads[i].compare=compare_function;
@@ -838,6 +866,8 @@ index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_
 
  for(i=0;i<option_filesort_threads;i++)
    {
+    log_free(threads[i].data);
+
     free(threads[i].data);
 
     free(threads[i].filename);
diff --git a/src/superx.c b/src/superx.c
index 3a7bc77..c8e504e 100644
--- a/src/superx.c
+++ b/src/superx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -69,6 +69,7 @@ void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  if(!nodesx->super)
    {
     nodesx->super=AllocBitMask(nodesx->number);
+    log_malloc(nodesx->super,LengthBitMask(nodesx->number)*sizeof(BitMask));
 
     logassert(nodesx->super,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
@@ -327,6 +328,15 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  waysx->fd=SlimUnmapFile(waysx->fd);
 #endif
 
+ /* Free the no-longer required memory */
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+    segmentsx->firstnode=NULL;
+   }
+
  /* Print the final message */
 
  printf_last("Created Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
diff --git a/src/typesx.h b/src/typesx.h
index b1b1204..2aad40f 100644
--- a/src/typesx.h
+++ b/src/typesx.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2012 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -49,7 +49,9 @@
 
 #define BitMask uint32_t
 
-#define AllocBitMask(xx)    (BitMask*)calloc((1+(xx)/32),sizeof(BitMask))
+#define LengthBitMask(xx)   (1+(xx)/32)
+
+#define AllocBitMask(xx)    (BitMask*)calloc(LengthBitMask(xx),sizeof(BitMask))
 
 #define ClearAllBits(xx,yy) memset((xx), 0,(1+(yy)/32)*sizeof(BitMask))
 #define SetAllBits(xx,yy)   memset((xx),~0,(1+(yy)/32)*sizeof(BitMask))
diff --git a/src/visualiser.c b/src/visualiser.c
index d07b56b..4062074 100644
--- a/src/visualiser.c
+++ b/src/visualiser.c
@@ -83,7 +83,7 @@ static void output_property(index_t node,double latitude,double longitude);
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for junctions.
+  Output the data for junctions (--data=junctions).
 
   Nodes *nodes The set of nodes to use.
 
@@ -123,7 +123,7 @@ void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relat
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node as a junction (called as a callback).
+  Process a single node and output all those that are junctions (called as a callback).
 
   index_t node The node to output.
 
@@ -162,7 +162,7 @@ static void output_junctions(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for super-nodes and super-segments.
+  Output the data for super-nodes and super-segments (--data=super).
 
   Nodes *nodes The set of nodes to use.
 
@@ -202,7 +202,7 @@ void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node as a super-node (called as a callback).
+  Process a single node and output all that are super-nodes and all connected super-segments (called as a callback).
 
   index_t node The node to output.
 
@@ -243,7 +243,7 @@ static void output_super(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for one-way segments.
+  Output the data for segments of special highway types (--data=waytype-oneway etc).
 
   Nodes *nodes The set of nodes to use.
 
@@ -287,7 +287,7 @@ void OutputWaytype(Nodes *nodes,Segments *segments,Ways *ways,Relations *relatio
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node and all connected way-type segments (called as a callback).
+  Process a single node and output all connected segments of a particular special highway type (called as a callback).
 
   index_t node The node to output.
 
@@ -333,7 +333,7 @@ static void output_waytype(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for segments of a particular highway type.
+  Output the data for segments of a particular highway type (--data=highway-primary etc).
 
   Nodes *nodes The set of nodes to use.
 
@@ -377,7 +377,7 @@ void OutputHighway(Nodes *nodes,Segments *segments,Ways *ways,Relations *relatio
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node and all connected one-way segments (called as a callback).
+  Process a single node and output all connected segments that are of a particular highway type (called as a callback).
 
   index_t node The node to output.
 
@@ -418,7 +418,7 @@ static void output_highway(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for segments allowed for a particular type of traffic.
+  Output the data for segments allowed for a particular type of traffic (--data=transport-motorcar etc).
 
   Nodes *nodes The set of nodes to use.
 
@@ -462,7 +462,7 @@ void OutputTransport(Nodes *nodes,Segments *segments,Ways *ways,Relations *relat
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node and all connected one-way segments (called as a callback).
+  Process a single node and output all connected segments for a particular traffic type (called as a callback).
 
   index_t node The node to output.
 
@@ -503,7 +503,7 @@ static void output_transport(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for nodes disallowed for a particular type of traffic.
+  Output the data for nodes disallowed for a particular type of traffic (--data=barrier).
 
   Nodes *nodes The set of nodes to use.
 
@@ -547,7 +547,7 @@ void OutputBarrier(Nodes *nodes,Segments *segments,Ways *ways,Relations *relatio
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node (called as a callback).
+  Process a single node and output those that are barriers (called as a callback).
 
   index_t node The node to output.
 
@@ -566,7 +566,7 @@ static void output_barrier(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for turn restrictions.
+  Output the data for turn restrictions (--data=turns).
 
   Nodes *nodes The set of nodes to use.
 
@@ -606,7 +606,7 @@ void OutputTurnRestrictions(Nodes *nodes,Segments *segments,Ways *ways,Relations
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node as the 'via' node for a turn restriction (called as a callback).
+  Process a single node and output those that are 'via' nodes for a turn restriction and the associated segments (called as a callback).
 
   index_t node The node to output.
 
@@ -656,7 +656,7 @@ static void output_turnrestriction(index_t node,double latitude,double longitude
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for speed limits.
+  Output the data for speed limits (--data=speed).
 
   Nodes *nodes The set of nodes to use.
 
@@ -698,7 +698,7 @@ void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *rel
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for weight limits.
+  Output the data for weight limits (--data=weight).
 
   Nodes *nodes The set of nodes to use.
 
@@ -740,7 +740,7 @@ void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *re
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for height limits.
+  Output the data for height limits (--data=height).
 
   Nodes *nodes The set of nodes to use.
 
@@ -782,7 +782,7 @@ void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *re
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for width limits.
+  Output the data for width limits (--data=width).
 
   Nodes *nodes The set of nodes to use.
 
@@ -824,7 +824,7 @@ void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *rel
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for length limits.
+  Output the data for length limits (--data=length).
 
   Nodes *nodes The set of nodes to use.
 
@@ -866,7 +866,7 @@ void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *re
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node as a speed, weight, height, length, width limit (called as a callback).
+  Process a single node and output those and connected segments that have a speed, weight, height, width or length limit change (called as a callback).
 
   index_t node The node to output.
 
@@ -968,7 +968,7 @@ static void output_limits(index_t node,double latitude,double longitude)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for segments that have a particular property.
+  Output the data for segments that have a particular property (--data=property-paved etc).
 
   Nodes *nodes The set of nodes to use.
 
@@ -1012,7 +1012,7 @@ void OutputProperty(Nodes *nodes,Segments *segments,Ways *ways,Relations *relati
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Process a single node and all connected one-way segments (called as a callback).
+  Process a single node and output all connected segments with a particular property (called as a callback).
 
   index_t node The node to output.
 
@@ -1103,7 +1103,7 @@ static void find_all_nodes(Nodes *nodes,callback_t callback)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Output the data for error logs within the region.
+  Output the data for error logs within the region (--data=errorlogs).
 
   ErrorLogs *errorlogs The set of error logs to use.
 
diff --git a/src/ways.c b/src/ways.c
index 60cb08d..b265a98 100644
--- a/src/ways.c
+++ b/src/ways.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -24,7 +24,6 @@
 
 #include "ways.h"
 
-#include "cache.h"
 #include "files.h"
 
 
@@ -66,6 +65,7 @@ Ways *LoadWayList(const char *filename)
  ways->namesoffset=sizeof(WaysFile)+ways->file.number*sizeof(Way);
 
  ways->cache=NewWayCache();
+ log_malloc(ways->cache,sizeof(*ways->cache));
 
 #endif
 
@@ -89,6 +89,7 @@ void DestroyWayList(Ways *ways)
 
  ways->fd=SlimUnmapFile(ways->fd);
 
+ log_free(ways->cache);
  DeleteWayCache(ways->cache);
 
 #endif
diff --git a/src/waysx.c b/src/waysx.c
index d7d737d..89485dc 100644
--- a/src/waysx.c
+++ b/src/waysx.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -112,6 +112,7 @@ WaysX *NewWayList(int append,int readonly)
 
 #if SLIM
  waysx->cache=NewWayXCache();
+ log_malloc(waysx->cache,sizeof(*waysx->cache));
 #endif
 
 
@@ -142,19 +143,29 @@ void FreeWayList(WaysX *waysx,int keep)
  free(waysx->filename_tmp);
 
  if(waysx->idata)
+   {
+    log_free(waysx->idata);
     free(waysx->idata);
+   }
 
  if(waysx->odata)
+   {
+    log_free(waysx->odata);
     free(waysx->odata);
+   }
 
  if(waysx->cdata)
+   {
+    log_free(waysx->cdata);
     free(waysx->cdata);
+   }
 
  DeleteFile(waysx->nfilename_tmp);
 
  free(waysx->nfilename_tmp);
 
 #if SLIM
+ log_free(waysx->cache);
  DeleteWayXCache(waysx->cache);
 #endif
 
@@ -301,6 +312,7 @@ void SortWayList(WaysX *waysx)
  /* Allocate the array of indexes */
 
  waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
+ log_malloc(waysx->idata,waysx->number*sizeof(way_t));
 
  logassert(waysx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -443,11 +455,11 @@ SegmentsX *SplitWays(WaysX *waysx,NodesX *nodesx,int keep)
 
        if(prevnode==node)
          {
-          logerror("Way %"Pway_t" contains node %"Pnode_t" that is connected to itself.\n",logerror_way(wayx.id),logerror_node(node));
+          logerror("Way %"Pway_t" contains node %"Pnode_t" that is connected to itself.\n",logerror_way(waysx->idata[i]),logerror_node(node));
          }
        else if(index==NO_NODE)
          {
-          logerror("Way %"Pway_t" contains node %"Pnode_t" that does not exist in the Routino database.\n",logerror_way(wayx.id),logerror_node(node));
+          logerror("Way %"Pway_t" contains node %"Pnode_t" that does not exist in the Routino database.\n",logerror_way(waysx->idata[i]),logerror_node(node));
          }
        else if(previndex==NO_NODE)
           ;
@@ -680,6 +692,7 @@ void CompactWayList(WaysX *waysx,SegmentsX *segmentsx)
  /* Allocate the array of indexes */
 
  waysx->cdata=(index_t*)malloc(waysx->number*sizeof(index_t));
+ log_malloc(waysx->cdata,waysx->number*sizeof(index_t));
 
  logassert(waysx->cdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
@@ -707,6 +720,7 @@ void CompactWayList(WaysX *waysx,SegmentsX *segmentsx)
 
  /* Free the data */
 
+ log_free(segmentsx->usedway);
  free(segmentsx->usedway);
  segmentsx->usedway=NULL;
 
diff --git a/src/waysx.h b/src/waysx.h
index 0a75f8d..24cab2a 100644
--- a/src/waysx.h
+++ b/src/waysx.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2013 Andrew M. Bishop
+ This file Copyright 2008-2014 Andrew M. Bishop
 
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
@@ -26,9 +26,9 @@
 #include <stdint.h>
 
 #include "types.h"
+#include "ways.h"
 
 #include "typesx.h"
-#include "ways.h"
 
 #include "cache.h"
 #include "files.h"
diff --git a/web/translations/translation.de.txt b/web/translations/translation.de.txt
index 6278a28..372844e 100644
--- a/web/translations/translation.de.txt
+++ b/web/translations/translation.de.txt
@@ -7,7 +7,7 @@
 #
 
 %%copyright_creator_string%%	Urheber
-%%copyright_source_string%%	Source
+%%copyright_source_string%%	Quelle
 %%copyright_source_text%%	Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/
 %%copyright_license_string%%	Lizenz
 
@@ -127,6 +127,7 @@
 @@VISUALISER-BOX@@	Routino Ansichten
 
 @@WAYPOINT-SEARCH@@	Nach Ort suchen
+@@WAYPOINT-GET@@	Aktuellen Ort bestimmen
 @@WAYPOINT-CENTRE1@@	Karte auf Wegpunkt zentrieren
 @@WAYPOINT-UP@@	wegpunkt nach oben verschieben
 @@WAYPOINT-ADD@@	Neuer Wegpunkt nach diesem
diff --git a/web/www/routino/router.html.de b/web/www/routino/router.html.de
index 7288988..c23086d 100644
--- a/web/www/routino/router.html.de
+++ b/web/www/routino/router.html.de
@@ -129,7 +129,7 @@ Wähle Start- und Endpunkt (klicke auf die Marker-Symbole unten), wähle die Rou
 </span>
 <td>
 <img alt="?" src="icons/waypoint-search.png" title="Nach Ort suchen" onmousedown="markerSearch(XXX);" >
-<img alt="G" src="icons/waypoint-locate.png" title="Get current location" onmousedown="markerLocate(XXX);" >
+<img alt="G" src="icons/waypoint-locate.png" title="Aktuellen Ort bestimmen" onmousedown="markerLocate(XXX);" >
 <img alt="O" src="icons/waypoint-recentre.png" title="Karte auf Wegpunkt zentrieren" onmousedown="markerRecentre(XXX);">
 <img alt="^" src="icons/waypoint-up.png" title="wegpunkt nach oben verschieben" onmousedown="markerMoveUp(XXX);" >
 <img alt="+" src="icons/waypoint-add.png" title="Neuer Wegpunkt nach diesem" onmousedown="markerAddAfter(XXX);">
diff --git a/xml/routino-translations.xml b/xml/routino-translations.xml
index 7b75298..b280e6c 100644
--- a/xml/routino-translations.xml
+++ b/xml/routino-translations.xml
@@ -114,7 +114,7 @@
     <!-- Copyright of the data being routed, not of this file  -->
     <copyright>
       <creator string="Urheber" text="Routino - http://www.routino.org/" />
-      <source  string="Source" text="Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/" />
+      <source  string="Quelle" text="Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/" />
       <license string="Lizenz" text="http://www.openstreetmap.org/copyright" />
     </copyright>
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/routino.git



More information about the Pkg-grass-devel mailing list