[routino] 01/13: Imported Upstream version 2.4.1

Uwe Steinmann steinm-guest at moszumanska.debian.org
Thu Apr 17 11:40:01 UTC 2014


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

steinm-guest pushed a commit to branch master
in repository routino.

commit fc6d7dd568613ee714d0ce7baa01008e9359e339
Author: Uwe Steinmann <steinm at debian.org>
Date:   Fri Dec 21 21:34:25 2012 +0100

    Imported Upstream version 2.4.1
---
 ChangeLog                                          |  619 ++++++++++++
 doc/ALGORITHM.txt                                  |   25 +-
 doc/DATALIFE.txt                                   |   88 ++
 doc/NEWS.txt                                       |   50 +
 doc/README.txt                                     |    2 +
 doc/TAGGING.txt                                    |   25 +-
 doc/USAGE.txt                                      |  132 ++-
 doc/html/algorithm.html                            |   24 +-
 doc/html/readme.html                               |  113 +--
 doc/html/tagging.html                              |   34 +-
 doc/html/usage.html                                |  126 ++-
 src/Makefile                                       |   10 +-
 src/fakes.c                                        |   42 +-
 src/fakes.h                                        |    6 +-
 src/filedumper.c                                   |  231 +++--
 src/filedumperx.c                                  |  397 ++++++++
 src/files.c                                        |   32 +-
 src/files.h                                        |   19 +-
 src/logging.c                                      |   28 +-
 src/logging.h                                      |    7 +
 src/nodes.c                                        |   70 +-
 src/nodes.h                                        |    2 +-
 src/nodesx.c                                       |  572 ++++++-----
 src/nodesx.h                                       |   30 +-
 src/optimiser.c                                    |  244 +++--
 src/osmparser.c                                    |  342 ++++++-
 src/osmparser.h                                    |    4 +-
 src/output.c                                       |   86 +-
 src/planetsplitter.c                               |  164 +--
 src/profiles.c                                     |   40 +-
 src/profiles.h                                     |    4 +-
 src/prunex.c                                       |  446 +++++----
 src/relationsx.c                                   |  636 +++++++-----
 src/relationsx.h                                   |   44 +-
 src/results.c                                      |    5 +-
 src/router.c                                       |    8 +-
 src/segments.c                                     |   62 +-
 src/segments.h                                     |   52 +-
 src/segmentsx.c                                    | 1040 ++++++++++++--------
 src/segmentsx.h                                    |   50 +-
 src/sorting.c                                      |  129 ++-
 src/sorting.h                                      |   20 +-
 src/superx.c                                       |   97 +-
 src/tagging.c                                      |   21 +-
 src/tagmodifier.c                                  |    8 +-
 src/translations.c                                 |    6 +-
 src/translations.h                                 |    4 +-
 src/types.c                                        |   81 +-
 src/types.h                                        |  114 ++-
 src/typesx.h                                       |   21 +-
 src/visualiser.c                                   |  124 +--
 src/ways.c                                         |   42 +-
 src/ways.h                                         |   17 +-
 src/waysx.c                                        |  609 +++++++-----
 src/waysx.h                                        |   34 +-
 .../{bad-cdata-start.xml => bad-text-outside.xml}  |    4 +-
 src/xml/test/good.xml                              |    1 -
 src/xmlparse.l                                     |   77 +-
 web/bin/summarise-log.pl                           |  216 +++-
 web/www/routino/customrouter.cgi                   |   48 -
 web/www/routino/customvisualiser.cgi               |   48 -
 web/www/routino/noscript.cgi                       |  197 ----
 web/www/routino/noscript.html                      |   70 --
 web/www/routino/noscript.template.html             |  438 ---------
 xml/{routino-osm.xsd => osc.xsd}                   |   74 +-
 xml/osm.xsd                                        |    7 +-
 xml/{routino-osm.xsd => routino-osc.xsd}           |   63 +-
 xml/routino-osm.xsd                                |    2 +-
 xml/routino-tagging.xml                            |  194 +++-
 69 files changed, 5305 insertions(+), 3372 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index af348d4..bc9d4f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,622 @@
+2012-12-17  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	Version 2.4.1 released
+
+2012-12-17 [r1214]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/html/readme.html, doc/NEWS.txt, doc/README.txt, FILES: Update
+	  for version 2.4.1.
+
+2012-12-17 [r1213]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/optimiser.c, src/waysx.c, src/segmentsx.c, src/nodesx.c,
+	  src/router.c, src/prunex.c, src/logging.c, src/relationsx.c:
+	  Merge revisions 1191, 1193, 1198, 1208 and 1210 from trunk into
+	  2.4.1 branch.
+
+2012-12-17 [r1210]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/optimiser.c: Fix the incorrect finish_score variable that was
+	  set to infinite distance and not infinite score (infinte distance
+	  << infinite score so search was terminating early).
+
+2012-12-15 [r1208]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c, src/prunex.c, src/relationsx.c, src/waysx.c,
+	  src/segmentsx.c: Stop planetsplitter crashing out in unusual ways
+	  if there is no data.
+
+2012-12-14 [r1198]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c, src/nodesx.c: Don't crash in binary search if no
+	  nodes/ways.
+
+2012-12-13 [r1193]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/logging.c: Fix bug with printing messages if not to stdout.
+
+2012-12-12 [r1191]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/router.c: Fix error when searching for default profiles.xml
+	  file.
+
+2012-12-08  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	Version 2.4 released
+
+2012-12-08 [r1182-1183]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/NEWS.txt, doc/README.txt, FILES, doc/html/readme.html: Update
+	  for version 2.4.
+
+	* doc/TAGGING.txt: Update with the tagging rule changes in this
+	  version.
+
+2012-12-08 [r1181]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/xmlparse.l, src/xml/test/good.xml,
+	  src/xml/test/bad-cdata-start.xml (removed),
+	  src/xml/test/bad-text-outside.xml (added): Simplify the XML
+	  parser by not handling the CDATA and DOCTYPE sections and also
+	  raise an explicit error for text outside of tags. Modify test
+	  cases for these changes.
+
+2012-12-06 [r1180]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/xmlparse.l: Some further small changes to pull out bigger
+	  groups of characters (only marginally faster though).
+
+2012-12-05 [r1179]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/prunex.c: Minor theoretical improvements to pruning (slim
+	  mode is still very slow).
+
+2012-12-05 [r1178]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/xmlparse.l: Change rules to remove all states that require
+	  backing up (only marginally faster though).
+
+2012-12-05 [r1176-1177]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/html/tagging.html: Update with the tagging rule changes in
+	  this version.
+
+	* xml/routino-tagging.xml: Small change to the tag processing for
+	  nodes for easier future expansion.
+
+2012-12-01 [r1175]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/tagging.c: Fix memory leak from making incorrect assumption
+	  when freeing tagging rule.
+
+2012-12-01 [r1174]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/superx.c, src/translations.h, src/visualiser.c,
+	  src/profiles.h, src/types.h, src/osmparser.c, src/filedumper.c,
+	  src/output.c, src/router.c, src/translations.c, src/profiles.c,
+	  src/types.c: Rename the Way_* enumerated values to Highway_*, add
+	  a new Highway_None type, change the HighwayType() function to
+	  return Highway_None instead of Highway_Count if no match found -
+	  all changes for consistency with similar types and functions.
+
+2012-11-27 [r1173]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/osmparser.c, web/bin/summarise-log.pl, src/segmentsx.c: Log
+	  an error about duplicated segments within a way while parsing the
+	  OSM instead of later (will have been removed by de-duplication
+	  code before tested later in most cases).
+
+2012-11-27 [r1172]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* web/bin/summarise-log.pl: Make the script still work when no
+	  command line argument is used.
+
+2012-11-27 [r1171]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/relationsx.c, src/planetsplitter.c, src/waysx.c,
+	  src/segmentsx.c, src/nodesx.c: Don't log an error for duplicated
+	  nodes, ways or relations because it can only occur when applying
+	  changes or if using multiple geographically overlapping files and
+	  neither is a data error.
+
+2012-11-21 [r1170]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* xml/routino-tagging.xml: Add some more tag checking, accept more
+	  tags.
+
+2012-11-21 [r1169]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/types.h, src/segmentsx.c: Finally fix the segment area
+	  handling - segments that are areas are discarded in preference to
+	  those that are not (as it was between r914 and r1136) and
+	  segments that are areas don't have the wrong distance (as they
+	  did between r914 and r1136). Revision r1137 correctly changed to
+	  use a flag and fixed the distance bug but then didn't sort using
+	  the new flag. Revision r1153 started sorting using the segment
+	  flags but the area was not the most significant bit so they were
+	  not sorted last. Revision r1164 correctly cleared the area flag
+	  when no longer needed but didn't fix the rest. Revision r1168
+	  reverted r1164 so needed to be re-applied.
+
+2012-11-21 [r1168]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/prunex.c, src/segmentsx.h, src/filedumperx.c, src/segments.c,
+	  src/superx.c, src/fakes.c, src/types.h, src/segments.h,
+	  src/optimiser.c, src/osmparser.c, src/filedumper.c,
+	  src/segmentsx.c, src/fakes.h, src/output.c: Revert r1164 - some
+	  super-segments are longer than 65535 metres even if no individual
+	  segment is.
+
+2012-11-20 [r1167]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/html/usage.html, src/relationsx.c, src/planetsplitter.c,
+	  src/waysx.c, src/relationsx.h, src/segmentsx.c, doc/USAGE.txt,
+	  src/nodesx.c, src/waysx.h, src/segmentsx.h, src/nodesx.h: Rename
+	  the '--preserve' command line option to '--keep' for simplicity.
+
+2012-11-20 [r1166]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c, src/nodesx.c, src/prunex.c, src/results.c,
+	  src/sorting.c, src/logging.c, src/superx.c, src/files.h,
+	  src/relationsx.c, src/tagmodifier.c, src/logging.h,
+	  src/optimiser.c, src/osmparser.c, src/waysx.c, src/Makefile:
+	  Replace all assert statements with a custom error message that
+	  explains the cause and suggests a solution.
+
+2012-11-20 [r1165]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/types.h, src/osmparser.c, src/nodes.h, src/nodesx.c,
+	  src/nodesx.h: Use a specific type for the node flags instead of a
+	  generic uint16_t.
+
+2012-11-20 [r1164]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/filedumperx.c, src/segments.c, src/superx.c, src/fakes.c,
+	  src/types.h, src/segments.h, src/optimiser.c, src/osmparser.c,
+	  src/filedumper.c, src/segmentsx.c, src/fakes.h, src/output.c,
+	  src/prunex.c, src/segmentsx.h: Replace the 32-bit combined
+	  distance and flags in the segment with 16 bits for each.
+
+2012-11-20 [r1163]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/relationsx.c, src/relationsx.h, src/typesx.h,
+	  src/filedumperx.c: Tidy up all of the recent code changes -
+	  Rename TurnRestrictRelX structure to TurnRelX.
+
+2012-11-20 [r1162]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/files.c: Tidy up all of the recent code changes - Fix
+	  comment.
+
+2012-11-20 [r1161]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c, src/waysx.h, src/segmentsx.h, doc/DATALIFE.txt,
+	  src/nodesx.h, src/superx.c, src/relationsx.c, src/osmparser.c,
+	  src/waysx.c, src/relationsx.h, src/segmentsx.c: Tidy up all of
+	  the recent code changes - change the name of a few of the
+	  functions.
+
+2012-11-20 [r1160]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c, src/relationsx.h, src/segmentsx.c, src/nodesx.c,
+	  src/waysx.h, src/segmentsx.h, src/nodesx.h: Tidy up all of the
+	  recent code changes - change the order of the functions within
+	  the files to a more sensible and consitent order.
+
+2012-11-19 [r1159]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/osmparser.c: Unconditionally mark ways as deleted if they
+	  have been modified to handle the case when applying more than one
+	  change file if a way is created by the first of the change files
+	  and modified by the second it will not be in the index.
+
+2012-11-19 [r1158]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c, src/waysx.h, src/planetsplitter.c: Do not create the
+	  way indexes when loading the parsed ways to apply changes
+	  (reverses r1145).
+
+2012-11-19 [r1157]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/html/usage.html, src/planetsplitter.c, doc/USAGE.txt: Do not
+	  require that --preserve must be used with --parse-only before
+	  changes can be applied (reverses r1151 for the change to
+	  functionality but preserves the changes to the functions that
+	  enable it).
+
+2012-11-19 [r1156]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/filedumperx.c: Fix bug with dumping ways.
+
+2012-11-19 [r1155]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c: De-duplicate segments when sorting only if they
+	  have the same nodes, way and distance - i.e. the same data
+	  imported twice.
+
+2012-11-18 [r1154]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/osmparser.c: When marking modified nodes as deleted don't
+	  accidentally re-include them as new ways with the deleted flag
+	  set.
+
+2012-11-18 [r1152-1153]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c: When sorting segments use the distance flags as
+	  the tie-breaker so that duplicated segments with different flags
+	  get sorted into the same order when applying changes as when not
+	  applying changes.
+
+	* src/osmparser.c: Mark modified relations as deleted before
+	  storing the modification to handle the case where the
+	  modification causes it to be invalid and not stored therefore
+	  leaving the old version.
+
+2012-11-18 [r1151]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.h, src/nodesx.h, src/superx.c, doc/html/usage.html,
+	  src/relationsx.c, src/planetsplitter.c, src/waysx.c,
+	  src/relationsx.h, src/segmentsx.c, doc/USAGE.txt, src/nodesx.c,
+	  src/waysx.h: Using --parse-only and --preserve must sort the data
+	  so that it is ready to apply the changes.
+
+2012-11-17 [r1149-1150]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/filedumper.c: Some small changes to match the new filedumperx
+	  program.
+
+	* src, doc/USAGE.txt, src/filedumperx.c (added),
+	  doc/html/usage.html, src/Makefile, web/bin: Add a new program to
+	  dump the contents of the intermediate files that are generated by
+	  using --preserve or --changes.
+
+2012-11-17 [r1147-1148]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c: Replace a hard-coded constant with the #defined
+	  value it should have been.
+
+	* src/relationsx.c: Clear the route relation before adding data to
+	  it so that there are no unused bytes in the structure to get
+	  written to disk (avoid byte-level differences when applying
+	  changes).
+
+2012-11-17 [r1146]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c, src/relationsx.c, src/planetsplitter.c,
+	  src/waysx.c, src/segmentsx.c: Suppress some error log messages
+	  when applying changes (false positive duplicate detection due to
+	  modification of existing items).
+
+2012-11-17 [r1144-1145]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/osmparser.c, src/waysx.c, src/waysx.h:
+	  Fix applying changes for ways (highways that have been modified
+	  to be non-highways were not added to the database so the original
+	  remains).
+
+	* src/typesx.h, src/types.h: Change the type-casting of some
+	  constants.
+
+2012-11-16 [r1140-1143]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/xml: Ignore the automatically generated executables from the
+	  new XML Schema.
+
+	* xml/routino-osm.xsd, xml/osm.xsd: Changes to comments to make
+	  them more like the OSC files.
+
+	* xml/routino-osc.xsd (added), xml/osc.xsd (added): XML Schema for
+	  OSC change files (.osc files) used to create the XML parser.
+
+	* doc/html/usage.html, src/relationsx.c, src/types.h,
+	  src/planetsplitter.c, src/osmparser.c, src/waysx.c,
+	  src/segmentsx.c, doc/USAGE.txt, src/nodesx.c, src/osmparser.h,
+	  src/segmentsx.h, doc/DATALIFE.txt: Code to allow adding OSC
+	  change files (.osc files) to an existing set of parsed (and
+	  preserved) data.
+
+2012-11-15 [r1139]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.h, src/superx.c, src/relationsx.c,
+	  src/planetsplitter.c, src/waysx.c, src/relationsx.h,
+	  src/segmentsx.c, src/nodesx.c, src/waysx.h, src/segmentsx.h:
+	  Fixed the --preserve option.
+
+2012-11-12 [r1138]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/relationsx.c: Fix mis-use of NO_WAY/NO_WAY_ID and
+	  NO_RELATION/NO_RELATION_ID constants in route relation handling.
+
+2012-11-11 [r1137]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/types.h, src/osmparser.c, src/segmentsx.c: Mark those
+	  segments that come from ways which are areas with an explicit
+	  flag rather than an implicit one (also fixes a bug).
+
+2012-11-10 [r1136]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c, src/waysx.h, src/segmentsx.h, src/nodesx.h,
+	  doc/html/usage.html, src/relationsx.c, src/planetsplitter.c,
+	  src/waysx.c, src/relationsx.h, src/segmentsx.c, doc/USAGE.txt:
+	  Added a --preserve option which keeps the raw data files after
+	  parsing, sorting and de-duplication.
+
+2012-11-10 [r1134-1135]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/DATALIFE.txt, src/waysx.c: Don't index the ways in the first
+	  sorting, but wait until after de-duplicating.
+
+	* src/relationsx.c: Sort the route relations and remove duplicates.
+
+2012-11-10 [r1133]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h,
+	  doc/DATALIFE.txt: The MergeSuperSegments function creates the
+	  output file in the sorted order already, there is no need to
+	  re-sort it.
+
+2012-11-10 [r1132]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c, src/segmentsx.h, doc/DATALIFE.txt,
+	  src/planetsplitter.c: De-duplicate the super-segments as a
+	  post-processing function after the sort so both operations are
+	  combined in a single function.
+
+2012-11-10 [r1131]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.h, src/planetsplitter.c, src/segmentsx.c:
+	  De-duplicate the raw segments before any other processing (to
+	  match the node, way and turn relation processing).
+
+2012-11-10 [r1129-1130]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c: Separate the de-duplication of the ways
+	  from the extracting of the names. Use the modified functions for
+	  creating lists of nodes,segments,ways and relations from r1123.
+
+	* src/waysx.c, src/waysx.h, doc/DATALIFE.txt: Separate the
+	  de-duplication of the ways from the extracting of the names.
+
+2012-11-08 [r1128]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* web/bin/summarise-log.pl: Allow generation of an HTML version of
+	  the log file summary.
+
+2012-11-08 [r1127]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/osmparser.c: Add two extra parsing rules for feet and inches.
+
+2012-11-04 [r1126]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/tagging.c: Clarify that errors logged when examining tags
+	  mean that tag will be ignored.
+
+2012-11-04 [r1125]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/osmparser.c: Log an error for ways with only 1 node and for
+	  relations with no nodes, ways or relations.
+
+2012-11-03 [r1124]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/prunex.c: Append the new ways directly to the end of the
+	  existing ways rather than using a new file.
+
+2012-11-03 [r1123]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.h, src/superx.c, src/relationsx.c, src/waysx.c,
+	  src/relationsx.h, src/segmentsx.c, src/nodesx.c, src/waysx.h,
+	  src/segmentsx.h: Don't open the input file for appending if there
+	  is no intention to write anything to it.
+
+2012-11-03 [r1122]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/superx.c, src/files.h, src/relationsx.c, src/segmentsx.c,
+	  src/prunex.c, src/files.c: Change the UnmapFile() function to
+	  take a pointer to the data instead of the filename (like the
+	  CloseFile() function takes the file descriptor).
+
+2012-11-02 [r1121]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/prunex.c, src/segmentsx.h: Fix a bug which gave different
+	  results for slim mode and normal mode when pruning short
+	  segments.
+
+2012-11-01 [r1120]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/waysx.c, src/relationsx.h,
+	  src/segmentsx.c, doc/USAGE.txt, src/nodesx.c, src/waysx.h,
+	  src/prunex.c, src/segmentsx.h, src/nodesx.h, src/superx.c,
+	  doc/html/usage.html, src/relationsx.c: Introduce a new'--append'
+	  option for appending data from a file to the currently parsed
+	  data. Rename the intermediate file used for storing data to be
+	  appended to. Add a function to call after appending to a file
+	  which closes the file and renames it to a temporary filename
+	  which is used for the remaining processing.
+
+2012-11-01 [r1119]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/files.c, src/files.h: Add a function to rename a file.
+
+2012-10-31 [r1118]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/relationsx.c, src/sorting.h, src/waysx.c, src/segmentsx.c,
+	  src/nodesx.c: Add the option for the sorting function to preserve
+	  the input order of equivalent items on the output. Use this
+	  feature in sorting so that slim mode and normal mode give the
+	  same results.
+
+2012-10-24 [r1116-1117]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/html/usage.html, doc/html/algorithm.html,
+	  src/planetsplitter.c, doc/USAGE.txt, doc/ALGORITHM.txt,
+	  src/prunex.c: Perform the pruning for isolated regions in terms
+	  of each transport type individually.
+
+	* doc/DATALIFE.txt: Use the index provided by the pre-sort function
+	  rather than the way's internal id when pruning/compacting.
+
+2012-10-24 [r1114-1115]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c: Remove a debugging print statement.
+
+	* src/waysx.c: Use the index provided by the pre-sort function
+	  rather than the way's internal id when pruning/compacting.
+
+2012-10-22 [r1112-1113]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c: Use the new pre-sort function to allow CompactWays()
+	  to delete the unused segments before sorting them.
+
+	* src/segmentsx.c, src/sorting.c, src/relationsx.c: Fix bug with
+	  index parameter in new pre-sort function and change comments to
+	  clarify.
+
+2012-10-22 [r1110-1111]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c: Use the new pre-sort function to allow
+	  RemovePrunedSegments() to delete the pruned segments before
+	  sorting them.
+
+	* src/segmentsx.c, src/relationsx.c: Change the message after
+	  sorting geographically to be consistent with others.
+
+2012-10-21 [r1109]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/nodesx.c, doc/DATALIFE.txt,
+	  src/nodesx.h: Move the UpdateNodes() work into the callback for
+	  SortNodeListGeographically() and use firstnode when saving the
+	  nodes.
+
+2012-10-21 [r1108]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/relationsx.h, doc/DATALIFE.txt,
+	  src/relationsx.c: Use the new pre-sort function to allow
+	  UpdateTurnRelations() and SortTurnRelationList() to be combined
+	  into a single SortTurnRelationListGeographically() function that
+	  only reads and writes the data once instead of twice.
+
+2012-10-21 [r1107]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.h, doc/DATALIFE.txt, src/planetsplitter.c,
+	  src/segmentsx.c: Use the new pre-sort function to allow
+	  UpdateSegments() and SortSegmentList() to be combined into a
+	  single SortSegmentListGeographically() function that only reads
+	  and writes the data once instead of twice.
+
+2012-10-21 [r1106]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c, src/sorting.c, src/relationsx.c, src/sorting.h,
+	  src/waysx.c, src/segmentsx.c: Change the sorting functions to
+	  have a pre-sort and post-sort selection function instead of just
+	  a post-selection one (this will allow deletion of some items
+	  before sorting instead of after sorting in some cases).
+
+2012-10-21 [r1103-1105]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/DATALIFE.txt: Added new columns showing when the data files
+	  are mapped into memory.
+
+	* src/waysx.c: Delete the onumber parameter from the Ways file
+	  header. Don't map the ways file into memory when writing the
+	  ways.
+
+	* src/ways.h, src/filedumper.c: Delete the onumber parameter from
+	  the Ways file header.
+
+2012-10-21 [r1102]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/segmentsx.c: Reallocate the firstnode array when indexing
+	  segments because there may be fewer nodes now.
+
+2012-10-21 [r1101]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c: Remove some unused parts of the
+	  SortNodeListGeographically() function.
+
+2012-10-20 [r1100]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/DATALIFE.txt, src/relationsx.c, src/planetsplitter.c,
+	  src/waysx.c, src/segmentsx.c, src/waysx.h, src/segmentsx.h: Move
+	  the compacting of the ways back to the top, delete the unused
+	  ways at this point and also call the function again after pruning
+	  segments.
+
+2012-10-20 [r1099]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c: Mark pruned nodes in the node index.
+
+2012-10-20 [r1098]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/relationsx.c, src/planetsplitter.c, src/relationsx.h,
+	  src/segmentsx.c, src/nodesx.c, src/prunex.c, doc/DATALIFE.txt,
+	  src/nodesx.h, src/superx.c: Delete the pruned nodes before
+	  searching for super-nodes etc.
+
+2012-10-20 [r1097]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/nodesx.c: Move the calculation of lat/long extents to the
+	  UpdateNodes() function.
+
+2012-10-20 [r1096]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/DATALIFE.txt: Add missing data (nodesx->super).
+
+2012-10-20 [r1095]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* doc/DATALIFE.txt (added): A description of the data lifetime in
+	  the planetsplitter program (as an aid to understanding it better
+	  and not messing it up when editing it).
+
+2012-10-19 [r1094]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c: Remove one filesort and one read through the ways
+	  file when compacting.
+
+2012-10-19 [r1093]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.c, src/segmentsx.c, src/waysx.h: Change to an external
+	  index for the compacted ways.
+
+2012-10-18 [r1092]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c, src/waysx.c, src/waysx.h: When compacting
+	  ways exclude the ones that are not used by any segments.
+
+2012-10-17 [r1091]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/planetsplitter.c: Perform the Way compacting at the end
+	  (after pruning segments).
+
+2012-10-17 [r1090]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/waysx.h, src/waysx.c, src/segmentsx.c: Rename the WayX->prop
+	  entry to WayX->cid to disambiguate it.
+
+2012-10-17 [r1089]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/typesx.h, src/superx.c: Rename the BitMask functions to set
+	  or clear all bits.
+
+2012-09-28 [r1078]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* src/ways.c, src/segments.c, src/visualiser.c, src/nodes.c,
+	  src/ways.h, src/fakes.c, src/segments.h, src/optimiser.c,
+	  src/filedumper.c, src/fakes.h, src/output.c: Rename some
+	  variables so that pointers to nodes, segments, ways and relations
+	  use the Hungarian notation "p" suffix (only applies to the
+	  router, not planetsplitter).
+
+2012-07-22 [r1027-1028]  Andrew M. Bishop <amb at gedanken.demon.co.uk>
+
+	* web/www/routino/noscript.cgi (removed),
+	  web/www/routino/noscript.html (removed),
+	  web/www/routino/noscript.template.html (removed): Delete obsolete
+	  noscript web pages and CGIs.
+
+	* web/www/routino/customvisualiser.cgi (removed),
+	  web/www/routino/customrouter.cgi (removed): Delete obsolete
+	  custom* CGIs.
+
 2012-10-06  Andrew M. Bishop <amb at gedanken.demon.co.uk>
 
 	Version 2.3.2 released
diff --git a/doc/ALGORITHM.txt b/doc/ALGORITHM.txt
index fbd1767..929db12 100644
--- a/doc/ALGORITHM.txt
+++ b/doc/ALGORITHM.txt
@@ -208,10 +208,27 @@ Data Pruning
        segments must clearly indicate the route to take.
 
    The prune options all have user-controllable parameters which allow the
-   geographical accuracy to be controlled. In the extreme case this means
-   that although the topology is the same the geographical accuracy can be
-   sacrificed to minimise the number of nodes and segments.
-
+   geographical accuracy to be controlled. This means that although the
+   topology is the same the geographical accuracy can be sacrificed
+   slightly to minimise the number of nodes and segments.
+
+   The pruning options that are available are:
+     * Removing the access permissions for a transport type from segments
+       if it is not possible to route that transport type from those
+       segments to a significant number of other places. The limit on the
+       pruning is set by the total length of the isolated group of
+       segments. This significantly increases the chance that a route will
+       be found by not putting waypoints in inaccessible places.
+     * Removing short segments, the limit is set by the length of the
+       segment. This removes a number of redundant segments (and
+       associated nodes) but rules are applied to ensure that removing the
+       segments does not alter junction topology or remove node access
+       permissions or changes in way properties.
+     * Removing nodes from almost straight highways, the limit is set by
+       the distance between the remaining segments and the original nodes.
+       This removes a large number of redundant nodes (and therefore
+       segments) but again care is taken not to remove node access
+       permissions or changes in way properties.
 
 Turn Restrictions
 -----------------
diff --git a/doc/DATALIFE.txt b/doc/DATALIFE.txt
new file mode 100644
index 0000000..9c88db5
--- /dev/null
+++ b/doc/DATALIFE.txt
@@ -0,0 +1,88 @@
+                                Planetsplitter Data Lifetime
+                                ============================
+
+Key (memory mapping):
+  nswr = Mapped into memory read-only
+  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)
+  | = Preserved unmodified for later
+  * = Applies to super-segments
+
+                              .............................
+                              : Nodes        \
+                              : |Segments     | Mapped into
+                              : ||Ways        | memory
+                              : |||Relations /
+                              : |||| ...........................
+                              : vvvv : nodesx->idata
+                              :      : | . nodesx->gdata
+                              :      : | . | . nodesx->pdata
+                              :      : | . | . | . nodesx->super
+                              :      : | . | . | . | . nodex->id
+                              :      : | . | . | . | . | ...................................
+                              :      : v . v . v . v . v : segmentsx->firstnode
+                              :      :   .   .   .   .   : | . segmentsx->next1
+                              :      :   .   .   .   .   : | . | . segmentsx->usednode
+                              :      :   .   .   .   .   : | . | . | . segmentsx->usedway
+                              :      :   .   .   .   .   : | . | . | . | . segmentx->node1,2
+                              :      :   .   .   .   .   : | . | . | . | . | . segmentx->way
+                              :      :   .   .   .   .   : | . | . | . | . | . | ..................
+                              :      :   .   .   .   .   : v . v . v . v . v . v : waysx->idata
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . waysx->cdata
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . | . wayx->id
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . | . | ...............
+Function name (in order)      :      :   .   .   .   .   :   .   .   .   .   .   : v . v . v : relationx->id
+|                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : | ...........
+v                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : v :
+                              :......:...................:.......................:...........:...:
+SortNodeList                  :      : C .   .   .   . U :   .   .   .   . | . | :   .   . | : | :
+ApplySegmentChanges           :      : | .   .   .   .   :   .   .   .   . U . U :   .   . | : | : - Changes
+SortSegmentList               :      : | .   .   .   .   :   .   .   .   . U . | :   .   . | : | :
+SortWayList                   :      : | .   .   .   .   :   .   .   .   . | . | :   .   . | : | :
+SortRelationList              :      : | .   .   .   .   :   .   .   .   . | . | :   .   . | : U :
+ExtractWayNames               :      : | .   .   .   .   :   .   .   .   . | . | : C .   . U : | :
+RemoveBadSegments             :      : U .   .   .   .   :   .   . C .   . U . U : U .   .   : | :
+RemoveNonHighwayNodes         :      : M .   .   .   . R :   .   . D .   . | . | : | .   .   : | :
+ProcessRouteRelations         :   W  : | .   .   .   . | :   .   .   .   . | . | : U .   .   : U :
+ProcessTurnRelations1         :      : U .   .   .   . | :   .   .   .   . | . | : U .   .   : U :
+MeasureSegments               : n    : D .   .   .   . | :   .   .   . C . M . M : D .   .   : | :
+IndexSegments                 :  S   :   .   .   .   . | : C .   .   . | . M . | :   .   .   : | :
+ProcessTurnRelations2         : Nsw  :   .   .   .   . | : U .   .   . | . U . | :   .   .   : U :
+CompactWayList                :      :   .   .   .   . | :   .   .   . D . | . | :   . C . M :   :
+IndexSegments                 :  S   :   .   .   .   . | : R .   .   .   . M . | :   . D .   :   :
+                              :......:...................:.......................:...........:...:
+StartPruning                  :      :   .   .   .   .   : | . C .   .   . U . | :   .   .   :   : \
+PruneStraightHighwayNodes     : nSw  :   .   .   .   .   : U . U .   .   . U . | :   .   .   :   :  | O
+PruneIsolatedRegions          : nSw  :   .   .   .   .   : U . U .   .   . U . | :   .   .   :   :  | p
+PruneShortSegments            : NSw  :   .   .   .   .   : U . U .   .   . U . | :   .   .   :   :  | t
+FinishPruning                 :      :   .   .   .   .   : | . D .   .   . | . | :   .   .   :   :  | i
+RemovePrunedNodes             :      :   .   . C .   . R : U .   .   .   . | . | :   .   .   :   :  | o
+RemovePrunedSegments          :      :   .   . | .   . | :   .   .   . C . U . | :   .   .   :   :  | n
+CompactWayList                :      :   .   . | .   . | :   .   .   . D . | . | :   . C . M :   :  | a
+RemovePrunedTurnRelations     :      :   .   . U .   . | :   .   .   .   . | . | :   . | .   :   :  | l
+IndexSegments                 :  S   :   .   . D .   . | : R .   .   .   . M . | :   . D .   :   : /
+                              :......:...................:.......................:...........:...:
+ChooseSuperNodes              : nsw  :   .   .   . C . | : U .   .   .   . | . | :   .   .   :   : <-+ L
+CreateSuperSegments           : nsw  :   .   .   . U . | : U .   .   .   . R*. | :   .   .   :   :   | o
+DeduplicateSuperSegments      :   w  :   .   .   . | . | :   .   .   .   . U*. | :   .   .   :   :   | o
+IndexSegments                 :  S   :   .   .   . | . | : C*.   .   .   . U*. | :   .   .   :   :   | p
+                              :......:...................:.......................:...........:...: --+
+MergeSuperSegments            :  s   :   .   .   . | . | :   .   .   .   . U . | :   .   .   :   :
+IndexSegments                 :  S   :   .   .   . | . | : R .   .   .   . U . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+SortNodeListGeographically    :      :   . C .   . | . U :   .   .   .   . | . | :   .   .   :   :
+SortSegmentListGeographically :      :   . U .   . D . | :   .   .   .   . U . | :   .   .   :   :
+IndexSegments                 :  S   :   . | .   .   . | : R .   .   .   . U . | :   .   .   :   :
+SortTurnRelationListGeogra... : n    :   . U .   .   . | : U .   .   .   . U . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+SaveNodeList                  :      :   . D .   .   . U : D .   .   .   . | . | :   .   .   :   :
+SaveSegmentList               :      :   .   .   .   .   :   .   .   .   . U . U :   .   .   :   :
+SaveWayList                   :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
+SaveRelationList              :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
+                              :......:...................:.......................:...........:...:
diff --git a/doc/NEWS.txt b/doc/NEWS.txt
index c905bec..b2a92cd 100644
--- a/doc/NEWS.txt
+++ b/doc/NEWS.txt
@@ -1,3 +1,53 @@
+Version 2.4.1 of Routino released : Mon Dec 17 2012
+---------------------------------------------------
+
+Bug fixes:
+  Fix error with finding routes with low preference values (router).
+  Fix error when searching for default profiles.xml (router).
+  Fix bug with printing log messages when output is not stdout (tagmodifier).
+  Stop various crashes if trying to process file with no data (planetsplitter).
+
+Note: This version is compatible with databases from version 2.4.
+
+
+Version 2.4 of Routino released : Sat Dec 8 2012
+------------------------------------------------
+
+Bug fixes:
+  Fix pruning short segments in slim mode (gave different results to non-slim).
+  Fix error with segment lengths for some segments from ways that are areas.
+  Fix latent bug with route relations when compiled for 64-bit IDs.
+
+router/planetsplitter:
+  Replace all debugging "assert" statements with fatal error messages.
+
+planetsplitter:
+  Delete ways that are not used from the output files (names remain though).
+  Delete turn relations that are not used from the output files.
+  Speed up the processing, mainly by reducing the number of I/O operations.
+  Change the pruning of isolated regions to look at each transport type.
+  Slim and normal mode now give identical results (sorting preserves order).
+  Log some more error cases, clarify some existing ones.
+  Added a --append option which must be used to append files to existing data.
+  Added a --keep option which can be used to keep parsed, sorted data.
+  Added a --changes option to allow appending OSM change files (.osc files).
+
+Configuration Files:
+  Accept some more tag values for OSM file parsing.
+
+summarise-log.pl
+  Can now generate an HTML version with links to OSM information for each item.
+
+Deleted obsoleted files:
+  The CGI scripts customrouter.cgi and customvisualiser.cgi have been removed.
+  The noscript.cgi and noscript.html web pages have been removed.
+
+
+Note: Files deprecated in version 2.3 have been removed in version 2.4.
+
+Note: This version is not compatible with databases from previous versions.
+
+
 Version 2.3.2 of Routino released : Sat Oct 6 2012
 --------------------------------------------------
 
diff --git a/doc/README.txt b/doc/README.txt
index ced23cd..dc14a04 100644
--- a/doc/README.txt
+++ b/doc/README.txt
@@ -118,6 +118,8 @@ Status
    Version 2.3 of Routino was released on 21st July 2012.
    Version 2.3.1 of Routino was released on 11th August 2012.
    Version 2.3.2 of Routino was released on 6th October 2012.
+   Version 2.4 of Routino was released on 8th December 2012.
+   Version 2.4.1 of Routino was released on 17th December 2012.
 
    The full version history is available in the NEWS.txt file.
 
diff --git a/doc/TAGGING.txt b/doc/TAGGING.txt
index dcf1f19..615234e 100644
--- a/doc/TAGGING.txt
+++ b/doc/TAGGING.txt
@@ -273,16 +273,17 @@ Barrier Defaults
 
    Barrier       foot horse wheelchair bicycle moped motorbike motorcar goods hgv psv
    -------       ---- ----- ---------- ------- ----- --------- -------- ----- --- ---
-   bollard       yes  yes   yes        yes     yes   yes       no       no    no  no
-   kissing_gate,
-   stile,
-   v_stile,
-   turnstile,
-   footgate,
-   cycle_barrier yes  no    no         no      no    no        no       no    no  no
-   horse_barrier,
-   cattle_grid   yes  no    yes        yes     yes   yes       yes      yes   yes yes
-   car_trap      yes  yes   yes        yes     no    no        no       no    no  no
+   kissing_gate, footgate, stile, v_stile, turnstile, squeeze, squeeze_stile,
+   cycle_barrier, bicycle_barrier
+                 yes  no    no         no      no    no        no       no    no  no
+   horse_stile, horse_jump, step_over
+                 yes  yes   no         no      no    no        no       no    no  no
+   horse_barrier, cattle_grid
+                 yes  no    yes        yes     yes   yes       yes      yes   yes yes
+   motorcyle_barrier
+                 yes  yes   yes        yes     no    no        no       no    no  no
+   bollard, car_barrier, car_trap
+                 yes  yes   yes        yes     yes   yes       no       no    no  no
 
 Generic Access Permissions
 - - - - - - - - - - - - -
@@ -341,7 +342,7 @@ Highway Defaults
    tertiary_link                           tertiary
    minor, road                             unclassified
    living_street                           residential
-   services, layby                         service
+   access, services, layby                 service
    byway, unsurfaced, unpaved              track
    footway, bridleway, pedestrian, walkway path
    route=ferry                             ferry (1)
@@ -509,4 +510,4 @@ Turn Restrictions
 
 --------
 
-Copyright 2008-2011 Andrew M. Bishop.
+Copyright 2008-2012 Andrew M. Bishop.
diff --git a/doc/USAGE.txt b/doc/USAGE.txt
index 6ba36f6..49d866c 100644
--- a/doc/USAGE.txt
+++ b/doc/USAGE.txt
@@ -2,14 +2,14 @@
                                ===============
 
 
-   There are four programs that make up this software. The first one takes
+   There are five programs that make up this software. The first one takes
    the planet.osm datafile from OpenStreetMap (or other source of data
    using the same formats) and converts it into a local database. The
    second program uses the database to determine an optimum route between
    two points. The third program allows visualisation of the data and
-   statistics to be extracted. The fourth program is a test program for
-   the tag transformations.
-
+   statistics to be extracted. The fourth program allows dumping the raw
+   parsed data for test purposes and the fifth is a test program for the
+   tag transformations.
 
 planetsplitter
 --------------
@@ -25,6 +25,7 @@ planetsplitter
                          [--loggable] [--logtime]
                          [--errorlog[=<name>]]
                          [--parse-only | --process-only]
+                         [--append] [--keep] [--changes]
                          [--max-iterations=<number>]
                          [--prune-none]
                          [--prune-isolated=<len>]
@@ -77,15 +78,34 @@ planetsplitter
    --errorlog[=<name>]
           Log OSM parsing and processing errors to 'error.log' or the
           specified file name (the '--dir' and '--prefix' options are
-          applied).
+          applied). If the --append option is used then the existing log
+          file will be appended, otherwise a new one will be created.
 
    --parse-only
-          Parse the input files and store them in a temporary file but
-          don't process the data into a routing database.
+          Parse the input files and store the data in intermediate files
+          but don't process the data into a routing database. This option
+          must be used with the --append option for all except the first
+          file.
 
    --process-only
-          Don't read in any files but process the existing temporary file
-          into the routing database.
+          Don't read in any files but process the existing intermediate
+          files created by using the --parse-only option.
+
+   --append
+          Parse the input file and append the result to the existing
+          intermediate files; the appended file can be either an OSM file
+          or an OSC change file.
+
+   --keep
+          Store a set of intermediate files after parsing the OSM files,
+          sorting and removing duplicates; this allows appending an OSC
+          file and re-processing later.
+
+   --changes
+          This option indicates that the data being processed contains one
+          or more OSC (OSM changes) files, they must be applied in time
+          sequence if more than one is used. This option implies --append
+          when parsing data files and --keep when processing data.
 
    --max-iterations=<number>
           The maximum number of iterations to use when generating
@@ -97,8 +117,10 @@ planetsplitter
           adding them to the command line after this option.
 
    --prune-isolated=<length>
-          Remove small disconnected groups of segments (defaults to
-          removing groups under 500m).
+          Remove the access permissions for a transport type from small
+          disconnected groups of segments and remove the segments if they
+          nd up with no access permission (defaults to removing groups
+          under 500m).
 
    --prune-short=<length>
           Remove short segments (defaults to removing segments up to a
@@ -125,13 +147,43 @@ planetsplitter
    machines). The penalty for this is that the program takes about twice
    as long to run.
 
-   Example usage:
+   Example usage 1:
 
-   ./planetsplitter --dir=data --prefix=gb great_britain.osm
+   planetsplitter --dir=data --prefix=gb great_britain.osm
 
    This will generate the output files 'data/gb-nodes.mem',
-   'data/gb-segments.mem' and 'data/gb-ways.mem'.
+   'data/gb-segments.mem' and 'data/gb-ways.mem'. Multiple filenames can
+   be specified on the command line and they will all be read in, combined
+   and processed together.
+
+   Example usage 2:
+
+   planetsplitter --dir=data --prefix=gb --parse-only          great_britain_part1.osm
+   planetsplitter --dir=data --prefix=gb --parse-only --append great_britain_part2.osm
+   planetsplitter --dir=data --prefix=gb --parse-only --append ...
+   planetsplitter --dir=data --prefix=gb --process-only
+
+   This will generate the same output files as the first example but
+   parsing the input files is performed separately from the data
+   processing. The first file read in must not use the --append option but
+   the later ones must.
+
+   Example usage 3:
+
+   planetsplitter --dir=data --prefix=gb --keep    great_britain_part.osm
 
+   planetsplitter --dir=data --prefix=gb --changes great_britain.osc
+
+   This will generate the same output files as the first example. The
+   first command will process the complete file and keep some intermediate
+   data for later. The second command will apply a set of changes to the
+   stored intermediate data and keep the updated intermediate files for
+   repeating this step later with more change data.
+
+   The parsing and processing can be split into multiple commands as it
+   was in example 2 with the --keep option used with --process-only for
+   the initial OSM file(s) and the --changes option used with --parse-only
+   or --process-only for every OSC file.
 
 router
 ------
@@ -374,8 +426,8 @@ router
 
    Example usage (motorbike journey, scenic route, not very fast):
 
-   ./router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
-            --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+   router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
+          --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
 
    This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and
    'data/gb-ways.mem' to find the quickest route by motorbike not using
@@ -489,6 +541,54 @@ filedumper
    needed rather than being mapped into memory.
 
 
+filedumperx
+-----------
+
+   This program is a modified version of filedumper that will dump out the
+   contents of the intermediate data that is saved by planetsplitter after
+   processing using the --keep or --changes option. This is intended
+   for test purposes only and gives no useful information about the
+   routing database.
+
+   Usage: filedumper [--help]
+                     [--dir=<dirname>] [--prefix=<name>]
+                     [--dump [--nodes]
+                             [--segments]
+                             [--ways]
+                             [--route-relations]
+                             [--turn-relations]]
+
+   --help
+          Prints out the help information.
+
+   --dir=<dirname>
+          Sets the directory name in which to read the local database.
+          Defaults to the current directory.
+
+   --prefix=<name>
+          Sets the filename prefix for the files in the local database.
+
+   --dump
+          Dumps the complete set of data in the intermediate files that
+          are written by planetsplitter using the --keep or --changes
+          options.
+
+        --nodes
+                Dumps the node data.
+
+        --segments
+                Dumps the segment data.
+
+        --ways
+                Dumps the way data.
+
+        --route-relations
+                Dumps the route relation data.
+
+        --turn-relations
+                Dumps the turn relation data.
+
+
 tagmodifier
 -----------
 
diff --git a/doc/html/algorithm.html b/doc/html/algorithm.html
index e890d62..fbc5964 100644
--- a/doc/html/algorithm.html
+++ b/doc/html/algorithm.html
@@ -247,9 +247,27 @@ The pruning options must meet a number of conditions to be useful:
 </ul>
 <p>
 The prune options all have user-controllable parameters which allow the
-geographical accuracy to be controlled.  In the extreme case this means that
-although the topology is the same the geographical accuracy can be sacrificed to
-minimise the number of nodes and segments.
+geographical accuracy to be controlled.  This means that although the topology
+is the same the geographical accuracy can be sacrificed slightly to minimise the
+number of nodes and segments.
+<p>
+The pruning options that are available are:
+<ul>
+  <li>Removing the access permissions for a transport type from segments if it
+  is not possible to route that transport type from those segments to a
+  significant number of other places.  The limit on the pruning is set by the
+  total length of the isolated group of segments.  This significantly increases
+  the chance that a route will be found by not putting waypoints in inaccessible
+  places.
+  <li>Removing short segments, the limit is set by the length of the segment.
+  This removes a number of redundant segments (and associated nodes) but rules
+  are applied to ensure that removing the segments does not alter junction
+  topology or remove node access permissions or changes in way properties.
+  <li>Removing nodes from almost straight highways, the limit is set by the
+  distance between the remaining segments and the original nodes.  This removes
+  a large number of redundant nodes (and therefore segments) but again care is
+  taken not to remove node access permissions or changes in way properties.
+</ul>
 
 <h3><a name="H_1_1_6"></a>Turn Restrictions</h3>
 
diff --git a/doc/html/readme.html b/doc/html/readme.html
index 22bac92..09f7a63 100644
--- a/doc/html/readme.html
+++ b/doc/html/readme.html
@@ -182,107 +182,66 @@ Version 2.3 of Routino was released on 21st July 2012.
 Version 2.3.1 of Routino was released on 11th August 2012.
 <br>
 Version 2.3.2 of Routino was released on 6th October 2012.
+<br>
+Version 2.4 of Routino was released on 8th December 2012.
+<br>
+Version 2.4.1 of Routino was released on 17th December 2012.
 
 <p>
 
 The full version history is available in the NEWS file.
 
 
-<h3><a name="H_1_5_1" title="Changes"></a>Changes in Versions 2.3, 2.3.1 and 2.3.2</h3>
+<h3><a name="H_1_5_1" title="Changes"></a>Changes in Version 2.4/2.4.1</h3>
 
-In version 2.3.2:
+In version 2.4.1 - bug fixes.
 
 <dl>
   <dt>Bug fixes:
-  <dd>Fix for highway type visualiser (was missing one-way segments).
-  <br>Fix a real-life routing problem with oneway streets and super-segments.
-  <br>Find a route even if an end waypoint forbids the specified transport.
-  <br>Include the final junction in the HTML output (was missed in some cases).
-
-  <dt>Test cases:
-  <dd>Create new test cases for two bugs fixed in this version.
-
-  <dt>router:
-  <dd>Improve the error message for some cases of failing to route.
-
-  <dt>planetsplitter:
-  <dd>Log an error if a foot/bicycle way doesn't allow foot/bicycle transport.
-  <br>Do not mark nodes as super-nodes if they allow no transport types through.
-
-  <dt>Web pages (visualiser):
-  <dd>Allow plotting nodes that block each transport type.
-
-  <dt>Configuration Files:
-  <dd>Change the default license/copyright notice in the translations.xml file.
+  <dd>Fix error with finding routes with low preference values (router).
+  <dd>Fix error when searching for default profiles.xml (router).
+  <dd>Fix bug with printing log messages when output is not stdout (tagmodifier).
+  <dd>Stop various crashes if trying to process file with no data (planetsplitter).
 </dl>
 
-In version 2.3.1:
+In version 2.4 - mostly new features.
 
 <dl>
   <dt>Bug fixes:
-  <dd>Create marker-XXX-grey.png icon which gets used before Javascript removes it.
-  <br>Provide full set of 99 marker icons instead of just 19.
-  <br>Add more limit icons (0.0-0.9, 20.0-40.0 and 161-200).
-  <br>Fix router web page problem with placing initial marker (coords not updated).
-  <br>Hide waypoints so that they are not visible when Javascript adds them to HTML.
-  <br>Fix web page font problems by choosing an explicit font pixel-size in the CSS.
-  <br>Fix potential crash in XML files containing lots of key/value pairs in a tag.
-
-  <dt>Web pages (router):
-  <dd>Unused waypoints show as blank rather than 0,0.
-  <br>Add a button to insert a waypoint to close the loop.
-  <br>Write the command line and execution time to the log file.
-</dl>
+  <dd>Fix pruning short segments in slim mode (gave different results to non-slim).
+  <br>Fix error with segment lengths for some segments from ways that are areas.
+  <br>Fix latent bug with route relations when compiled for 64-bit IDs.
 
-In version 2.3:
-
-<dl>
-  <dt>Bug fixes:
-  <dd>Handle OSM files that contain changesets (don't raise an error).
-  <br>Force bicyle/foot routes to allow bicycle/foot transport.
-  <br>Fix problem running CGIs on Macs (md5 program name).
-  <br>Fix bug with pruning straight highways (uninitialised data).
-  <br>Fix bug with XML parsing error log (could miss some unrecognised tags).
-
-  <dt>Web pages (all):
-  <dd>Make compatible with OpenLayers v2.12 (but don't change the install script).
-  <br>Make all HTML files standards compliant.
-  <br>Allow the HTML files to parse the query string instead of using a CGI.
-  <br>Move all user-editable parameters to paths.pl and mapprops.js.
-
-  <dt>Web pages (router):
-  <dd>Add a button to put a marker at the current location (Javascript geolocation).
-  <br>Add a button to centre the map on a given marker.
-  <br>Automatically insert the waypoints in the HTML from the JavaScript.
-  <br>Added a German language router web page translation.
-  <br>Add buttons to switch between lat/long and placename with Nominatim lookups.
-
-  <dt>Web pages (visualiser):
-  <dd>Allow plotting segments of each highway type.
-  <br>Allow plotting segments accessible to each transport type.
+  <dt>router/planetsplitter:
+  <dd>Replace all debugging "assert" statements with fatal error messages.
 
   <dt>planetsplitter:
-  <dd>Add a new '--logtime' option that prints the elapsed time of each step.
-  <br>Make the sort functions multi-threaded (run-time option).
-  <br>Improve the XML parsing speed slightly.
-</dl>
+  <dd>Delete ways that are not used from the output files (names remain though).
+  <br>Delete turn relations that are not used from the output files.
+  <br>Speed up the processing, mainly by reducing the number of I/O operations.
+  <br>Change the pruning of isolated regions to look at each transport type.
+  <br>Slim and normal mode now give identical results (sorting preserves order).
+  <br>Log some more error cases, clarify some existing ones.
+  <br>Added a --append option which must be used to append files to existing data.
+  <br>Added a --keep option which can be used to keep parsed, sorted data.
+  <br>Added a --changes option to allow appending OSM change files (.osc files).
 
-<p>
-<b>Note:</b> Existing mapprops.js and paths.pl files need to be updated to
-include new items for this version.
+  <dt>Configuration Files:
+  <dd>Accept some more tag values for OSM file parsing.
 
-<p>
-<b>Note:</b> Existing OpenLayers installations must be updated if they were
-installed with older Routino provided script (the old OpenLayers.js will not
-work).
+  <dt>summarise-log.pl:
+  <dd>Can now generate an HTML version with links to OSM information for each item.
+
+  <dt>Deleted obsoleted files:
+  <dd>The CGI scripts customrouter.cgi and customvisualiser.cgi have been removed.
+  <br>The noscript.cgi and noscript.html web pages have been removed.
+</dl>
 
 <p>
-<b>Note:</b> The CGI scripts customrouter.cgi and customvisualiser.cgi are
-deprecated and will be removed in the next version.
+<b>Note:</b> Files deprecated in version 2.3 have been removed in version 2.4.
 
 <p>
-<b>Note:</b> The noscript.cgi and noscript.html web pages are deprecated and
-will be removed in the next version.
+<b>Note:</b> This version is not compatible with databases from previous versions.
 
 
 <h3><a name="H_1_5_2"></a>License</h3>
diff --git a/doc/html/tagging.html b/doc/html/tagging.html
index 1d15942..e7cce07 100644
--- a/doc/html/tagging.html
+++ b/doc/html/tagging.html
@@ -6,7 +6,7 @@
 
  Part of the Routino routing software.
 
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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
@@ -351,21 +351,21 @@ a default set of disallowed transport types.
     <th class="center">hgv
     <th class="center">psv
   <tr>
-    <td class="left">bollard
-    <td class="center">yes
-    <td class="center">yes
-    <td class="center">yes
-    <td class="center">yes
-    <td class="center">yes
+    <td class="left">kissing_gate, footgate, stile, v_stile, turnstile, squeeze, squeeze_stile, cycle_barrier, bicycle_barrier
     <td class="center">yes
     <td class="center">no
     <td class="center">no
     <td class="center">no
     <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
   <tr>
-    <td class="left">kissing_gate, stile, v_stile, turnstile, footgate, cycle_barrier
+    <td class="left">horse_stile, horse_jump, step_over
+    <td class="center">yes
     <td class="center">yes
-    <td class="center">no
     <td class="center">no
     <td class="center">no
     <td class="center">no
@@ -387,7 +387,7 @@ a default set of disallowed transport types.
     <td class="center">yes
     <td class="center">yes
   <tr>
-    <td class="left">car_trap
+    <td class="left">motorcyle_barrier
     <td class="center">yes
     <td class="center">yes
     <td class="center">yes
@@ -398,6 +398,18 @@ a default set of disallowed transport types.
     <td class="center">no
     <td class="center">no
     <td class="center">no
+  <tr>
+    <td class="left">bollard, car_barrier, car_trap
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
 </table>
 
 <h4><a name="H_1_3_1_2" title="Generic access"></a>Generic Access Permissions</h4>
@@ -483,7 +495,7 @@ is recognised by Routino.
     <td class="left">living_street
     <td class="left">residential
   <tr>
-    <td class="left">services, layby
+    <td class="left">access, services, layby
     <td class="left">service
   <tr>
     <td class="left">byway, unsurfaced, unpaved
diff --git a/doc/html/usage.html b/doc/html/usage.html
index 3e53638..1b65bc0 100644
--- a/doc/html/usage.html
+++ b/doc/html/usage.html
@@ -47,12 +47,13 @@
 
 <h2><a name="H_1_1"></a>Program Usage</h2>
 
-There are four programs that make up this software.  The first one takes the
+There are five programs that make up this software.  The first one takes the
 planet.osm datafile from OpenStreetMap (or other source of data using the same
 formats) and converts it into a local database.  The second program uses the
 database to determine an optimum route between two points.  The third program
 allows visualisation of the data and statistics to be extracted.  The fourth
-program is a test program for the tag transformations.
+program allows dumping the raw parsed data for test purposes and the fifth is a
+test program for the tag transformations.
 
 <h3><a name="H_1_1_1"></a>planetsplitter</h3>
 
@@ -68,6 +69,7 @@ Usage: planetsplitter [--help]
                       [--loggable] [--logtime]
                       [--errorlog[=<name>]]
                       [--parse-only | --process-only]
+                      [--append] [--keep] [--changes]
                       [--max-iterations=<number>]
                       [--prune-none]
                       [--prune-isolated=<len>]
@@ -110,13 +112,28 @@ Usage: planetsplitter [--help]
   <dd>Print the elapsed time for each processing step.
   <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).
+    name (the '--dir' and '--prefix' options are applied).  If the --append
+    option is used then the existing log file will be appended, otherwise a new
+    one will be created.
   <dt>--parse-only
-  <dd>Parse the input files and store them in a temporary file but don't process
-    the data into a routing database.
+  <dd>Parse the input files and store the data in intermediate files but don't
+    process the data into a routing database.  This option must be used with the
+    --append option for all except the first file.
   <dt>--process-only
-  <dd>Don't read in any files but process the existing temporary file into the
-    routing database.
+  <dd>Don't read in any files but process the existing intermediate files
+    created by using the --parse-only option.
+  <dt>--append
+  <dd>Parse the input file and append the result to the existing intermediate
+    files; the appended file can be either an OSM file or an OSC change file.
+  <dt>--keep
+  <dd>Store a set of intermediate files after parsing the OSM files, sorting and
+    removing duplicates; this allows appending an OSC file and re-processing
+    later.
+  <dt>--changes
+  <dd>This option indicates that the data being processed contains one or more
+    OSC (OSM changes) files, they must be applied in time sequence if more than
+    one is used.  This option implies --append when parsing data files and
+    --keep when processing data.
   <dt>--max-iterations=<number>
   <dd>The maximum number of iterations to use when generating super-nodes and
     super-segments.  Defaults to 5 which is normally enough.
@@ -124,8 +141,9 @@ Usage: planetsplitter [--help]
   <dd>Disable the prune options below, they can be re-enabled by adding them to
     the command line after this option.
   <dt>--prune-isolated=<length>
-  <dd>Remove small disconnected groups of segments (defaults to removing groups
-    under 500m).
+  <dd>Remove the access permissions for a transport type from small disconnected
+    groups of segments and remove the segments if they nd up with no access
+    permission (defaults to removing groups under 500m).
   <dt>--prune-short=<length>
   <dd>Remove short segments (defaults to removing segments up to a maximum
     length of 5m).
@@ -152,14 +170,49 @@ or no virtual memory (e.g. some virtual machines).  The penalty for this is that
 the program takes about twice as long to run.</i>
 
 <p>
-Example usage:
+Example usage 1:
 
 <pre class="boxed">
-./planetsplitter --dir=data --prefix=gb great_britain.osm
+planetsplitter --dir=data --prefix=gb great_britain.osm
 </pre>
 
 This will generate the output files 'data/gb-nodes.mem', 'data/gb-segments.mem'
-and 'data/gb-ways.mem'.
+and 'data/gb-ways.mem'.  Multiple filenames can be specified on the command
+line and they will all be read in, combined and processed together.
+
+<p>
+Example usage 2:
+
+<pre class="boxed">
+planetsplitter --dir=data --prefix=gb --parse-only          great_britain_part1.osm
+planetsplitter --dir=data --prefix=gb --parse-only --append great_britain_part2.osm
+planetsplitter --dir=data --prefix=gb --parse-only --append ...
+planetsplitter --dir=data --prefix=gb --process-only
+</pre>
+
+This will generate the same output files as the first example but parsing the
+input files is performed separately from the data processing.  The first file
+read in must not use the --append option but the later ones must.
+
+<p>
+Example usage 3:
+
+<pre class="boxed">
+planetsplitter --dir=data --prefix=gb --keep    great_britain_part.osm
+
+planetsplitter --dir=data --prefix=gb --changes great_britain.osc
+</pre>
+
+This will generate the same output files as the first example.  The first
+command will process the complete file and keep some intermediate data for
+later.  The second command will apply a set of changes to the stored
+intermediate data and keep the updated intermediate files for repeating this
+step later with more change data.
+<p>
+The parsing and processing can be split into multiple commands as it was in
+example 2 with the --keep option used with --process-only for the initial OSM
+file(s) and the --changes option used with --parse-only or --process-only for
+every OSC file.
 
 
 <h3><a name="H_1_1_2"></a>router</h3>
@@ -372,8 +425,8 @@ and all of the preferences for the highway properties.
 Example usage (motorbike journey, scenic route, not very fast):
 
 <pre class="boxed">
-./router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
-         --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
+       --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
 </pre>
 
 This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and
@@ -478,7 +531,50 @@ that operates in slim mode.  In slim mode the database files are read as needed
 rather than being mapped into memory.</i>
 
 
-<h3><a name="H_1_1_4"></a>tagmodifier</h3>
+<h3><a name="H_1_1_4"></a>filedumperx</h3>
+
+This program is a modified version of filedumper that will dump out the contents
+of the intermediate data that is saved by planetsplitter after processing using
+the --keep or --changes option.  This is intended for test purposes only and
+gives no useful information about the routing database.
+
+<pre class="boxed">
+Usage: filedumper [--help]
+                  [--dir=<dirname>] [--prefix=<name>]
+                  [--dump [--nodes]
+                          [--segments]
+                          [--ways]
+                          [--route-relations]
+                          [--turn-relations]]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=<dirname>
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=<name>
+  <dd>Sets the filename prefix for the files in the local database.
+  <dt>--dump
+  <dd>Dumps the complete set of data in the intermediate files that are written
+    by planetsplitter using the --keep or --changes options.
+    <dl>
+      <dt>--nodes
+      <dd>Dumps the node data.
+      <dt>--segments
+      <dd>Dumps the segment data.
+      <dt>--ways
+      <dd>Dumps the way data.
+      <dt>--route-relations
+      <dd>Dumps the route relation data.
+      <dt>--turn-relations
+      <dd>Dumps the turn relation data.
+    </dl>
+</dl>
+
+
+<h3><a name="H_1_1_5"></a>tagmodifier</h3>
 
 This program is used to run the tag transformation process on an OSM XML file
 for test purposes.
diff --git a/src/Makefile b/src/Makefile
index 9356bf0..5fcf661 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -60,7 +60,7 @@ CFLAGS+=-D_POSIX_C_SOURCE=200809L
 C=$(wildcard *.c)
 D=$(wildcard .deps/*.d)
 
-EXE=planetsplitter planetsplitter-slim router router-slim filedumper filedumper-slim tagmodifier
+EXE=planetsplitter planetsplitter-slim router router-slim filedumperx filedumper filedumper-slim tagmodifier
 
 ########
 
@@ -123,6 +123,14 @@ router-slim : $(ROUTER_SLIM_OBJ)
 
 ########
 
+FILEDUMPERX_OBJ=filedumperx.o \
+	        files.o logging.o
+
+filedumperx : $(FILEDUMPERX_OBJ)
+	$(LD) $(FILEDUMPERX_OBJ) -o $@ $(LDFLAGS)
+
+########
+
 FILEDUMPER_OBJ=filedumper.o \
 	       nodes.o segments.o ways.o relations.o types.o fakes.o \
                visualiser.o \
diff --git a/src/fakes.c b/src/fakes.c
index fd6df79..7076834 100644
--- a/src/fakes.c
+++ b/src/fakes.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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,7 +57,7 @@ static int prevpoint=0;
 
   int point Which of the waypoints this is.
 
-  Segment *segment The segment to split.
+  Segment *segmentp The segment to split.
 
   index_t node1 The first node at the end of this segment.
 
@@ -68,7 +68,7 @@ static int prevpoint=0;
   distance_t dist2 The distance to the second node.
   ++++++++++++++++++++++++++++++++++++++*/
 
-index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segment,index_t node1,index_t node2,distance_t dist1,distance_t dist2)
+index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segmentp,index_t node1,index_t node2,distance_t dist1,distance_t dist2)
 {
  index_t fakenode;
  double lat1,lon1,lat2,lon2;
@@ -149,23 +149,23 @@ index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segment,i
 
  /* Create the first fake segment */
 
- fake_segments[4*point-4]=*segment;
+ fake_segments[4*point-4]=*segmentp;
 
  fake_segments[4*point-4].node2=fakenode;
 
- fake_segments[4*point-4].distance=DISTANCE(dist1)|DISTFLAG(segment->distance);
+ fake_segments[4*point-4].distance=DISTANCE(dist1)|DISTFLAG(segmentp->distance);
 
- real_segments[4*point-4]=IndexSegment(segments,segment);
+ real_segments[4*point-4]=IndexSegment(segments,segmentp);
 
  /* Create the second fake segment */
 
- fake_segments[4*point-3]=*segment;
+ fake_segments[4*point-3]=*segmentp;
 
  fake_segments[4*point-3].node1=fakenode;
 
- fake_segments[4*point-3].distance=DISTANCE(dist2)|DISTFLAG(segment->distance);
+ fake_segments[4*point-3].distance=DISTANCE(dist2)|DISTFLAG(segmentp->distance);
 
- real_segments[4*point-3]=IndexSegment(segments,segment);
+ real_segments[4*point-3]=IndexSegment(segments,segmentp);
 
  /* Create a third fake segment to join adjacent points if both are fake and on the same real segment */
 
@@ -177,7 +177,7 @@ index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segment,i
 
        fake_segments[4*point-2].node2=fakenode;
 
-       fake_segments[4*point-2].distance=(DISTANCE(dist1)-DISTANCE(fake_segments[4*prevpoint-4].distance))|DISTFLAG(segment->distance);
+       fake_segments[4*point-2].distance=(DISTANCE(dist1)-DISTANCE(fake_segments[4*prevpoint-4].distance))|DISTFLAG(segmentp->distance);
       }
     else
       {
@@ -185,10 +185,10 @@ index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segment,i
 
        fake_segments[4*point-2].node1=fakenode;
 
-       fake_segments[4*point-2].distance=(DISTANCE(fake_segments[4*prevpoint-4].distance)-DISTANCE(dist1))|DISTFLAG(segment->distance);
+       fake_segments[4*point-2].distance=(DISTANCE(fake_segments[4*prevpoint-4].distance)-DISTANCE(dist1))|DISTFLAG(segmentp->distance);
       }
 
-    real_segments[4*point-2]=IndexSegment(segments,segment);
+    real_segments[4*point-2]=IndexSegment(segments,segmentp);
 
     fake_segments[4*prevpoint-1]=fake_segments[4*point-2];
 
@@ -243,25 +243,25 @@ Segment *FirstFakeSegment(index_t fakenode)
 
   Segment *NextFakeSegment Returns a pointer to the next fake segment.
 
-  Segment *fakesegment The first fake segment.
+  Segment *fakesegmentp The first fake segment.
 
   index_t fakenode The node to lookup.
   ++++++++++++++++++++++++++++++++++++++*/
 
-Segment *NextFakeSegment(Segment *fakesegment,index_t fakenode)
+Segment *NextFakeSegment(Segment *fakesegmentp,index_t fakenode)
 {
  index_t whichnode=fakenode-NODE_FAKE;
 
- if(fakesegment==&fake_segments[4*whichnode-4])
+ if(fakesegmentp==&fake_segments[4*whichnode-4])
     return(&fake_segments[4*whichnode-3]);
 
- if(fakesegment==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-2].node1!=NO_NODE)
+ if(fakesegmentp==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-2].node1!=NO_NODE)
     return(&fake_segments[4*whichnode-2]);
 
- if(fakesegment==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-1].node1!=NO_NODE)
+ if(fakesegmentp==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-1].node1!=NO_NODE)
     return(&fake_segments[4*whichnode-1]);
 
- if(fakesegment==&fake_segments[4*whichnode-2] && fake_segments[4*whichnode-1].node1!=NO_NODE)
+ if(fakesegmentp==&fake_segments[4*whichnode-2] && fake_segments[4*whichnode-1].node1!=NO_NODE)
     return(&fake_segments[4*whichnode-1]);
 
  return(NULL);
@@ -313,12 +313,12 @@ Segment *LookupFakeSegment(index_t fakesegment)
 
   index_t IndexFakeSegment Returns the fake segment.
 
-  Segment *fakesegment The fake segment to look for.
+  Segment *fakesegmentp The fake segment to look for.
   ++++++++++++++++++++++++++++++++++++++*/
 
-index_t IndexFakeSegment(Segment *fakesegment)
+index_t IndexFakeSegment(Segment *fakesegmentp)
 {
- index_t whichsegment=fakesegment-&fake_segments[0];
+ index_t whichsegment=fakesegmentp-&fake_segments[0];
 
  return(whichsegment+SEGMENT_FAKE);
 }
diff --git a/src/fakes.h b/src/fakes.h
index 7d9524a..211e2bf 100644
--- a/src/fakes.h
+++ b/src/fakes.h
@@ -37,16 +37,16 @@
 
 /* Functions in fakes.c */
 
-index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segment,index_t node1,index_t node2,distance_t dist1,distance_t dist2);
+index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segmentp,index_t node1,index_t node2,distance_t dist1,distance_t dist2);
 
 void GetFakeLatLong(index_t fakenode, double *latitude,double *longitude);
 
 Segment *FirstFakeSegment(index_t fakenode);
-Segment *NextFakeSegment(Segment *fakesegment,index_t fakenode);
+Segment *NextFakeSegment(Segment *fakesegmentp,index_t fakenode);
 Segment *ExtraFakeSegment(index_t realnode,index_t fakenode);
 
 Segment *LookupFakeSegment(index_t index);
-index_t IndexFakeSegment(Segment *fakesegment);
+index_t IndexFakeSegment(Segment *fakesegmentp);
 index_t IndexRealSegment(index_t fakesegment);
 
 int IsFakeUTurn(index_t fakesegment1,index_t fakesegment2);
diff --git a/src/filedumper.c b/src/filedumper.c
index 9d796ef..c289aea 100644
--- a/src/filedumper.c
+++ b/src/filedumper.c
@@ -44,14 +44,14 @@
 static void print_node(Nodes *nodes,index_t item);
 static void print_segment(Segments *segments,index_t item);
 static void print_way(Ways *ways,index_t item);
-static void print_turnrelation(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
+static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
 
 static void print_head_osm(int coordcount,double latmin,double latmax,double lonmin,double lonmax);
 static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,
                              double latmin,double latmax,double lonmin,double lonmax,int option_no_super);
 static void print_node_osm(Nodes *nodes,index_t item);
 static void print_segment_osm(Segments *segments,index_t item,Ways *ways);
-static void print_turnrelation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
+static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
 static void print_tail_osm(void);
 
 static char *RFC822Date(time_t t);
@@ -153,7 +153,7 @@ int main(int argc,char** argv)
        OutputSuper(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
     else if(!strcmp(option_data,"oneway"))
        OutputOneway(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
-    else if(!strncmp(option_data,"highway",7) && option_data[7]=='-' && (highway=HighwayType(option_data+8))!=Way_Count)
+    else if(!strncmp(option_data,"highway",7) && option_data[7]=='-' && (highway=HighwayType(option_data+8))!=Highway_None)
        OutputHighway(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,highway);
     else if(!strncmp(option_data,"transport",9) && option_data[9]=='-' && (transport=TransportType(option_data+10))!=Transport_None)
        OutputTransport(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,transport);
@@ -248,13 +248,12 @@ int main(int argc,char** argv)
     printf("----\n");
     printf("\n");
 
-    printf("sizeof(Way)      =%9lu Bytes\n",(unsigned long)sizeof(Way));
-    printf("Number(compacted)=%9"Pindex_t"\n",OSMWays->file.number);
-    printf("Number(original) =%9"Pindex_t"\n",OSMWays->file.onumber);
+    printf("sizeof(Way)=%9lu Bytes\n",(unsigned long)sizeof(Way));
+    printf("Number     =%9"Pindex_t"\n",OSMWays->file.number);
     printf("\n");
 
     stat(ways_filename,&buf);
-    printf("Total names =%9lu Bytes\n",(unsigned long)buf.st_size-(unsigned long)sizeof(Ways)-(unsigned long)OSMWays->file.number*(unsigned long)sizeof(Way));
+    printf("Total names=%9lu Bytes\n",(unsigned long)buf.st_size-(unsigned long)sizeof(Ways)-(unsigned long)OSMWays->file.number*(unsigned long)sizeof(Way));
     printf("\n");
 
     printf("Included highways  : %s\n",HighwaysNameList(OSMWays->file.highways));
@@ -324,14 +323,14 @@ int main(int argc,char** argv)
        else if(!strcmp(argv[arg],"--turn-relation=all"))
          {
           for(item=0;item<OSMRelations->file.trnumber;item++)
-             print_turnrelation(OSMRelations,item,OSMSegments,OSMNodes);
+             print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes);
          }
        else if(!strncmp(argv[arg],"--turn-relation=",16))
          {
           item=atoi(&argv[arg][16]);
 
           if(item>=0 && item<OSMRelations->file.trnumber)
-             print_turnrelation(OSMRelations,item,OSMSegments,OSMNodes);
+             print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes);
           else
              printf("Invalid turn relation number; minimum=0, maximum=%"Pindex_t".\n",OSMRelations->file.trnumber-1);
          }
@@ -360,7 +359,7 @@ int main(int argc,char** argv)
              print_segment_osm(OSMSegments,item,OSMWays);
 
        for(item=0;item<OSMRelations->file.trnumber;item++)
-          print_turnrelation_osm(OSMRelations,item,OSMSegments,OSMNodes);
+          print_turn_relation_osm(OSMRelations,item,OSMSegments,OSMNodes);
       }
 
     print_tail_osm();
@@ -380,16 +379,16 @@ int main(int argc,char** argv)
 
 static void print_node(Nodes *nodes,index_t item)
 {
- Node *node=LookupNode(nodes,item,1);
+ Node *nodep=LookupNode(nodes,item,1);
  double latitude,longitude;
 
  GetLatLong(nodes,item,&latitude,&longitude);
 
  printf("Node %"Pindex_t"\n",item);
- printf("  firstseg=%"Pindex_t"\n",node->firstseg);
- printf("  latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",node->latoffset,node->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude));
- printf("  allow=%02x (%s)\n",node->allow,AllowedNameList(node->allow));
- if(IsSuperNode(node))
+ printf("  firstseg=%"Pindex_t"\n",nodep->firstseg);
+ printf("  latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",nodep->latoffset,nodep->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude));
+ printf("  allow=%02x (%s)\n",nodep->allow,AllowedNameList(nodep->allow));
+ if(IsSuperNode(nodep))
     printf("  Super-Node\n");
 }
 
@@ -404,20 +403,20 @@ static void print_node(Nodes *nodes,index_t item)
 
 static void print_segment(Segments *segments,index_t item)
 {
- Segment *segment=LookupSegment(segments,item,1);
+ Segment *segmentp=LookupSegment(segments,item,1);
 
  printf("Segment %"Pindex_t"\n",item);
- printf("  node1=%"Pindex_t" node2=%"Pindex_t"\n",segment->node1,segment->node2);
- printf("  next2=%"Pindex_t"\n",segment->next2);
- printf("  way=%"Pindex_t"\n",segment->way);
- printf("  distance=%d (%.3f km)\n",DISTANCE(segment->distance),distance_to_km(DISTANCE(segment->distance)));
- if(IsSuperSegment(segment) && IsNormalSegment(segment))
+ printf("  node1=%"Pindex_t" node2=%"Pindex_t"\n",segmentp->node1,segmentp->node2);
+ printf("  next2=%"Pindex_t"\n",segmentp->next2);
+ printf("  way=%"Pindex_t"\n",segmentp->way);
+ printf("  distance=%d (%.3f km)\n",DISTANCE(segmentp->distance),distance_to_km(DISTANCE(segmentp->distance)));
+ if(IsSuperSegment(segmentp) && IsNormalSegment(segmentp))
     printf("  Super-Segment AND normal Segment\n");
- else if(IsSuperSegment(segment) && !IsNormalSegment(segment))
+ else if(IsSuperSegment(segmentp) && !IsNormalSegment(segmentp))
     printf("  Super-Segment\n");
- if(IsOnewayTo(segment,segment->node1))
+ if(IsOnewayTo(segmentp,segmentp->node1))
     printf("  One-Way from node2 to node1\n");
- if(IsOnewayTo(segment,segment->node2))
+ if(IsOnewayTo(segmentp,segmentp->node2))
     printf("  One-Way from node1 to node2\n");
 }
 
@@ -432,26 +431,26 @@ static void print_segment(Segments *segments,index_t item)
 
 static void print_way(Ways *ways,index_t item)
 {
- Way *way=LookupWay(ways,item,1);
- char *name=WayName(ways,way);
+ Way *wayp=LookupWay(ways,item,1);
+ char *name=WayName(ways,wayp);
 
  printf("Way %"Pindex_t"\n",item);
  if(*name)
     printf("  name=%s\n",name);
- printf("  type=%02x (%s%s%s)\n",way->type,HighwayName(HIGHWAY(way->type)),way->type&Way_OneWay?",One-Way":"",way->type&Way_Roundabout?",Roundabout":"");
- printf("  allow=%02x (%s)\n",way->allow,AllowedNameList(way->allow));
- if(way->props)
-    printf("  props=%02x (%s)\n",way->props,PropertiesNameList(way->props));
- if(way->speed)
-    printf("  speed=%d (%d km/hr)\n",way->speed,speed_to_kph(way->speed));
- if(way->weight)
-    printf("  weight=%d (%.1f tonnes)\n",way->weight,weight_to_tonnes(way->weight));
- if(way->height)
-    printf("  height=%d (%.1f m)\n",way->height,height_to_metres(way->height));
- if(way->width)
-    printf("  width=%d (%.1f m)\n",way->width,width_to_metres(way->width));
- if(way->length)
-    printf("  length=%d (%.1f m)\n",way->length,length_to_metres(way->length));
+ printf("  type=%02x (%s%s%s)\n",wayp->type,HighwayName(HIGHWAY(wayp->type)),wayp->type&Highway_OneWay?",One-Way":"",wayp->type&Highway_Roundabout?",Roundabout":"");
+ printf("  allow=%02x (%s)\n",wayp->allow,AllowedNameList(wayp->allow));
+ if(wayp->props)
+    printf("  props=%02x (%s)\n",wayp->props,PropertiesNameList(wayp->props));
+ if(wayp->speed)
+    printf("  speed=%d (%d km/hr)\n",wayp->speed,speed_to_kph(wayp->speed));
+ if(wayp->weight)
+    printf("  weight=%d (%.1f tonnes)\n",wayp->weight,weight_to_tonnes(wayp->weight));
+ if(wayp->height)
+    printf("  height=%d (%.1f m)\n",wayp->height,height_to_metres(wayp->height));
+ if(wayp->width)
+    printf("  width=%d (%.1f m)\n",wayp->width,width_to_metres(wayp->width));
+ if(wayp->length)
+    printf("  length=%d (%.1f m)\n",wayp->length,length_to_metres(wayp->length));
 }
 
 
@@ -467,42 +466,42 @@ static void print_way(Ways *ways,index_t item)
   Nodes *nodes The set of nodes to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static void print_turnrelation(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
+static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
 {
- Segment *segment;
- TurnRelation *relation=LookupTurnRelation(relations,item,1);
- Node *node=LookupNode(nodes,relation->via,1);
+ Segment *segmentp;
+ TurnRelation *relationp=LookupTurnRelation(relations,item,1);
+ Node *nodep=LookupNode(nodes,relationp->via,1);
  index_t from_way=NO_WAY,to_way=NO_WAY;
  index_t from_node=NO_NODE,to_node=NO_NODE;
 
- segment=FirstSegment(segments,node,1);
+ segmentp=FirstSegment(segments,nodep,1);
 
  do
    {
-    index_t seg=IndexSegment(segments,segment);
+    index_t seg=IndexSegment(segments,segmentp);
 
-    if(seg==relation->from)
+    if(seg==relationp->from)
       {
-       from_node=OtherNode(segment,relation->from);
-       from_way=segment->way;
+       from_node=OtherNode(segmentp,relationp->from);
+       from_way=segmentp->way;
       }
 
-    if(seg==relation->to)
+    if(seg==relationp->to)
       {
-       to_node=OtherNode(segment,relation->to);
-       to_way=segment->way;
+       to_node=OtherNode(segmentp,relationp->to);
+       to_way=segmentp->way;
       }
 
-    segment=NextSegment(segments,segment,relation->via);
+    segmentp=NextSegment(segments,segmentp,relationp->via);
    }
- while(segment);
+ while(segmentp);
 
  printf("Relation %"Pindex_t"\n",item);
- printf("  from=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relation->from,from_way,from_node);
- printf("  via=%"Pindex_t" (node)\n",relation->via);
- printf("  to=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relation->to,to_way,to_node);
- if(relation->except)
-    printf("  except=%02x (%s)\n",relation->except,AllowedNameList(relation->except));
+ printf("  from=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->from,from_way,from_node);
+ printf("  via=%"Pindex_t" (node)\n",relationp->via);
+ printf("  to=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->to,to_way,to_node);
+ if(relationp->except)
+    printf("  except=%02x (%s)\n",relationp->except,AllowedNameList(relationp->except));
 }
 
 
@@ -583,40 +582,40 @@ static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relation
 
        for(item=index1;item<index2;item++)
          {
-          Node *node=LookupNode(nodes,item,1);
-          double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
-          double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));
+          Node *nodep=LookupNode(nodes,item,1);
+          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));
 
           if(lat>latmin && lat<latmax && lon>lonmin && lon<lonmax)
             {
-             Segment *segment;
+             Segment *segmentp;
 
              print_node_osm(nodes,item);
 
-             segment=FirstSegment(segments,node,1);
+             segmentp=FirstSegment(segments,nodep,1);
 
-             while(segment)
+             while(segmentp)
                {
                 double olat,olon;
-                index_t oitem=OtherNode(segment,item);
+                index_t oitem=OtherNode(segmentp,item);
 
                 GetLatLong(nodes,oitem,&olat,&olon);
 
                 if(olat>latmin && olat<latmax && olon>lonmin && olon<lonmax)
                    if(item>oitem)
-                      if(!option_no_super || IsNormalSegment(segment))
-                         print_segment_osm(segments,IndexSegment(segments,segment),ways);
+                      if(!option_no_super || IsNormalSegment(segmentp))
+                         print_segment_osm(segments,IndexSegment(segments,segmentp),ways);
 
-                segment=NextSegment(segments,segment,item);
+                segmentp=NextSegment(segments,segmentp,item);
                }
 
-             if(IsTurnRestrictedNode(node))
+             if(IsTurnRestrictedNode(nodep))
                {
                 index_t relindex=FindFirstTurnRelation1(relations,item);
 
                 while(relindex!=NO_RELATION)
                   {
-                   print_turnrelation_osm(relations,relindex,segments,nodes);
+                   print_turn_relation_osm(relations,relindex,segments,nodes);
 
                    relindex=FindNextTurnRelation1(relations,relindex);
                   }
@@ -637,32 +636,32 @@ static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relation
 
 static void print_node_osm(Nodes *nodes,index_t item)
 {
- Node *node=LookupNode(nodes,item,1);
+ Node *nodep=LookupNode(nodes,item,1);
  double latitude,longitude;
  int i;
 
  GetLatLong(nodes,item,&latitude,&longitude);
 
- if(node->allow==Transports_ALL && node->flags==0)
+ if(nodep->allow==Transports_ALL && nodep->flags==0)
     printf("  <node id='%lu' lat='%.7f' lon='%.7f' version='1' />\n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
  else
    {
     printf("  <node id='%lu' lat='%.7f' lon='%.7f' version='1'>\n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
 
-    if(node->flags & NODE_SUPER)
+    if(nodep->flags & NODE_SUPER)
        printf("    <tag k='routino:super' v='yes' />\n");
 
-    if(node->flags & NODE_UTURN)
+    if(nodep->flags & NODE_UTURN)
        printf("    <tag k='routino:uturn' v='yes' />\n");
 
-    if(node->flags & NODE_MINIRNDBT)
+    if(nodep->flags & NODE_MINIRNDBT)
        printf("    <tag k='highway' v='mini_roundabout' />\n");
 
-    if(node->flags & NODE_TURNRSTRCT)
+    if(nodep->flags & NODE_TURNRSTRCT)
        printf("    <tag k='routino:turnrestriction' v='yes' />\n");
 
     for(i=1;i<Transport_Count;i++)
-       if(!(node->allow & TRANSPORTS(i)))
+       if(!(nodep->allow & TRANSPORTS(i)))
           printf("    <tag k='%s' v='no' />\n",TransportName(i));
 
     printf("  </node>\n");
@@ -682,61 +681,61 @@ static void print_node_osm(Nodes *nodes,index_t item)
 
 static void print_segment_osm(Segments *segments,index_t item,Ways *ways)
 {
- Segment *segment=LookupSegment(segments,item,1);
- Way *way=LookupWay(ways,segment->way,1);
- char *name=WayName(ways,way);
+ Segment *segmentp=LookupSegment(segments,item,1);
+ Way *wayp=LookupWay(ways,segmentp->way,1);
+ char *name=WayName(ways,wayp);
  int i;
 
  printf("  <way id='%lu' version='1'>\n",(unsigned long)item+1);
 
- if(IsOnewayTo(segment,segment->node1))
+ if(IsOnewayTo(segmentp,segmentp->node1))
    {
-    printf("    <nd ref='%lu' />\n",(unsigned long)segment->node2+1);
-    printf("    <nd ref='%lu' />\n",(unsigned long)segment->node1+1);
+    printf("    <nd ref='%lu' />\n",(unsigned long)segmentp->node2+1);
+    printf("    <nd ref='%lu' />\n",(unsigned long)segmentp->node1+1);
    }
  else
    {
-    printf("    <nd ref='%lu' />\n",(unsigned long)segment->node1+1);
-    printf("    <nd ref='%lu' />\n",(unsigned long)segment->node2+1);
+    printf("    <nd ref='%lu' />\n",(unsigned long)segmentp->node1+1);
+    printf("    <nd ref='%lu' />\n",(unsigned long)segmentp->node2+1);
    }
 
- if(IsSuperSegment(segment))
+ if(IsSuperSegment(segmentp))
     printf("    <tag k='routino:super' v='yes' />\n");
- if(IsNormalSegment(segment))
+ if(IsNormalSegment(segmentp))
     printf("    <tag k='routino:normal' v='yes' />\n");
 
- printf("    <tag k='routino:distance' v='%.3f' />\n",distance_to_km(DISTANCE(segment->distance)));
+ printf("    <tag k='routino:distance' v='%.3f' />\n",distance_to_km(DISTANCE(segmentp->distance)));
 
- if(way->type & Way_OneWay)
+ if(wayp->type & Highway_OneWay)
     printf("    <tag k='oneway' v='yes' />\n");
 
- if(way->type & Way_Roundabout)
+ if(wayp->type & Highway_Roundabout)
     printf("    <tag k='roundabout' v='yes' />\n");
 
- printf("    <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(way->type)));
+ printf("    <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(wayp->type)));
 
- if(IsNormalSegment(segment) && *name)
+ if(IsNormalSegment(segmentp) && *name)
     printf("    <tag k='name' v='%s' />\n",ParseXML_Encode_Safe_XML(name));
 
  for(i=1;i<Transport_Count;i++)
-    if(way->allow & TRANSPORTS(i))
+    if(wayp->allow & TRANSPORTS(i))
        printf("    <tag k='%s' v='yes' />\n",TransportName(i));
 
  for(i=1;i<Property_Count;i++)
-    if(way->props & PROPERTIES(i))
+    if(wayp->props & PROPERTIES(i))
        printf("    <tag k='%s' v='yes' />\n",PropertyName(i));
 
- if(way->speed)
-    printf("    <tag k='maxspeed' v='%d' />\n",speed_to_kph(way->speed));
+ if(wayp->speed)
+    printf("    <tag k='maxspeed' v='%d' />\n",speed_to_kph(wayp->speed));
 
- if(way->weight)
-    printf("    <tag k='maxweight' v='%.1f' />\n",weight_to_tonnes(way->weight));
- if(way->height)
-    printf("    <tag k='maxheight' v='%.1f' />\n",height_to_metres(way->height));
- if(way->width)
-    printf("    <tag k='maxwidth' v='%.1f' />\n",width_to_metres(way->width));
- if(way->length)
-    printf("    <tag k='maxlength' v='%.1f' />\n",length_to_metres(way->length));
+ if(wayp->weight)
+    printf("    <tag k='maxweight' v='%.1f' />\n",weight_to_tonnes(wayp->weight));
+ if(wayp->height)
+    printf("    <tag k='maxheight' v='%.1f' />\n",height_to_metres(wayp->height));
+ if(wayp->width)
+    printf("    <tag k='maxwidth' v='%.1f' />\n",width_to_metres(wayp->width));
+ if(wayp->length)
+    printf("    <tag k='maxlength' v='%.1f' />\n",length_to_metres(wayp->length));
 
  printf("  </way>\n");
 }
@@ -754,14 +753,14 @@ static void print_segment_osm(Segments *segments,index_t item,Ways *ways)
   Nodes *nodes The set of nodes to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static void print_turnrelation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
+static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
 {
- TurnRelation *relation=LookupTurnRelation(relations,item,1);
+ TurnRelation *relationp=LookupTurnRelation(relations,item,1);
 
- Segment *segment_from=LookupSegment(segments,relation->from,1);
- Segment *segment_to  =LookupSegment(segments,relation->to  ,2);
+ Segment *segmentp_from=LookupSegment(segments,relationp->from,1);
+ Segment *segmentp_to  =LookupSegment(segments,relationp->to  ,2);
 
- double angle=TurnAngle(nodes,segment_from,segment_to,relation->via);
+ double angle=TurnAngle(nodes,segmentp_from,segmentp_to,relationp->via);
 
  char *restriction;
 
@@ -778,12 +777,12 @@ static void print_turnrelation_osm(Relations *relations,index_t item,Segments *s
  printf("    <tag k='type' v='restriction' />\n");
  printf("    <tag k='restriction' v='%s'/>\n",restriction);
 
- if(relation->except)
-    printf("    <tag k='except' v='%s' />\n",AllowedNameList(relation->except));
+ if(relationp->except)
+    printf("    <tag k='except' v='%s' />\n",AllowedNameList(relationp->except));
 
- printf("    <member type='way' ref='%lu' role='from' />\n",(unsigned long)relation->from+1);
- printf("    <member type='node' ref='%lu' role='via' />\n",(unsigned long)relation->via+1);
- printf("    <member type='way' ref='%lu' role='to' />\n",(unsigned long)relation->to+1);
+ printf("    <member type='way' ref='%lu' role='from' />\n",(unsigned long)relationp->from+1);
+ printf("    <member type='node' ref='%lu' role='via' />\n",(unsigned long)relationp->via+1);
+ printf("    <member type='way' ref='%lu' role='to' />\n",(unsigned long)relationp->to+1);
 
  printf("  </relation>\n");
 }
@@ -864,7 +863,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
          "                                --data=<data-type>]\n"
          "                  [--dump [--node=<node> ...]\n"
          "                          [--segment=<segment> ...]\n"
-         "                          [--way=<way> ...]]\n"
+         "                          [--way=<way> ...]\n"
          "                          [--turn-relation=<rel> ...]]\n"
          "                  [--dump-osm [--no-super]\n"
          "                              [--latmin=<latmin> --latmax=<latmax>\n"
diff --git a/src/filedumperx.c b/src/filedumperx.c
new file mode 100644
index 0000000..5043284
--- /dev/null
+++ b/src/filedumperx.c
@@ -0,0 +1,397 @@
+/***************************************
+ Memory file dumper for the intermediate files containing parsed data.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2012 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "files.h"
+#include "sorting.h"
+
+
+/* Local functions */
+
+static void print_nodes(const char *filename);
+static void print_segments(const char *filename);
+static void print_ways(const char *filename);
+static void print_route_relations(const char *filename);
+static void print_turn_relations(const char *filename);
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the file dumper.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ int   arg;
+ char *dirname=NULL,*prefix=NULL;
+ char *nodes_filename,*segments_filename,*ways_filename,*route_relations_filename,*turn_relations_filename;
+ int   option_dump;
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--prefix=",9))
+       prefix=&argv[arg][9];
+    else if(!strcmp(argv[arg],"--dump"))
+       option_dump=1;
+    else if(!strcmp(argv[arg],"--nodes"))
+       ;
+    else if(!strcmp(argv[arg],"--segments"))
+       ;
+    else if(!strcmp(argv[arg],"--ways"))
+       ;
+    else if(!strcmp(argv[arg],"--route-relations"))
+       ;
+    else if(!strcmp(argv[arg],"--turn-relations"))
+       ;
+    else
+       print_usage(0,argv[arg],NULL);
+   }
+
+ if((option_dump)!=1)
+    print_usage(0,NULL,"Must choose --dump.");
+
+ /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
+
+ nodes_filename=FileName(dirname,prefix,"nodesx.parsed.mem");
+
+ segments_filename=FileName(dirname,prefix,"segmentsx.parsed.mem");
+
+ ways_filename=FileName(dirname,prefix,"waysx.parsed.mem");
+
+ route_relations_filename=FileName(dirname,prefix,"relationsx.route.parsed.mem");
+
+ turn_relations_filename=FileName(dirname,prefix,"relationsx.turn.parsed.mem");
+
+ /* Print out internal data (in plain text format) */
+
+ if(option_dump)
+   {
+    for(arg=1;arg<argc;arg++)
+       if(!strcmp(argv[arg],"--nodes"))
+         {
+          print_nodes(nodes_filename);
+         }
+       else if(!strcmp(argv[arg],"--segments"))
+         {
+          print_segments(segments_filename);
+         }
+       else if(!strcmp(argv[arg],"--ways"))
+         {
+          print_ways(ways_filename);
+         }
+       else if(!strcmp(argv[arg],"--route-relations"))
+         {
+          print_route_relations(route_relations_filename);
+         }
+       else if(!strcmp(argv[arg],"--turn-relations"))
+         {
+          print_turn_relations(turn_relations_filename);
+         }
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the nodes.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_nodes(const char *filename)
+{
+ off_t size,position=0;
+ int fd;
+
+ size=SizeFile(filename);
+
+ fd=ReOpenFile(filename);
+
+ while(position<size)
+   {
+    NodeX nodex;
+
+    ReadFile(fd,&nodex,sizeof(NodeX));
+
+    printf("Node %"Pnode_t"\n",nodex.id);
+    printf("  lat=%d lon=%d\n",nodex.latitude,nodex.longitude);
+    printf("  allow=%02x\n",nodex.allow);
+    printf("  flags=%02x\n",nodex.flags);
+
+    position+=sizeof(NodeX);
+   }
+
+ CloseFile(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the segments.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_segments(const char *filename)
+{
+ off_t size,position=0;
+ int fd;
+
+ size=SizeFile(filename);
+
+ fd=ReOpenFile(filename);
+
+ while(position<size)
+   {
+    SegmentX segmentx;
+
+    ReadFile(fd,&segmentx,sizeof(SegmentX));
+
+    printf("Segment\n");
+    printf("  node1=%"Pnode_t" node2=%"Pnode_t"\n",segmentx.node1,segmentx.node2);
+    printf("  way=%"Pway_t"\n",segmentx.way);
+    if(segmentx.distance&SEGMENT_AREA)
+       printf("  Part of area\n");
+    if(segmentx.distance&ONEWAY_1TO2)
+       printf("  One-way (forward)\n");
+    if(segmentx.distance&ONEWAY_2TO1)
+       printf("  One-way (reverse)\n");
+
+    position+=sizeof(SegmentX);
+   }
+
+ CloseFile(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the ways.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_ways(const char *filename)
+{
+ off_t size,position=0;
+ int fd;
+
+ size=SizeFile(filename);
+
+ fd=ReOpenFile(filename);
+
+ while(position<size)
+   {
+    FILESORT_VARINT waysize;
+    WayX wayx;
+    char *name=NULL;
+    int malloced=0;
+
+    ReadFile(fd,&waysize,FILESORT_VARSIZE);
+
+    ReadFile(fd,&wayx,sizeof(WayX));
+
+    if(malloced<(waysize-sizeof(WayX)))
+      {
+       malloced=(waysize-sizeof(WayX));
+       name=(char*)realloc((void*)name,malloced);
+      }
+
+    ReadFile(fd,name,(waysize-sizeof(WayX)));
+
+    printf("Way %"Pway_t"\n",wayx.id);
+    if(*name)
+       printf("  name=%s\n",name);
+    printf("  type=%02x\n",wayx.way.type);
+    printf("  allow=%02x\n",wayx.way.allow);
+    if(wayx.way.props)
+       printf("  props=%02x\n",wayx.way.props);
+    if(wayx.way.speed)
+       printf("  speed=%d\n",wayx.way.speed);
+    if(wayx.way.weight)
+       printf("  weight=%d\n",wayx.way.weight);
+    if(wayx.way.height)
+       printf("  height=%d\n",wayx.way.height);
+    if(wayx.way.width)
+       printf("  width=%d\n",wayx.way.width);
+    if(wayx.way.length)
+       printf("  length=%d\n",wayx.way.length);
+
+    position+=waysize+FILESORT_VARSIZE;
+   }
+
+ CloseFile(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the route relations.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_route_relations(const char *filename)
+{
+ off_t size,position=0;
+ int fd;
+
+ size=SizeFile(filename);
+
+ fd=ReOpenFile(filename);
+
+ while(position<size)
+   {
+    FILESORT_VARINT relationsize;
+    RouteRelX relationx;
+    way_t wayid;
+    relation_t relationid;
+
+    ReadFile(fd,&relationsize,FILESORT_VARSIZE);
+
+    ReadFile(fd,&relationx,sizeof(RouteRelX));
+
+    printf("Relation %"Prelation_t"\n",relationx.id);
+    printf("  routes=%02x\n",relationx.routes);
+
+    do
+      {
+       ReadFile(fd,&wayid,sizeof(way_t));
+
+       printf("  way=%"Pway_t"\n",wayid);
+      }
+    while(wayid!=NO_WAY_ID);
+
+    do
+      {
+       ReadFile(fd,&relationid,sizeof(relation_t));
+
+       printf("  relation=%"Prelation_t"\n",relationid);
+      }
+    while(relationid!=NO_RELATION_ID);
+
+    position+=relationsize+FILESORT_VARSIZE;
+   }
+
+ CloseFile(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the turn relations.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_turn_relations(const char *filename)
+{
+ off_t size,position=0;
+ int fd;
+
+ size=SizeFile(filename);
+
+ fd=ReOpenFile(filename);
+
+ while(position<size)
+   {
+    TurnRelX relationx;
+
+    ReadFile(fd,&relationx,sizeof(TurnRelX));
+
+    printf("Relation %"Prelation_t"\n",relationx.id);
+    printf("  from=%"Pway_t"\n",relationx.from);
+    printf("  via=%"Pnode_t"\n",relationx.via);
+    printf("  to=%"Pway_t"\n",relationx.to);
+    printf("  type=%d\n",relationx.restriction);
+    if(relationx.except)
+       printf("  except=%02x\n",relationx.except);
+
+    position+=sizeof(TurnRelX);
+   }
+
+ CloseFile(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: filedumper [--help]\n"
+         "                  [--dir=<dirname>] [--prefix=<name>]\n"
+         "                  [--dump [--nodes]\n"
+         "                          [--segments]\n"
+         "                          [--ways]\n"
+         "                          [--route-relations]\n"
+         "                          [--turn-relations]]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the routing database.\n"
+            "--prefix=<name>           The filename prefix for the routing database.\n"
+            "\n"
+            "--dump                    Dump the intermediate files after parsing.\n"
+            "  --nodes                 * all of the nodes.\n"
+            "  --segments              * all of the segments.\n"
+            "  --ways                  * all of the ways.\n"
+            "  --route-relations       * all of the route relations.\n"
+            "  --turn-relations        * all of the turn relations.\n");
+
+ exit(!detail);
+}
diff --git a/src/files.c b/src/files.c
index 2508954..ec78d5e 100644
--- a/src/files.c
+++ b/src/files.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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
@@ -170,20 +170,20 @@ void *MapFileWriteable(const char *filename)
 
   void *UnmapFile Returns NULL (for similarity to the MapFile function).
 
-  const char *filename The name of the file when it was opened.
+  const void *address The address of the mapped file in memory.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void *UnmapFile(const char *filename)
+void *UnmapFile(const void *address)
 {
  int i;
 
  for(i=0;i<nmappedfiles;i++)
-    if(!strcmp(mappedfiles[i].filename,filename))
+    if(mappedfiles[i].address==address)
        break;
 
  if(i==nmappedfiles)
    {
-    fprintf(stderr,"The file '%s' was not mapped using MapFile().\n",filename);
+    fprintf(stderr,"The data at address %p was not mapped using MapFile().\n",address);
     exit(EXIT_FAILURE);
    }
 
@@ -372,12 +372,30 @@ int CloseFile(int fd)
 
   int DeleteFile Returns 0 if OK.
 
-  char *filename The name of the file to delete.
+  const char *filename The name of the file to delete.
   ++++++++++++++++++++++++++++++++++++++*/
 
-int DeleteFile(char *filename)
+int DeleteFile(const char *filename)
 {
  unlink(filename);
 
  return(0);
 }
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Rename a file on disk.
+
+  int RenameFile Returns 0 if OK.
+
+  const char *oldfilename The old name of the file before renaming.
+
+  const char *newfilename The new name of the file after renaming.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int RenameFile(const char *oldfilename,const char *newfilename)
+{
+ rename(oldfilename,newfilename);
+
+ return(0);
+}
diff --git a/src/files.h b/src/files.h
index c96469e..1f66c87 100644
--- a/src/files.h
+++ b/src/files.h
@@ -29,10 +29,11 @@
 #define HAVE_PREAD_PWRITE 1
 
 
-#include <assert.h>
 #include <unistd.h>
 #include <sys/types.h>
 
+#include "logging.h"
+
 
 /* Functions in files.c */
 
@@ -40,7 +41,7 @@ char *FileName(const char *dirname,const char *prefix, const char *name);
 
 void *MapFile(const char *filename);
 void *MapFileWriteable(const char *filename);
-void *UnmapFile(const char *filename);
+void *UnmapFile(const void *address);
 
 int OpenFileNew(const char *filename);
 int OpenFileAppend(const char *filename);
@@ -60,7 +61,9 @@ static int SeekFile(int fd,off_t position);
 
 int CloseFile(int fd);
 
-int DeleteFile(char *filename);
+int DeleteFile(const char *filename);
+
+int RenameFile(const char *oldfilename,const char *newfilename);
 
 
 /* Inline the frequently called functions */
@@ -79,7 +82,7 @@ int DeleteFile(char *filename);
 
 static inline int WriteFile(int fd,const void *address,size_t length)
 {
- assert(fd!=-1);
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
 
  /* Write the data */
 
@@ -104,7 +107,7 @@ static inline int WriteFile(int fd,const void *address,size_t length)
 
 static inline int ReadFile(int fd,void *address,size_t length)
 {
- assert(fd!=-1);
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
 
  /* Read the data */
 
@@ -127,7 +130,7 @@ static inline int ReadFile(int fd,void *address,size_t length)
 
 static inline int SeekFile(int fd,off_t position)
 {
- assert(fd!=-1);
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
 
  /* Seek the data */
 
@@ -154,7 +157,7 @@ static inline int SeekFile(int fd,off_t position)
 
 static inline int SeekWriteFile(int fd,const void *address,size_t length,off_t position)
 {
- assert(fd!=-1);
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
 
  /* Seek and write the data */
 
@@ -193,7 +196,7 @@ static inline int SeekWriteFile(int fd,const void *address,size_t length,off_t p
 
 static inline int SeekReadFile(int fd,void *address,size_t length,off_t position)
 {
- assert(fd!=-1);
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
 
  /* Seek and read the data */
 
diff --git a/src/logging.c b/src/logging.c
index f7ef664..94174ae 100644
--- a/src/logging.c
+++ b/src/logging.c
@@ -241,7 +241,7 @@ static void vfprintf_middle(FILE *file,const char *format,va_list ap)
 {
  int retval;
 
- putchar('\r');
+ fputc('\r',file);
 
  if(option_logtime)
     fprintf_elapsed_time(file,&start_time);
@@ -254,7 +254,7 @@ static void vfprintf_middle(FILE *file,const char *format,va_list ap)
     int new_printed_length=retval;
 
     while(retval++<printed_length)
-       putchar(' ');
+       fputc(' ',file);
 
     printed_length=new_printed_length;
    }
@@ -276,7 +276,7 @@ static void vfprintf_last(FILE *file,const char *format,va_list ap)
  int retval;
 
  if(!option_loggable)
-    putchar('\r');
+    fputc('\r',file);
 
  if(option_logtime)
     fprintf_elapsed_time(file,&start_time);
@@ -285,9 +285,9 @@ static void vfprintf_last(FILE *file,const char *format,va_list ap)
 
  if(retval>0)
     while(retval++<printed_length)
-       putchar(' ');
+       fputc(' ',file);
 
- putchar('\n');
+ fputc('\n',file);
  fflush(file);
 }
 
@@ -370,3 +370,21 @@ void logerror(const char *format, ...)
 
  va_end(ap);
 }
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Log a fatal error and exit
+
+  const char *message The error message.
+
+  const char *file The file in which the error occured.
+
+  int line The line number in the file at which the error occured.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void _logassert(const char *message,const char *file,int line)
+{
+ fprintf(stderr,"Routino Fatal Error (%s:%d): %s\n",file,line,message);
+
+ exit(EXIT_FAILURE);
+}
diff --git a/src/logging.h b/src/logging.h
index 58024ac..8857316 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -75,4 +75,11 @@ void logerror(const char *format, ...);
 #endif
 
 
+/* Runtime fatal error assertion */
+
+#define logassert(xx,yy) do{ if(!(xx)) _logassert(yy,__FILE__,__LINE__); } while(0);
+
+void _logassert(const char *message,const char *file,int line);
+
+
 #endif /* LOGGING_H */
diff --git a/src/nodes.c b/src/nodes.c
index 2baae3f..9b693a1 100644
--- a/src/nodes.c
+++ b/src/nodes.c
@@ -34,7 +34,7 @@
 
 /* Local functions */
 
-static int valid_segment_for_profile(Ways *ways,Segment *segment,Profile *profile);
+static int valid_segment_for_profile(Ways *ways,Segment *segmentp,Profile *profile);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -194,23 +194,23 @@ index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitu
 
           for(i=index1;i<index2;i++)
             {
-             Node *node=LookupNode(nodes,i,3);
-             double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
-             double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));
+             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));
 
              distance_t dist=Distance(lat,lon,latitude,longitude);
 
              if(dist<distance)
                {
-                Segment *segment;
+                Segment *segmentp;
 
                 /* Check that at least one segment is valid for the profile */
 
-                segment=FirstSegment(segments,node,1);
+                segmentp=FirstSegment(segments,nodep,1);
 
                 do
                   {
-                   if(IsNormalSegment(segment) && valid_segment_for_profile(ways,segment,profile))
+                   if(IsNormalSegment(segmentp) && valid_segment_for_profile(ways,segmentp,profile))
                      {
                       bestn=i;
                       bestd=distance=dist;
@@ -218,9 +218,9 @@ index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitu
                       break;
                      }
 
-                   segment=NextSegment(segments,segment,i);
+                   segmentp=NextSegment(segments,segmentp,i);
                   }
-                while(segment);
+                while(segmentp);
                }
             }
 
@@ -350,29 +350,29 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
 
           for(i=index1;i<index2;i++)
             {
-             Node *node=LookupNode(nodes,i,3);
-             double lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
-             double lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));
+             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));
              distance_t dist1;
 
              dist1=Distance(lat1,lon1,latitude,longitude);
 
              if(dist1<distance)
                {
-                Segment *segment;
+                Segment *segmentp;
 
                 /* Check each segment for closeness and if valid for the profile */
 
-                segment=FirstSegment(segments,node,1);
+                segmentp=FirstSegment(segments,nodep,1);
 
                 do
                   {
-                   if(IsNormalSegment(segment) && valid_segment_for_profile(ways,segment,profile))
+                   if(IsNormalSegment(segmentp) && valid_segment_for_profile(ways,segmentp,profile))
                      {
                       distance_t dist2,dist3;
                       double lat2,lon2,dist3a,dist3b,distp;
 
-                      GetLatLong(nodes,OtherNode(segment,i),&lat2,&lon2);
+                      GetLatLong(nodes,OtherNode(segmentp,i),&lat2,&lon2);
 
                       dist2=Distance(lat2,lon2,latitude,longitude);
 
@@ -404,18 +404,18 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
 
                       if(distp<(double)bestd)
                         {
-                         bests=IndexSegment(segments,segment);
+                         bests=IndexSegment(segments,segmentp);
 
-                         if(segment->node1==i)
+                         if(segmentp->node1==i)
                            {
                             bestn1=i;
-                            bestn2=OtherNode(segment,i);
+                            bestn2=OtherNode(segmentp,i);
                             bestd1=(distance_t)dist3a;
                             bestd2=(distance_t)dist3b;
                            }
                          else
                            {
-                            bestn1=OtherNode(segment,i);
+                            bestn1=OtherNode(segmentp,i);
                             bestn2=i;
                             bestd1=(distance_t)dist3b;
                             bestd2=(distance_t)dist3a;
@@ -425,9 +425,9 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
                         }
                      }
 
-                   segment=NextSegment(segments,segment,i);
+                   segmentp=NextSegment(segments,segmentp,i);
                   }
-                while(segment);
+                while(segmentp);
                }
 
             } /* dist1 < distance */
@@ -458,37 +458,37 @@ index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double lat
 
   Ways *ways The set of ways to use.
 
-  Segment *segment The segment to check.
+  Segment *segmentp The segment to check.
 
   Profile *profile The profile to check.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int valid_segment_for_profile(Ways *ways,Segment *segment,Profile *profile)
+static int valid_segment_for_profile(Ways *ways,Segment *segmentp,Profile *profile)
 {
- Way *way=LookupWay(ways,segment->way,1);
+ Way *wayp=LookupWay(ways,segmentp->way,1);
  score_t segment_pref;
  int i;
 
  /* mode of transport must be allowed on the highway */
- if(!(way->allow&profile->allow))
+ if(!(wayp->allow&profile->allow))
     return(0);
 
  /* must obey weight restriction (if exists) */
- if(way->weight && way->weight<profile->weight)
+ if(wayp->weight && wayp->weight<profile->weight)
     return(0);
 
  /* must obey height/width/length restriction (if exists) */
- if((way->height && way->height<profile->height) ||
-    (way->width  && way->width <profile->width ) ||
-    (way->length && way->length<profile->length))
+ if((wayp->height && wayp->height<profile->height) ||
+    (wayp->width  && wayp->width <profile->width ) ||
+    (wayp->length && wayp->length<profile->length))
     return(0);
 
- segment_pref=profile->highway[HIGHWAY(way->type)];
+ segment_pref=profile->highway[HIGHWAY(wayp->type)];
 
  for(i=1;i<Property_Count;i++)
     if(ways->file.props & PROPERTIES(i))
       {
-       if(way->props & PROPERTIES(i))
+       if(wayp->props & PROPERTIES(i))
           segment_pref*=profile->props_yes[i];
        else
           segment_pref*=profile->props_no[i];
@@ -517,7 +517,7 @@ static int valid_segment_for_profile(Ways *ways,Segment *segment,Profile *profil
 
 void GetLatLong(Nodes *nodes,index_t index,double *latitude,double *longitude)
 {
- Node *node=LookupNode(nodes,index,4);
+ Node *nodep=LookupNode(nodes,index,4);
  ll_bin_t latbin=-1,lonbin=-1;
  ll_bin_t start,end,mid;
  index_t offset;
@@ -603,6 +603,6 @@ void GetLatLong(Nodes *nodes,index_t index,double *latitude,double *longitude)
 
  /* Return the values */
 
- *latitude =latlong_to_radians(bin_to_latlong(nodes->file.latzero+latbin)+off_to_latlong(node->latoffset));
- *longitude=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonbin)+off_to_latlong(node->lonoffset));
+ *latitude =latlong_to_radians(bin_to_latlong(nodes->file.latzero+latbin)+off_to_latlong(nodep->latoffset));
+ *longitude=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonbin)+off_to_latlong(nodep->lonoffset));
 }
diff --git a/src/nodes.h b/src/nodes.h
index a7ffb20..faf416a 100644
--- a/src/nodes.h
+++ b/src/nodes.h
@@ -44,7 +44,7 @@ struct _Node
  ll_off_t     lonoffset;        /*+ The node longitude offset within its bin. +*/
 
  transports_t allow;            /*+ The types of transport that are allowed through the node. +*/
- uint16_t     flags;            /*+ Flags containing extra information (e.g. super-node, turn restriction). +*/
+ nodeflags_t  flags;            /*+ Flags containing extra information (e.g. super-node, turn restriction). +*/
 };
 
 
diff --git a/src/nodesx.c b/src/nodesx.c
index bd62f96..1b74bba 100644
--- a/src/nodesx.c
+++ b/src/nodesx.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -37,21 +36,24 @@
 #include "sorting.h"
 
 
-/* Variables */
+/* Global variables */
 
 /*+ The command line '--tmpdir' option or its default value. +*/
 extern char *option_tmpdirname;
 
-/*+ A temporary file-local variable for use by the sort functions. +*/
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions. +*/
 static NodesX *sortnodesx;
+static latlong_t lat_min,lat_max,lon_min,lon_max;
 
-/* Functions */
+/* Local functions */
 
 static int sort_by_id(NodeX *a,NodeX *b);
 static int deduplicate_and_index_by_id(NodeX *nodex,index_t index);
 
 static int sort_by_lat_long(NodeX *a,NodeX *b);
-static int delete_pruned_and_index_by_lat_long(NodeX *nodex,index_t index);
+static int index_by_lat_long(NodeX *nodex,index_t index);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -59,36 +61,43 @@ static int delete_pruned_and_index_by_lat_long(NodeX *nodex,index_t index);
 
   NodesX *NewNodeList Returns a pointer to the node list.
 
-  int append Set to 1 if the file is to be opened for appending (now or later).
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
   ++++++++++++++++++++++++++++++++++++++*/
 
-NodesX *NewNodeList(int append)
+NodesX *NewNodeList(int append,int readonly)
 {
  NodesX *nodesx;
 
  nodesx=(NodesX*)calloc(1,sizeof(NodesX));
 
- assert(nodesx); /* Check calloc() worked */
+ logassert(nodesx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
 
- nodesx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
+ nodesx->filename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ nodesx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- if(append)
-    sprintf(nodesx->filename,"%s/nodesx.input.tmp",option_tmpdirname);
- else
-    sprintf(nodesx->filename,"%s/nodesx.%p.tmp",option_tmpdirname,(void*)nodesx);
+ sprintf(nodesx->filename    ,"%s/nodesx.parsed.mem",option_tmpdirname);
+ sprintf(nodesx->filename_tmp,"%s/nodesx.%p.tmp"    ,option_tmpdirname,(void*)nodesx);
 
- if(append)
-   {
-    off_t size;
+ if(append || readonly)
+    if(ExistsFile(nodesx->filename))
+      {
+       off_t size;
 
-    nodesx->fd=OpenFileAppend(nodesx->filename);
+       size=SizeFile(nodesx->filename);
 
-    size=SizeFile(nodesx->filename);
+       nodesx->number=size/sizeof(NodeX);
 
-    nodesx->number=size/sizeof(NodeX);
-   }
+       RenameFile(nodesx->filename,nodesx->filename_tmp);
+      }
+
+ if(append)
+    nodesx->fd=OpenFileAppend(nodesx->filename_tmp);
+ else if(!readonly)
+    nodesx->fd=OpenFileNew(nodesx->filename_tmp);
  else
-    nodesx->fd=OpenFileNew(nodesx->filename);
+    nodesx->fd=-1;
 
  return(nodesx);
 }
@@ -99,15 +108,18 @@ NodesX *NewNodeList(int append)
 
   NodesX *nodesx The set of nodes to be freed.
 
-  int keep Set to 1 if the file is to be kept (for appending later).
+  int keep If set then the results file is to be kept.
   ++++++++++++++++++++++++++++++++++++++*/
 
 void FreeNodeList(NodesX *nodesx,int keep)
 {
- if(!keep)
-    DeleteFile(nodesx->filename);
+ if(keep)
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+ else
+    DeleteFile(nodesx->filename_tmp);
 
  free(nodesx->filename);
+ free(nodesx->filename_tmp);
 
  if(nodesx->idata)
     free(nodesx->idata);
@@ -115,6 +127,9 @@ void FreeNodeList(NodesX *nodesx,int keep)
  if(nodesx->gdata)
     free(nodesx->gdata);
 
+ if(nodesx->pdata)
+    free(nodesx->pdata);
+
  if(nodesx->super)
     free(nodesx->super);
 
@@ -135,10 +150,10 @@ void FreeNodeList(NodesX *nodesx,int keep)
 
   transports_t allow The allowed traffic types through the node.
 
-  uint16_t flags The flags to set for this node.
+  nodeflags_t flags The flags to set for this node.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void AppendNode(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,uint16_t flags)
+void AppendNodeList(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,nodeflags_t flags)
 {
  NodeX nodex;
 
@@ -152,7 +167,79 @@ void AppendNode(NodesX *nodesx,node_t id,double latitude,double longitude,transp
 
  nodesx->number++;
 
- assert(nodesx->number<NODE_FAKE); /* NODE_FAKE marks the high-water mark for real nodes. */
+ logassert(nodesx->number<NODE_FAKE,"Too many nodes (change index_t to 64-bits?)"); /* NODE_FAKE marks the high-water mark for real nodes. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending nodes and change the filename over.
+
+  NodesX *nodesx The nodes that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishNodeList(NodesX *nodesx)
+{
+ if(nodesx->fd!=-1)
+    nodesx->fd=CloseFile(nodesx->fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular node index.
+
+  index_t IndexNodeX Returns the index of the extended node with the specified id.
+
+  NodesX *nodesx The set of nodes to use.
+
+  node_t id The node id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexNodeX(NodesX *nodesx,node_t id)
+{
+ index_t start=0;
+ index_t end=nodesx->number-1;
+ index_t mid;
+
+ if(nodesx->number==0)          /* No nodes */
+    return(NO_NODE);
+
+ if(id<nodesx->idata[start])    /* Key is before start */
+    return(NO_NODE);
+
+ if(id>nodesx->idata[end])      /* Key is after end */
+    return(NO_NODE);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;             /* Choose mid point */
+
+    if(nodesx->idata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(nodesx->idata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                           /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(nodesx->idata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(nodesx->idata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_NODE);
 }
 
 
@@ -171,32 +258,29 @@ void SortNodeList(NodesX *nodesx)
 
  printf_first("Sorting Nodes");
 
- /* Close the file (finished appending) */
-
- nodesx->fd=CloseFile(nodesx->fd);
-
  /* Re-open the file read-only and a new file writeable */
 
- nodesx->fd=ReOpenFile(nodesx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
 
- DeleteFile(nodesx->filename);
+ DeleteFile(nodesx->filename_tmp);
 
- fd=OpenFileNew(nodesx->filename);
+ fd=OpenFileNew(nodesx->filename_tmp);
 
  /* Allocate the array of indexes */
 
  nodesx->idata=(node_t*)malloc(nodesx->number*sizeof(node_t));
 
- assert(nodesx->idata); /* Check malloc() worked */
+ logassert(nodesx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
- /* Sort by node indexes */
+ /* Sort the nodes by ID and index them */
 
  xnumber=nodesx->number;
- nodesx->number=0;
 
  sortnodesx=nodesx;
 
- nodesx->number=filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))deduplicate_and_index_by_id);
+ nodesx->number=filesort_fixed(nodesx->fd,fd,sizeof(NodeX),NULL,
+                                                           (int (*)(const void*,const void*))sort_by_id,
+                                                           (int (*)(void*,index_t))deduplicate_and_index_by_id);
 
  /* Close the files */
 
@@ -229,7 +313,7 @@ static int sort_by_id(NodeX *a,NodeX *b)
  else if(a_id>b_id)
     return(1);
  else
-    return(0);
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
 }
 
 
@@ -240,236 +324,189 @@ static int sort_by_id(NodeX *a,NodeX *b)
 
   NodeX *nodex The extended node.
 
-  index_t index The index of this node in the total.
+  index_t index The number of sorted nodes that have already been written to the output file.
   ++++++++++++++++++++++++++++++++++++++*/
 
 static int deduplicate_and_index_by_id(NodeX *nodex,index_t index)
 {
- if(index==0 || sortnodesx->idata[index-1]!=nodex->id)
+ static node_t previd=NO_NODE_ID;
+
+ if(nodex->id!=previd)
    {
-    sortnodesx->idata[index]=nodex->id;
+    previd=nodex->id;
 
-    return(1);
+    if(nodex->flags&NODE_DELETED)
+       return(0);
+    else
+      {
+       sortnodesx->idata[index]=nodex->id;
+
+       return(1);
+      }
    }
  else
-   {
-    logerror("Node %"Pnode_t" is duplicated\n",nodex->id);
-
     return(0);
-   }
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the node list geographically.
+  Remove any nodes that are not part of a highway.
 
   NodesX *nodesx The set of nodes to modify.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void SortNodeListGeographically(NodesX *nodesx)
+void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,int keep)
 {
+ NodeX nodex;
+ index_t total=0,highway=0,nothighway=0;
  int fd;
- index_t kept;
 
  /* Print the start message */
 
- printf_first("Sorting Nodes Geographically (Deleting Pruned)");
+ printf_first("Checking Nodes: Nodes=0");
 
- /* Allocate the memory for the geographical index array */
+ /* Re-open the file read-only and a new file writeable */
 
- nodesx->gdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
 
- assert(nodesx->gdata); /* Check malloc() worked */
+ if(keep)
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+ else
+    DeleteFile(nodesx->filename_tmp);
 
- /* Re-open the file read-only and a new file writeable */
+ fd=OpenFileNew(nodesx->filename_tmp);
 
- nodesx->fd=ReOpenFile(nodesx->filename);
+ /* Modify the on-disk image */
 
- DeleteFile(nodesx->filename);
+ while(!ReadFile(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+    if(!IsBitSet(segmentsx->usednode,total))
+       nothighway++;
+    else
+      {
+       nodex.id=highway;
+       nodesx->idata[highway]=nodesx->idata[total];
 
- fd=OpenFileNew(nodesx->filename);
+       WriteFile(fd,&nodex,sizeof(NodeX));
 
- /* Sort geographically */
+       highway++;
+      }
 
- sortnodesx=nodesx;
+    total++;
 
- kept=filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_lat_long,(int (*)(void*,index_t))delete_pruned_and_index_by_lat_long);
+    if(!(total%10000))
+       printf_middle("Checking Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+   }
+
+ nodesx->number=highway;
 
  /* Close the files */
 
  nodesx->fd=CloseFile(nodesx->fd);
  CloseFile(fd);
 
+ /* Free the now-unneeded index */
+
+ free(segmentsx->usednode);
+ segmentsx->usednode=NULL;
+
  /* Print the final message */
 
- printf_last("Sorted Nodes Geographically: Nodes=%"Pindex_t" Deleted=%"Pindex_t,kept,nodesx->number-kept);
- nodesx->number=kept;
+ printf_last("Checked Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the nodes into latitude and longitude order (first by longitude bin
-  number, then by latitude bin number and then by exact longitude and then by
-  exact latitude).
+  Remove any nodes that have been pruned.
 
-  int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
-
-  NodeX *a The first extended node.
+  NodesX *nodesx The set of nodes to prune.
 
-  NodeX *b The second extended node.
+  SegmentsX *segmentsx The set of segments to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int sort_by_lat_long(NodeX *a,NodeX *b)
+void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx)
 {
- int a_pruned=IsPrunedNodeX(a);
- int b_pruned=IsPrunedNodeX(b);
+ NodeX nodex;
+ index_t total=0,pruned=0,notpruned=0;
+ int fd;
 
- if(a_pruned && b_pruned)
-    return(0);
- else if(a_pruned)
-    return(1);
- else if(b_pruned)
-    return(-1);
- else
-   {
-    ll_bin_t a_lon=latlong_to_bin(a->longitude);
-    ll_bin_t b_lon=latlong_to_bin(b->longitude);
+ if(nodesx->number==0)
+    return;
 
-    if(a_lon<b_lon)
-       return(-1);
-    else if(a_lon>b_lon)
-       return(1);
-    else
-      {
-       ll_bin_t a_lat=latlong_to_bin(a->latitude);
-       ll_bin_t b_lat=latlong_to_bin(b->latitude);
+ /* Print the start message */
 
-       if(a_lat<b_lat)
-          return(-1);
-       else if(a_lat>b_lat)
-          return(1);
-       else
-         {
-          if(a->longitude<b->longitude)
-             return(-1);
-          else if(a->longitude>b->longitude)
-             return(1);
-          else
-            {
-             if(a->latitude<b->latitude)
-                return(-1);
-             else if(a->latitude>b->latitude)
-                return(1);
-            }
-
-          return(0);
-         }
-      }
-   }
-}
+ printf_first("Deleting Pruned Nodes: Nodes=0 Pruned=0");
 
+ /* Allocate the array of indexes */
 
-/*++++++++++++++++++++++++++++++++++++++
-  Delete the pruned nodes and create the index between the sorted and unsorted nodes.
+ nodesx->pdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
 
-  int delete_pruned_and_index_by_lat_long Return 1 if the value is to be kept, otherwise 0.
+ logassert(nodesx->pdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
-  NodeX *nodex The extended node.
+ /* Re-open the file read-only and a new file writeable */
 
-  index_t index The index of this node in the total.
-  ++++++++++++++++++++++++++++++++++++++*/
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
 
-static int delete_pruned_and_index_by_lat_long(NodeX *nodex,index_t index)
-{
- if(IsPrunedNodeX(nodex))
-    return(0);
+ DeleteFile(nodesx->filename_tmp);
 
- /* Create the index from the previous sort to the current one */
+ fd=OpenFileNew(nodesx->filename_tmp);
 
- sortnodesx->gdata[nodex->id]=index;
-
- return(1);
-}
+ /* Modify the on-disk image */
 
+ while(!ReadFile(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+    if(segmentsx->firstnode[total]==NO_SEGMENT)
+      {
+       pruned++;
 
-/*++++++++++++++++++++++++++++++++++++++
-  Find a particular node index.
+       nodesx->pdata[total]=NO_NODE;
+      }
+    else
+      {
+       nodex.id=notpruned;
+       nodesx->pdata[total]=notpruned;
 
-  index_t IndexNodeX Returns the index of the extended node with the specified id.
+       WriteFile(fd,&nodex,sizeof(NodeX));
 
-  NodesX *nodesx The set of nodes to use.
+       notpruned++;
+      }
 
-  node_t id The node id to look for.
-  ++++++++++++++++++++++++++++++++++++++*/
+    total++;
 
-index_t IndexNodeX(NodesX *nodesx,node_t id)
-{
- index_t start=0;
- index_t end=nodesx->number-1;
- index_t mid;
+    if(!(total%10000))
+       printf_middle("Deleting Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+   }
 
- /* Binary search - search key exact match only is required.
-  *
-  *  # <- start  |  Check mid and move start or end if it doesn't match
-  *  #           |
-  *  #           |  Since an exact match is wanted we can set end=mid-1
-  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
-  *  #           |
-  *  #           |  Eventually either end=start or end=start+1 and one of
-  *  # <- end    |  start or end is the wanted one.
-  */
+ nodesx->number=notpruned;
 
- if(end<start)                        /* There are no nodes */
-    return(NO_NODE);
- else if(id<nodesx->idata[start])     /* Check key is not before start */
-    return(NO_NODE);
- else if(id>nodesx->idata[end])       /* Check key is not after end */
-    return(NO_NODE);
- else
-   {
-    do
-      {
-       mid=(start+end)/2;             /* Choose mid point */
-
-       if(nodesx->idata[mid]<id)      /* Mid point is too low */
-          start=mid+1;
-       else if(nodesx->idata[mid]>id) /* Mid point is too high */
-          end=mid?(mid-1):mid;
-       else                           /* Mid point is correct */
-          return(mid);
-      }
-    while((end-start)>1);
+ /* Close the files */
 
-    if(nodesx->idata[start]==id)      /* Start is correct */
-       return(start);
+ nodesx->fd=CloseFile(nodesx->fd);
+ CloseFile(fd);
 
-    if(nodesx->idata[end]==id)        /* End is correct */
-       return(end);
-   }
+ /* Print the final message */
 
- return(NO_NODE);
+ printf_last("Deleted Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Remove any nodes that are not part of a highway.
+  Sort the node list geographically.
 
   NodesX *nodesx The set of nodes to modify.
-
-  SegmentsX *segmentsx The set of segments to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx)
+void SortNodeListGeographically(NodesX *nodesx)
 {
- NodeX nodex;
- index_t total=0,highway=0,nothighway=0;
- ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
- latlong_t lat_min,lat_max,lon_min,lon_max;
  int fd;
+ ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
 
- /* Print the start message */
-
- printf_first("Checking Nodes: Nodes=0");
+ if(nodesx->number==0)
+    return;
 
  /* While we are here we can work out the range of data */
 
@@ -478,52 +515,42 @@ void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx)
  lon_min=radians_to_latlong( 4);
  lon_max=radians_to_latlong(-4);
 
- /* Re-open the file read-only and a new file writeable */
+ /* Print the start message */
 
- nodesx->fd=ReOpenFile(nodesx->filename);
+ printf_first("Sorting Nodes Geographically");
 
- DeleteFile(nodesx->filename);
+ /* Allocate the memory for the geographical index array */
 
- fd=OpenFileNew(nodesx->filename);
+ nodesx->gdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
 
- /* Modify the on-disk image */
+ logassert(nodesx->gdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
- while(!ReadFile(nodesx->fd,&nodex,sizeof(NodeX)))
-   {
-    if(!IsBitSet(segmentsx->usednode,total))
-       nothighway++;
-    else
-      {
-       nodex.id=highway;
+ /* Re-open the file read-only and a new file writeable */
 
-       WriteFile(fd,&nodex,sizeof(NodeX));
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
 
-       nodesx->idata[highway]=nodesx->idata[total];
-       highway++;
+ DeleteFile(nodesx->filename_tmp);
 
-       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;
-      }
+ fd=OpenFileNew(nodesx->filename_tmp);
 
-    total++;
+ /* Sort nodes geographically and index them */
 
-    if(!(total%10000))
-       printf_middle("Checking Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
-   }
+ sortnodesx=nodesx;
 
- nodesx->number=highway;
+ filesort_fixed(nodesx->fd,fd,sizeof(NodeX),NULL,
+                                            (int (*)(const void*,const void*))sort_by_lat_long,
+                                            (int (*)(void*,index_t))index_by_lat_long);
 
  /* Close the files */
 
  nodesx->fd=CloseFile(nodesx->fd);
  CloseFile(fd);
 
+ /* Free the memory */
+
+ free(nodesx->super);
+ nodesx->super=NULL;
+
  /* Work out the number of bins */
 
  lat_min_bin=latlong_to_bin(lat_min);
@@ -537,74 +564,89 @@ void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx)
  nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
  nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
 
- /* Free the now-unneeded index */
-
- free(segmentsx->usednode);
- segmentsx->usednode=NULL;
-
  /* Print the final message */
 
- printf_last("Checked Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+ printf_last("Sorted Nodes Geographically: Nodes=%"Pindex_t,nodesx->number);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Insert the super-node flag and the first segment indexes after geographical sorting.
+  Sort the nodes into latitude and longitude order (first by longitude bin
+  number, then by latitude bin number and then by exact longitude and then by
+  exact latitude).
 
-  NodesX *nodesx The set of nodes to modify.
+  int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
 
-  SegmentsX *segmentsx The set of segments to use.
+  NodeX *a The first extended node.
+
+  NodeX *b The second extended node.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void UpdateNodes(NodesX *nodesx,SegmentsX *segmentsx)
+static int sort_by_lat_long(NodeX *a,NodeX *b)
 {
- index_t i;
- int fd;
+ ll_bin_t a_lon=latlong_to_bin(a->longitude);
+ ll_bin_t b_lon=latlong_to_bin(b->longitude);
 
- /* Print the start message */
-
- printf_first("Updating Super Nodes: Nodes=0");
-
- /* Re-open the file read-only and a new file writeable */
-
- nodesx->fd=ReOpenFile(nodesx->filename);
-
- DeleteFile(nodesx->filename);
-
- fd=OpenFileNew(nodesx->filename);
-
- /* Modify the on-disk image */
-
- for(i=0;i<nodesx->number;i++)
+ if(a_lon<b_lon)
+    return(-1);
+ else if(a_lon>b_lon)
+    return(1);
+ else
    {
-    NodeX nodex;
+    ll_bin_t a_lat=latlong_to_bin(a->latitude);
+    ll_bin_t b_lat=latlong_to_bin(b->latitude);
 
-    ReadFile(nodesx->fd,&nodex,sizeof(NodeX));
+    if(a_lat<b_lat)
+       return(-1);
+    else if(a_lat>b_lat)
+       return(1);
+    else
+      {
+       if(a->longitude<b->longitude)
+          return(-1);
+       else if(a->longitude>b->longitude)
+          return(1);
+       else
+         {
+          if(a->latitude<b->latitude)
+             return(-1);
+          else if(a->latitude>b->latitude)
+             return(1);
+         }
 
-    if(IsBitSet(nodesx->super,nodex.id))
-       nodex.flags|=NODE_SUPER;
+       return(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
+}
 
-    nodex.id=segmentsx->firstnode[nodesx->gdata[nodex.id]];
 
-    WriteFile(fd,&nodex,sizeof(NodeX));
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index between the sorted and unsorted nodes.
 
-    if(!((i+1)%10000))
-       printf_middle("Updating Super Nodes: Nodes=%"Pindex_t,i+1);
-   }
+  int index_by_lat_long Return 1 if the value is to be kept, otherwise 0.
 
- /* Close the files */
+  NodeX *nodex The extended node.
 
- nodesx->fd=CloseFile(nodesx->fd);
- CloseFile(fd);
+  index_t index The number of sorted nodes that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
 
- /* Free the memory */
+static int index_by_lat_long(NodeX *nodex,index_t index)
+{
+ sortnodesx->gdata[nodex->id]=index;
 
- free(nodesx->super);
- nodesx->super=NULL;
+ if(IsBitSet(sortnodesx->super,nodex->id))
+    nodex->flags|=NODE_SUPER;
 
- /* Print the final message */
+ 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;
 
- printf_last("Updated Super Nodes: Nodes=%"Pindex_t,nodesx->number);
+ return(1);
 }
 
 
@@ -614,9 +656,11 @@ void UpdateNodes(NodesX *nodesx,SegmentsX *segmentsx)
   NodesX *nodesx The set of nodes to save.
 
   const char *filename The name of the file to save.
+
+  SegmentsX *segmentsx The set of segments to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void SaveNodeList(NodesX *nodesx,const char *filename)
+void SaveNodeList(NodesX *nodesx,const char *filename,SegmentsX *segmentsx)
 {
  index_t i;
  int fd;
@@ -633,13 +677,13 @@ void SaveNodeList(NodesX *nodesx,const char *filename)
 
  offsets=(index_t*)malloc((nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
 
- assert(offsets); /* Check malloc() worked */
+ logassert(offsets,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
  latlonbin=0;
 
  /* Re-open the file */
 
- nodesx->fd=ReOpenFile(nodesx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
 
  /* Write out the nodes data */
 
@@ -660,7 +704,7 @@ void SaveNodeList(NodesX *nodesx,const char *filename)
 
     node.latoffset=latlong_to_off(nodex.latitude);
     node.lonoffset=latlong_to_off(nodex.longitude);
-    node.firstseg=nodex.id;
+    node.firstseg=segmentsx->firstnode[nodesx->gdata[nodex.id]];
     node.allow=nodex.allow;
     node.flags=nodex.flags;
 
diff --git a/src/nodesx.h b/src/nodesx.h
index 739c3d2..a2dfc34 100644
--- a/src/nodesx.h
+++ b/src/nodesx.h
@@ -45,15 +45,16 @@ struct _NodeX
  latlong_t    longitude;        /*+ The node longitude. +*/
 
  transports_t allow;            /*+ The node allowed traffic. +*/
-
- uint16_t     flags;            /*+ The node flags. +*/
+ nodeflags_t  flags;            /*+ The node flags. +*/
 };
 
 /*+ A structure containing a set of nodes (memory format). +*/
 struct _NodesX
 {
- char     *filename;            /*+ The name of the temporary file. +*/
- int       fd;                  /*+ The file descriptor of the temporary file. +*/
+ char     *filename;            /*+ The name of the intermediate file (for the NodesX). +*/
+ char     *filename_tmp;        /*+ The name of the temporary file (for the NodesX). +*/
+
+ int       fd;                  /*+ The file descriptor of the open file (for the NodesX). +*/
 
  index_t   number;              /*+ The number of extended nodes still being considered. +*/
 
@@ -70,6 +71,8 @@ struct _NodesX
 
  node_t   *idata;               /*+ The extended node IDs (sorted by ID). +*/
 
+ index_t  *pdata;               /*+ The node indexes after pruning. +*/
+
  index_t  *gdata;               /*+ The final node indexes (sorted geographically). +*/
 
  BitMask  *super;               /*+ A bit-mask marker for super nodes (same order as sorted nodes). +*/
@@ -84,29 +87,26 @@ struct _NodesX
 
 /* Functions in nodesx.c */
 
-NodesX *NewNodeList(int append);
+NodesX *NewNodeList(int append,int readonly);
 void FreeNodeList(NodesX *nodesx,int keep);
 
-void SaveNodeList(NodesX *nodesx,const char *filename);
+void AppendNodeList(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,nodeflags_t flags);
+void FinishNodeList(NodesX *nodesx);
 
 index_t IndexNodeX(NodesX *nodesx,node_t id);
 
-void AppendNode(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,uint16_t flags);
-
 void SortNodeList(NodesX *nodesx);
 
-void SortNodeListGeographically(NodesX *nodesx);
+void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,int keep);
 
-void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx);
-
-void UpdateNodes(NodesX *nodesx,SegmentsX *segmentsx);
+void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx);
 
+void SortNodeListGeographically(NodesX *nodesx);
 
-/* Macros and inline functions */
+void SaveNodeList(NodesX *nodesx,const char *filename,SegmentsX *segmentsx);
 
-/*+ Return true if this is a pruned node. +*/
-#define IsPrunedNodeX(xxx)   ((xxx)->latitude==NO_LATLONG)
 
+/* Macros and inline functions */
 
 #if !SLIM
 
diff --git a/src/optimiser.c b/src/optimiser.c
index 9a3652d..fc7cdd7 100644
--- a/src/optimiser.c
+++ b/src/optimiser.c
@@ -20,8 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
-
 #include "types.h"
 #include "nodes.h"
 #include "segments.h"
@@ -107,9 +105,9 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
  if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
    {
-    Node *start=LookupNode(nodes,start_node,1);
+    Node *startp=LookupNode(nodes,start_node,1);
 
-    if(!(start->allow&profile->allow))
+    if(!(startp->allow&profile->allow))
        force_uturn=1;
    }
 
@@ -118,7 +116,7 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
  while((result1=PopFromQueue(queue)))
    {
     Node *node1p=NULL;
-    Segment *segment;
+    Segment *segmentp;
     index_t node1,seg1,seg1r;
     index_t turnrelation=NO_RELATION;
 
@@ -144,36 +142,36 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
     /* Loop across all segments */
 
     if(IsFakeNode(node1))
-       segment=FirstFakeSegment(node1);
+       segmentp=FirstFakeSegment(node1);
     else
-       segment=FirstSegment(segments,node1p,1);
+       segmentp=FirstSegment(segments,node1p,1);
 
-    while(segment)
+    while(segmentp)
       {
        Node *node2p=NULL;
-       Way *way;
+       Way *wayp;
        index_t node2,seg2,seg2r;
        score_t segment_pref,segment_score,cumulative_score;
        int i;
 
-       node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */
+       node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
 
        /* must be a normal segment */
-       if(!IsNormalSegment(segment))
+       if(!IsNormalSegment(segmentp))
           goto endloop;
 
        /* must obey one-way restrictions (unless profile allows) */
-       if(profile->oneway && IsOnewayTo(segment,node1))
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
           goto endloop;
 
        if(IsFakeNode(node1) || IsFakeNode(node2))
          {
-          seg2 =IndexFakeSegment(segment);
+          seg2 =IndexFakeSegment(segmentp);
           seg2r=IndexRealSegment(seg2);
          }
        else
          {
-          seg2 =IndexSegment(segments,segment);
+          seg2 =IndexSegment(segments,segmentp);
           seg2r=seg2;
          }
 
@@ -199,23 +197,23 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        if(node2!=finish_node && node2p && IsSuperNode(node2p))
           goto endloop;
 
-       way=LookupWay(ways,segment->way,1);
+       wayp=LookupWay(ways,segmentp->way,1);
 
        /* mode of transport must be allowed on the highway */
-       if(!(way->allow&profile->allow))
+       if(!(wayp->allow&profile->allow))
           goto endloop;
 
        /* must obey weight restriction (if exists) */
-       if(way->weight && way->weight<profile->weight)
+       if(wayp->weight && wayp->weight<profile->weight)
           goto endloop;
 
        /* must obey height/width/length restriction (if exist) */
-       if((way->height && way->height<profile->height) ||
-          (way->width  && way->width <profile->width ) ||
-          (way->length && way->length<profile->length))
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
           goto endloop;
 
-       segment_pref=profile->highway[HIGHWAY(way->type)];
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
 
        /* highway preferences must allow this highway */
        if(segment_pref==0)
@@ -224,7 +222,7 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        for(i=1;i<Property_Count;i++)
           if(ways->file.props & PROPERTIES(i))
             {
-             if(way->props & PROPERTIES(i))
+             if(wayp->props & PROPERTIES(i))
                 segment_pref*=profile->props_yes[i];
              else
                 segment_pref*=profile->props_no[i];
@@ -239,9 +237,9 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
           goto endloop;
 
        if(option_quickest==0)
-          segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
        else
-          segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
 
        cumulative_score=result1->score+segment_score;
 
@@ -289,15 +287,15 @@ Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
       endloop:
 
        if(IsFakeNode(node1))
-          segment=NextFakeSegment(segment,node1);
+          segmentp=NextFakeSegment(segmentp,node1);
        else if(IsFakeNode(node2))
-          segment=NULL; /* cannot call NextSegment() with a fake segment */
+          segmentp=NULL; /* cannot call NextSegment() with a fake segment */
        else
          {
-          segment=NextSegment(segments,segment,node1);
+          segmentp=NextSegment(segments,segmentp,node1);
 
-          if(!segment && IsFakeNode(finish_node))
-             segment=ExtraFakeSegment(node1,finish_node);
+          if(!segmentp && IsFakeNode(finish_node))
+             segmentp=ExtraFakeSegment(node1,finish_node);
          }
       }
    }
@@ -353,7 +351,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
  /* Set up the finish conditions */
 
- finish_score=INF_DISTANCE;
+ finish_score=INF_SCORE;
  finish_result=NULL;
 
  if(IsFakeNode(end->finish_node))
@@ -434,9 +432,9 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
  if(begin->number==1 && results->prev_segment!=NO_SEGMENT)
    {
-    Node *start=LookupNode(nodes,result1->node,1);
+    Node *startp=LookupNode(nodes,result1->node,1);
 
-    if(!(start->allow&profile->allow))
+    if(!(startp->allow&profile->allow))
        force_uturn=1;
    }
 
@@ -445,7 +443,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
  while((result1=PopFromQueue(queue)))
    {
     Node *node1p;
-    Segment *segment;
+    Segment *segmentp;
     index_t node1,seg1;
     index_t turnrelation=NO_RELATION;
 
@@ -464,25 +462,25 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
     /* Loop across all segments */
 
-    segment=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */
+    segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */
 
-    while(segment)
+    while(segmentp)
       {
        Node *node2p;
-       Way *way;
+       Way *wayp;
        index_t node2,seg2;
        score_t segment_pref,segment_score,cumulative_score;
        int i;
 
        /* must be a super segment */
-       if(!IsSuperSegment(segment))
+       if(!IsSuperSegment(segmentp))
           goto endloop;
 
        /* must obey one-way restrictions (unless profile allows) */
-       if(profile->oneway && IsOnewayTo(segment,node1))
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
           goto endloop;
 
-       seg2=IndexSegment(segments,segment); /* segment cannot be a fake segment (must be a super-segment) */
+       seg2=IndexSegment(segments,segmentp); /* segment cannot be a fake segment (must be a super-segment) */
 
        /* must perform U-turn in special cases */
        if(force_uturn && node1==results->start_node)
@@ -499,23 +497,23 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow))
           goto endloop;
 
-       way=LookupWay(ways,segment->way,1);
+       wayp=LookupWay(ways,segmentp->way,1);
 
        /* mode of transport must be allowed on the highway */
-       if(!(way->allow&profile->allow))
+       if(!(wayp->allow&profile->allow))
           goto endloop;
 
        /* must obey weight restriction (if exists) */
-       if(way->weight && way->weight<profile->weight)
+       if(wayp->weight && wayp->weight<profile->weight)
           goto endloop;
 
        /* must obey height/width/length restriction (if exist) */
-       if((way->height && way->height<profile->height) ||
-          (way->width  && way->width <profile->width ) ||
-          (way->length && way->length<profile->length))
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
           goto endloop;
 
-       segment_pref=profile->highway[HIGHWAY(way->type)];
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
 
        /* highway preferences must allow this highway */
        if(segment_pref==0)
@@ -524,7 +522,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        for(i=1;i<Property_Count;i++)
           if(ways->file.props & PROPERTIES(i))
             {
-             if(way->props & PROPERTIES(i))
+             if(wayp->props & PROPERTIES(i))
                 segment_pref*=profile->props_yes[i];
              else
                 segment_pref*=profile->props_no[i];
@@ -534,7 +532,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        if(segment_pref==0)
           goto endloop;
 
-       node2=OtherNode(segment,node1);
+       node2=OtherNode(segmentp,node1);
 
        node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */
 
@@ -543,9 +541,9 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
           goto endloop;
 
        if(option_quickest==0)
-          segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
        else
-          segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
 
        cumulative_score=result1->score+segment_score;
 
@@ -624,7 +622,7 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
       endloop:
 
-       segment=NextSegment(segments,segment,node1); /* node1 cannot be a fake node (must be a super-node) */
+       segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */
       }
    }
 
@@ -679,31 +677,31 @@ Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t finish_node,index_t finish_segment)
 {
- Node *supernode;
- Segment *supersegment;
+ Node *supernodep;
+ Segment *supersegmentp;
 
  if(IsFakeSegment(finish_segment))
     finish_segment=IndexRealSegment(finish_segment);
 
- supernode=LookupNode(nodes,finish_node,5); /* finish_node cannot be a fake node (must be a super-node) */
- supersegment=LookupSegment(segments,finish_segment,2); /* finish_segment cannot be a fake segment. */
+ supernodep=LookupNode(nodes,finish_node,5); /* finish_node cannot be a fake node (must be a super-node) */
+ supersegmentp=LookupSegment(segments,finish_segment,2); /* finish_segment cannot be a fake segment. */
 
- if(IsSuperSegment(supersegment))
+ if(IsSuperSegment(supersegmentp))
     return(finish_segment);
 
  /* Loop across all segments */
 
- supersegment=FirstSegment(segments,supernode,3); /* supernode cannot be a fake node (must be a super-node) */
+ supersegmentp=FirstSegment(segments,supernodep,3); /* supernode cannot be a fake node (must be a super-node) */
 
- while(supersegment)
+ while(supersegmentp)
    {
-    if(IsSuperSegment(supersegment))
+    if(IsSuperSegment(supersegmentp))
       {
        Results *results;
        Result *result;
        index_t start_node;
 
-       start_node=OtherNode(supersegment,finish_node);
+       start_node=OtherNode(supersegmentp,finish_node);
 
        results=FindSuperRoute(nodes,segments,ways,relations,start_node,finish_node);
 
@@ -712,17 +710,17 @@ static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relat
 
        result=FindResult(results,finish_node,finish_segment);
 
-       if(result && (distance_t)result->score==DISTANCE(supersegment->distance))
+       if(result && (distance_t)result->score==DISTANCE(supersegmentp->distance))
          {
           FreeResultsList(results);
-          return(IndexSegment(segments,supersegment));
+          return(IndexSegment(segments,supersegmentp));
          }
 
        if(results)
           FreeResultsList(results);
       }
 
-    supersegment=NextSegment(segments,supersegment,finish_node); /* finish_node cannot be a fake node (must be a super-node) */
+    supersegmentp=NextSegment(segments,supersegmentp,finish_node); /* finish_node cannot be a fake node (must be a super-node) */
    }
 
  return(finish_segment);
@@ -771,7 +769,7 @@ static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relati
  while((result1=PopFromQueue(queue)))
    {
     Node *node1p=NULL;
-    Segment *segment;
+    Segment *segmentp;
     index_t node1,seg1;
 
     node1=result1->node;
@@ -781,29 +779,29 @@ static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relati
 
     /* Loop across all segments */
 
-    segment=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node */
+    segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node */
 
-    while(segment)
+    while(segmentp)
       {
        Node *node2p=NULL;
        index_t node2,seg2;
        score_t cumulative_score;
 
        /* must be a normal segment */
-       if(!IsNormalSegment(segment))
+       if(!IsNormalSegment(segmentp))
           goto endloop;
 
        /* must obey one-way restrictions */
-       if(IsOnewayTo(segment,node1))
+       if(IsOnewayTo(segmentp,node1))
           goto endloop;
 
-       seg2=IndexSegment(segments,segment);
+       seg2=IndexSegment(segments,segmentp);
 
        /* must not perform U-turn */
        if(seg1==seg2)
           goto endloop;
 
-       node2=OtherNode(segment,node1);
+       node2=OtherNode(segmentp,node1);
 
        node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node */
 
@@ -812,7 +810,7 @@ static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relati
           goto endloop;
 
        /* Specifically looking for the shortest route to emulate superx.c */
-       cumulative_score=result1->score+(score_t)DISTANCE(segment->distance);
+       cumulative_score=result1->score+(score_t)DISTANCE(segmentp->distance);
 
        result2=FindResult(results,node2,seg2);
 
@@ -841,7 +839,7 @@ static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relati
 
       endloop:
 
-       segment=NextSegment(segments,segment,node1);
+       segmentp=NextSegment(segments,segmentp,node1);
       }
    }
 
@@ -898,9 +896,9 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
 
  if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
    {
-    Node *start=LookupNode(nodes,start_node,1);
+    Node *startp=LookupNode(nodes,start_node,1);
 
-    if(!(start->allow&profile->allow))
+    if(!(startp->allow&profile->allow))
        force_uturn=1;
    }
 
@@ -909,7 +907,7 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
  while((result1=PopFromQueue(queue)))
    {
     Node *node1p=NULL;
-    Segment *segment;
+    Segment *segmentp;
     index_t node1,seg1,seg1r;
     index_t turnrelation=NO_RELATION;
 
@@ -931,36 +929,36 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
     /* Loop across all segments */
 
     if(IsFakeNode(node1))
-       segment=FirstFakeSegment(node1);
+       segmentp=FirstFakeSegment(node1);
     else
-       segment=FirstSegment(segments,node1p,1);
+       segmentp=FirstSegment(segments,node1p,1);
 
-    while(segment)
+    while(segmentp)
       {
        Node *node2p=NULL;
-       Way *way;
+       Way *wayp;
        index_t node2,seg2,seg2r;
        score_t segment_pref,segment_score,cumulative_score;
        int i;
 
-       node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */
+       node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
 
        /* must be a normal segment */
-       if(!IsNormalSegment(segment))
+       if(!IsNormalSegment(segmentp))
           goto endloop;
 
        /* must obey one-way restrictions (unless profile allows) */
-       if(profile->oneway && IsOnewayTo(segment,node1))
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
           goto endloop;
 
        if(IsFakeNode(node1) || IsFakeNode(node2))
          {
-          seg2 =IndexFakeSegment(segment);
+          seg2 =IndexFakeSegment(segmentp);
           seg2r=IndexRealSegment(seg2);
          }
        else
          {
-          seg2 =IndexSegment(segments,segment);
+          seg2 =IndexSegment(segments,segmentp);
           seg2r=seg2;
          }
 
@@ -979,23 +977,23 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
           goto endloop;
 
-       way=LookupWay(ways,segment->way,1);
+       wayp=LookupWay(ways,segmentp->way,1);
 
        /* mode of transport must be allowed on the highway */
-       if(!(way->allow&profile->allow))
+       if(!(wayp->allow&profile->allow))
           goto endloop;
 
        /* must obey weight restriction (if exists) */
-       if(way->weight && way->weight<profile->weight)
+       if(wayp->weight && wayp->weight<profile->weight)
           goto endloop;
 
        /* must obey height/width/length restriction (if exists) */
-       if((way->height && way->height<profile->height) ||
-          (way->width  && way->width <profile->width ) ||
-          (way->length && way->length<profile->length))
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
           goto endloop;
 
-       segment_pref=profile->highway[HIGHWAY(way->type)];
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
 
        /* highway preferences must allow this highway */
        if(segment_pref==0)
@@ -1004,7 +1002,7 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
        for(i=1;i<Property_Count;i++)
           if(ways->file.props & PROPERTIES(i))
             {
-             if(way->props & PROPERTIES(i))
+             if(wayp->props & PROPERTIES(i))
                 segment_pref*=profile->props_yes[i];
              else
                 segment_pref*=profile->props_no[i];
@@ -1022,9 +1020,9 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
           goto endloop;
 
        if(option_quickest==0)
-          segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
        else
-          segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
 
        cumulative_score=result1->score+segment_score;
 
@@ -1063,15 +1061,15 @@ Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *r
       endloop:
 
        if(IsFakeNode(node1))
-          segment=NextFakeSegment(segment,node1);
+          segmentp=NextFakeSegment(segmentp,node1);
        else if(IsFakeNode(node2))
-          segment=NULL; /* cannot call NextSegment() with a fake segment */
+          segmentp=NULL; /* cannot call NextSegment() with a fake segment */
        else
          {
-          segment=NextSegment(segments,segment,node1);
+          segmentp=NextSegment(segments,segmentp,node1);
 
-          if(!segment && IsFakeNode(finish_node))
-             segment=ExtraFakeSegment(node1,finish_node);
+          if(!segmentp && IsFakeNode(finish_node))
+             segmentp=ExtraFakeSegment(node1,finish_node);
          }
       }
    }
@@ -1130,7 +1128,7 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
  while((result1=PopFromQueue(queue)))
    {
     Node *node1p=NULL;
-    Segment *segment;
+    Segment *segmentp;
     index_t node1,seg1,seg1r;
     index_t turnrelation=NO_RELATION;
 
@@ -1152,40 +1150,40 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
     /* Loop across all segments */
 
     if(IsFakeNode(node1))
-       segment=FirstFakeSegment(node1);
+       segmentp=FirstFakeSegment(node1);
     else
-       segment=FirstSegment(segments,node1p,1);
+       segmentp=FirstSegment(segments,node1p,1);
 
-    while(segment)
+    while(segmentp)
       {
        Node *node2p=NULL;
-       Way *way;
+       Way *wayp;
        index_t node2,seg2,seg2r;
        score_t segment_pref,segment_score,cumulative_score;
        int i;
 
        /* must be a normal segment unless node1 is a super-node (see below). */
-       if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segment))
+       if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segmentp))
           goto endloop;
 
        /* must be a super segment if node1 is a super-node to give starting super-segment for finding middle route. */
-       if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segment))
+       if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segmentp))
           goto endloop;
 
        /* must obey one-way restrictions (unless profile allows) */
-       if(profile->oneway && IsOnewayFrom(segment,node1)) /* working backwards => disallow oneway *from* node1 */
+       if(profile->oneway && IsOnewayFrom(segmentp,node1)) /* working backwards => disallow oneway *from* node1 */
           goto endloop;
 
-       node2=OtherNode(segment,node1);
+       node2=OtherNode(segmentp,node1);
 
        if(IsFakeNode(node1) || IsFakeNode(node2))
          {
-          seg2 =IndexFakeSegment(segment);
+          seg2 =IndexFakeSegment(segmentp);
           seg2r=IndexRealSegment(seg2);
          }
        else
          {
-          seg2 =IndexSegment(segments,segment);
+          seg2 =IndexSegment(segments,segmentp);
           seg2r=seg2;
          }
 
@@ -1202,23 +1200,23 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
              goto endloop;
          }
 
-       way=LookupWay(ways,segment->way,1);
+       wayp=LookupWay(ways,segmentp->way,1);
 
        /* mode of transport must be allowed on the highway */
-       if(!(way->allow&profile->allow))
+       if(!(wayp->allow&profile->allow))
           goto endloop;
 
        /* must obey weight restriction (if exists) */
-       if(way->weight && way->weight<profile->weight)
+       if(wayp->weight && wayp->weight<profile->weight)
           goto endloop;
 
        /* must obey height/width/length restriction (if exist) */
-       if((way->height && way->height<profile->height) ||
-          (way->width  && way->width <profile->width ) ||
-          (way->length && way->length<profile->length))
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
           goto endloop;
 
-       segment_pref=profile->highway[HIGHWAY(way->type)];
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
 
        /* highway preferences must allow this highway */
        if(segment_pref==0)
@@ -1227,7 +1225,7 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
        for(i=1;i<Property_Count;i++)
           if(ways->file.props & PROPERTIES(i))
             {
-             if(way->props & PROPERTIES(i))
+             if(wayp->props & PROPERTIES(i))
                 segment_pref*=profile->props_yes[i];
              else
                 segment_pref*=profile->props_no[i];
@@ -1245,9 +1243,9 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
           goto endloop;
 
        if(option_quickest==0)
-          segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
        else
-          segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
 
        cumulative_score=result1->score+segment_score;
 
@@ -1280,9 +1278,9 @@ Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *
       endloop:
 
        if(IsFakeNode(node1))
-          segment=NextFakeSegment(segment,node1);
+          segmentp=NextFakeSegment(segmentp,node1);
        else
-          segment=NextSegment(segments,segment,node1);
+          segmentp=NextSegment(segments,segmentp,node1);
       }
    }
 
@@ -1508,7 +1506,7 @@ void FixForwardRoute(Results *results,Result *finish_result)
 
        result1=FindResult(results,node1,seg1);
 
-       assert(!result1->next);   /* Bugs elsewhere can lead to infinite loop here. */
+       logassert(!result1->next,"Unable to reverse route through results (report a bug)"); /* Bugs elsewhere can lead to infinite loop here. */
 
        result1->next=result2;
 
diff --git a/src/osmparser.c b/src/osmparser.c
index 6c9601f..ec9692e 100644
--- a/src/osmparser.c
+++ b/src/osmparser.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -49,8 +48,18 @@
 #define ISFALSE(xx) (!strcmp(xx,"false") || !strcmp(xx,"no") || !strcmp(xx,"0"))
 
 
+/* Constants */
+
+#define MODE_NORMAL  3
+#define MODE_CREATE  2
+#define MODE_MODIFY  1
+#define MODE_DELETE -1
+
+
 /* Local variables */
 
+static int mode=MODE_NORMAL;
+
 static index_t nnodes=0;
 static index_t nways=0;
 static index_t nrelations=0;
@@ -91,6 +100,10 @@ static double parse_length(way_t id,const char *k,const char *v);
 
 //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
 static int osmType_function(const char *_tag_,int _type_,const char *version);
+static int osmChangeType_function(const char *_tag_,int _type_,const char *version);
+static int deleteType_function(const char *_tag_,int _type_);
+static int createType_function(const char *_tag_,int _type_);
+static int modifyType_function(const char *_tag_,int _type_);
 static int relationType_function(const char *_tag_,int _type_,const char *id);
 static int wayType_function(const char *_tag_,int _type_,const char *id);
 static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role);
@@ -167,6 +180,34 @@ static xmltag relationType_tag=
                relationType_function,
                {&memberType_tag,&tagType_tag,NULL}};
 
+/*+ The deleteType type tag. +*/
+static xmltag deleteType_tag=
+              {"delete",
+               0, {NULL},
+               deleteType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The createType type tag. +*/
+static xmltag createType_tag=
+              {"create",
+               0, {NULL},
+               createType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The modifyType type tag. +*/
+static xmltag modifyType_tag=
+              {"modify",
+               0, {NULL},
+               modifyType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The osmChangeType type tag. +*/
+static xmltag osmChangeType_tag=
+              {"osmChange",
+               1, {"version"},
+               osmChangeType_function,
+               {&boundsType_tag,&modifyType_tag,&createType_tag,&deleteType_tag,NULL}};
+
 /*+ The osmType type tag. +*/
 static xmltag osmType_tag=
               {"osm",
@@ -182,8 +223,11 @@ static xmltag xmlDeclaration_tag=
                {NULL}};
 
 
-/*+ The complete set of tags at the top level. +*/
-static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
+/*+ The complete set of tags at the top level for OSM. +*/
+static xmltag *xml_osm_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
+
+/*+ The complete set of tags at the top level for OSC. +*/
+static xmltag *xml_osc_toplevel_tags[]={&xmlDeclaration_tag,&osmChangeType_tag,NULL};
 
 
 /* The XML tag processing functions */
@@ -303,10 +347,13 @@ static int nodeType_function(const char *_tag_,int _type_,const char *id,const c
 
     XMLPARSE_ASSERT_INTEGER(_tag_,id);   llid=atoll(id); /* need long long conversion */
     node_id=(node_t)llid;
-    assert((long long)node_id==llid);      /* check node id can be stored in node_t data type. */
+    logassert((long long)node_id==llid,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
 
-    XMLPARSE_ASSERT_FLOATING(_tag_,lat); latitude =atof(lat);
-    XMLPARSE_ASSERT_FLOATING(_tag_,lon); longitude=atof(lon);
+    if(mode!=MODE_DELETE)
+      {
+       XMLPARSE_ASSERT_FLOATING(_tag_,lat); latitude =atof(lat);
+       XMLPARSE_ASSERT_FLOATING(_tag_,lon); longitude=atof(lon);
+      }
    }
 
  if(_type_&XMLPARSE_TAG_END)
@@ -344,7 +391,7 @@ static int ndType_function(const char *_tag_,int _type_,const char *ref)
 
     XMLPARSE_ASSERT_INTEGER(_tag_,ref); llid=atoll(ref); /* need long long conversion */
     node_id=(node_t)llid;
-    assert((long long)node_id==llid);      /* check node id can be stored in node_t data type. */
+    logassert((long long)node_id==llid,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
 
     if(way_nnodes && (way_nnodes%256)==0)
        way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
@@ -386,7 +433,7 @@ static int memberType_function(const char *_tag_,int _type_,const char *type,con
        node_t node_id;
 
        node_id=(node_t)llid;
-       assert((long long)node_id==llid);   /* check node id can be stored in node_t data type. */
+       logassert((long long)node_id==llid,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
 
        if(relation_nnodes && (relation_nnodes%256)==0)
           relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t));
@@ -404,7 +451,7 @@ static int memberType_function(const char *_tag_,int _type_,const char *type,con
        way_t way_id;
 
        way_id=(way_t)llid;
-       assert((long long)way_id==llid);   /* check way id can be stored in way_t data type. */
+       logassert((long long)way_id==llid,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
 
        if(relation_nways && (relation_nways%256)==0)
           relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t));
@@ -424,7 +471,7 @@ static int memberType_function(const char *_tag_,int _type_,const char *type,con
        relation_t relation_id;
 
        relation_id=(relation_t)llid;
-       assert((long long)relation_id==llid);   /* check relation id can be stored in relation_t data type. */
+       logassert((long long)relation_id==llid,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
 
        if(relation_nrelations && (relation_nrelations%256)==0)
           relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t));
@@ -471,7 +518,7 @@ static int wayType_function(const char *_tag_,int _type_,const char *id)
     XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */
 
     way_id=(way_t)llid;
-    assert((long long)way_id==llid);   /* check way id can be stored in way_t data type. */
+    logassert((long long)way_id==llid,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
    }
 
  if(_type_&XMLPARSE_TAG_END)
@@ -526,7 +573,7 @@ static int relationType_function(const char *_tag_,int _type_,const char *id)
     XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */
 
     relation_id=(relation_t)llid;
-    assert((long long)relation_id==llid);   /* check relation id can be stored in relation_t data type. */
+    logassert((long long)relation_id==llid,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
    }
 
  if(_type_&XMLPARSE_TAG_END)
@@ -544,6 +591,87 @@ static int relationType_function(const char *_tag_,int _type_,const char *id)
 
 
 /*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the deleteType XSD type is seen
+
+  int deleteType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deleteType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    mode=MODE_DELETE;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the createType XSD type is seen
+
+  int createType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int createType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    mode=MODE_CREATE;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the modifyType XSD type is seen
+
+  int modifyType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int modifyType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    mode=MODE_MODIFY;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the osmChangeType XSD type is seen
+
+  int osmChangeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int osmChangeType_function(const char *_tag_,int _type_,const char *version)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    if(!version || strcmp(version,"0.6"))
+       XMLPARSE_MESSAGE(_tag_,"Invalid value for 'version' (only '0.6' accepted)");
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
   The function that is called when the osmType XSD type is seen
 
   int osmType_function Returns 0 if no error occured or something else otherwise.
@@ -559,6 +687,8 @@ static int osmType_function(const char *_tag_,int _type_,const char *version)
 {
  if(_type_&XMLPARSE_TAG_START)
    {
+    mode=MODE_NORMAL;
+
     if(!version || strcmp(version,"0.6"))
        XMLPARSE_MESSAGE(_tag_,"Invalid value for 'version' (only '0.6' accepted)");
    }
@@ -626,7 +756,60 @@ int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,R
 
  printf_first("Reading: Lines=0 Nodes=0 Ways=0 Relations=0");
 
- retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+ retval=ParseXML(file,xml_osm_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+
+ printf_last("Read: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+ free(way_nodes);
+
+ free(relation_nodes);
+ free(relation_ways);
+ free(relation_relations);
+
+ return(retval);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an OSC XML file (from planet download).
+
+  int ParseOSC Returns 0 if OK or something else in case of an error.
+
+  FILE *file The file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  SegmentsX *OSMSegments The data structure of segments to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseOSC(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Copy the function parameters and initialise the variables. */
+
+ nodes=OSMNodes;
+ segments=OSMSegments;
+ ways=OSMWays;
+ relations=OSMRelations;
+
+ way_nodes=(node_t*)malloc(256*sizeof(node_t));
+
+ relation_nodes    =(node_t    *)malloc(256*sizeof(node_t));
+ relation_ways     =(way_t     *)malloc(256*sizeof(way_t));
+ relation_relations=(relation_t*)malloc(256*sizeof(relation_t));
+
+ /* Parse the file */
+
+ nnodes=0,nways=0,nrelations=0;
+
+ printf_first("Reading: Lines=0 Nodes=0 Ways=0 Relations=0");
+
+ retval=ParseXML(file,xml_osc_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
 
  printf_last("Read: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations);
 
@@ -655,9 +838,18 @@ int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,R
 static void process_node_tags(TagList *tags,node_t id,double latitude,double longitude)
 {
  transports_t allow=Transports_ALL;
- uint16_t flags=0;
+ nodeflags_t flags=0;
  int i;
 
+ /* Delete */
+
+ if(mode==MODE_DELETE)
+   {
+    AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,NODE_DELETED);
+
+    return;
+   }
+
  /* Parse the tags */
 
  for(i=0;i<tags->ntags;i++)
@@ -796,7 +988,7 @@ static void process_node_tags(TagList *tags,node_t id,double latitude,double lon
 
  /* Create the node */
 
- AppendNode(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags);
+ AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags);
 }
 
 
@@ -810,10 +1002,41 @@ static void process_node_tags(TagList *tags,node_t id,double latitude,double lon
 
 static void process_way_tags(TagList *tags,way_t id)
 {
- Way   way={0};
- int   oneway=0,roundabout=0,area=0;
+ Way way={0};
+ distance_t oneway=0,area=0;
+ int roundabout=0;
  char *name=NULL,*ref=NULL,*refname=NULL;
- int i;
+ int i,j;
+
+ /* Delete */
+
+ if(mode==MODE_DELETE || mode==MODE_MODIFY)
+   {
+    way.type=WAY_DELETED;
+
+    AppendWayList(ways,id,&way,"");
+
+    way.type=Highway_None;
+
+    AppendSegmentList(segments,id,NO_NODE_ID,NO_NODE_ID,0);
+   }
+
+ if(mode==MODE_DELETE)
+    return;
+
+ /* Sanity check */
+
+ if(way_nnodes==0)
+   {
+    logerror("Way %"Pway_t" has no nodes.\n",id);
+    return;
+   }
+
+ if(way_nnodes==1)
+   {
+    logerror("Way %"Pway_t" has only one node.\n",id);
+    return;
+   }
 
  /* Parse the tags - just look for highway */
 
@@ -826,14 +1049,16 @@ static void process_way_tags(TagList *tags,way_t id)
       {
        way.type=HighwayType(v);
 
-       if(way.type==Way_Count)
+       if(way.type==Highway_None)
           logerror("Way %"Pway_t" has an unrecognised highway type '%s' (after tagging rules); ignoring it.\n",id,v);
+
+       break;
       }
    }
 
  /* Don't continue if this is not a highway (bypass error logging) */
 
- if(way.type==0 || way.type==Way_Count)
+ if(way.type==Highway_None)
     return;
 
  /* Parse the tags - look for the others */
@@ -850,7 +1075,7 @@ static void process_way_tags(TagList *tags,way_t id)
        if(!strcmp(k,"area"))
          {
           if(ISTRUE(v))
-             area=1;
+             area=SEGMENT_AREA;
           else if(!ISFALSE(v))
              logerror("Way %"Pway_t" has an unrecognised tag value 'area' = '%s' (after tagging rules); using 'no'.\n",id,v);
           recognised=1; break;
@@ -1030,9 +1255,9 @@ static void process_way_tags(TagList *tags,way_t id)
        if(!strcmp(k,"oneway"))
          {
           if(ISTRUE(v))
-             oneway=1;
+             oneway=ONEWAY_1TO2;
           else if(!strcmp(v,"-1"))
-             oneway=-1;
+             oneway=ONEWAY_2TO1;
           else if(!ISFALSE(v))
              logerror("Way %"Pway_t" has an unrecognised tag value 'oneway' = '%s' (after tagging rules); using 'no'.\n",id,v);
           recognised=1; break;
@@ -1116,18 +1341,11 @@ static void process_way_tags(TagList *tags,way_t id)
  if(!way.allow)
     return;
 
- if(way_nnodes==0)
-   {
-    logerror("Way %"Pway_t" has no nodes.\n",id);
-
-    return;
-   }
-
  if(oneway)
-    way.type|=Way_OneWay;
+    way.type|=Highway_OneWay;
 
  if(roundabout)
-    way.type|=Way_Roundabout;
+    way.type|=Highway_Roundabout;
 
  if(ref && name)
    {
@@ -1141,7 +1359,7 @@ static void process_way_tags(TagList *tags,way_t id)
  else /* if(!ref && !name) */
     refname="";
 
- AppendWay(ways,id,&way,refname);
+ AppendWayList(ways,id,&way,refname);
 
  if(ref && name)
     free(refname);
@@ -1151,12 +1369,16 @@ static void process_way_tags(TagList *tags,way_t id)
     node_t from=way_nodes[i-1];
     node_t to  =way_nodes[i];
 
-    if(oneway>0)
-       AppendSegment(segments,id,from,to,area+ONEWAY_1TO2);
-    else if(oneway<0)
-       AppendSegment(segments,id,from,to,area+ONEWAY_2TO1);
-    else
-       AppendSegment(segments,id,from,to,area);
+    for(j=1;j<i;j++)
+      {
+       node_t n1=way_nodes[j-1];
+       node_t n2=way_nodes[j];
+
+       if((n1==from && n2==to) || (n2==from && n1==to))
+          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" in way %"Pway_t" is duplicated.\n",n1,n2,id);
+      }
+
+    AppendSegmentList(segments,id,from,to,area+oneway);
    }
 }
 
@@ -1177,6 +1399,30 @@ static void process_relation_tags(TagList *tags,relation_t id)
  TurnRestriction restriction=TurnRestrict_None;
  int i;
 
+ /* Delete */
+
+ if(mode==MODE_DELETE || mode==MODE_MODIFY)
+   {
+    AppendRouteRelationList(relations,id,RELATION_DELETED,
+                            relation_ways,relation_nways,
+                            relation_relations,relation_nrelations);
+
+    AppendTurnRelationList(relations,id,
+                           relation_from,relation_to,relation_via,
+                           restriction,RELATION_DELETED);
+   }
+
+ if(mode==MODE_DELETE)
+    return;
+
+ /* Sanity check */
+
+ if(relation_nnodes==0 && relation_nways==0 && relation_nrelations==0)
+   {
+    logerror("Relation %"Prelation_t" has no nodes, ways or relations.\n",id);
+    return;
+   }
+
  /* Parse the tags */
 
  for(i=0;i<tags->ntags;i++)
@@ -1270,9 +1516,9 @@ static void process_relation_tags(TagList *tags,relation_t id)
     other relations that are routes) */
 
  if((relation_nways || relation_nrelations) && !relation_turn_restriction)
-    AppendRouteRelation(relations,id,routes,
-                        relation_ways,relation_nways,
-                        relation_relations,relation_nrelations);
+    AppendRouteRelationList(relations,id,routes,
+                            relation_ways,relation_nways,
+                            relation_relations,relation_nrelations);
 
  /* Create the turn restriction relation. */
 
@@ -1285,9 +1531,9 @@ static void process_relation_tags(TagList *tags,relation_t id)
     else if(relation_via==NO_NODE_ID)
        logerror("Relation %"Prelation_t" is a turn restriction but has no 'via' node.\n",id);
     else
-       AppendTurnRestrictRelation(relations,id,
-                                  relation_from,relation_to,relation_via,
-                                  restriction,except);
+       AppendTurnRelationList(relations,id,
+                              relation_from,relation_to,relation_via,
+                              restriction,except);
    }
 }
 
@@ -1393,6 +1639,12 @@ static double parse_length(way_t id,const char *k,const char *v)
     if(sscanf(v,"%d' %d\"%n",&feet,&inches,&en)==2 && en && !v[en])
        return((feet+(double)inches/12.0)*0.254);
 
+    if(sscanf(v,"%d'%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d'-%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
     if(sscanf(v,"%d - %d%n",&feet,&inches,&en)==2 && en && !v[en])
        return((feet+(double)inches/12.0)*0.254);
 
diff --git a/src/osmparser.h b/src/osmparser.h
index 9e1dda2..ba91717 100644
--- a/src/osmparser.h
+++ b/src/osmparser.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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
@@ -32,5 +32,7 @@
 
 int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,RelationsX *OSMRelations);
 
+int ParseOSC(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,RelationsX *OSMRelations);
+
 
 #endif /* OSMPARSER_H */
diff --git a/src/output.c b/src/output.c
index 9c9a388..2616936 100644
--- a/src/output.c
+++ b/src/output.c
@@ -67,7 +67,7 @@ extern int option_html,option_gpx_track,option_gpx_route,option_text,option_text
 /* Local variables */
 
 /*+ Heuristics for determining if a junction is important. +*/
-static char junction_other_way[Way_Count][Way_Count]=
+static char junction_other_way[Highway_Count][Highway_Count]=
  { /* M, T, P, S, T, U, R, S, T, C, P, S, F = Way type of route not taken */
   {   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Motorway     */
   {   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Trunk        */
@@ -327,10 +327,10 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
     do
       {
        double latitude,longitude;
-       Node *resultnode=NULL;
+       Node *resultnodep=NULL;
        index_t realsegment=NO_SEGMENT,next_realsegment=NO_SEGMENT;
-       Segment *resultsegment=NULL,*next_resultsegment=NULL;
-       Way *resultway=NULL,*next_resultway=NULL;
+       Segment *resultsegmentp=NULL,*next_resultsegmentp=NULL;
+       Way *resultwayp=NULL,*next_resultwayp=NULL;
        Result *next_result;
        int important=IMP_UNIMPORTANT;
 
@@ -349,7 +349,7 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
           GetLatLong(nodes,result->node,&latitude,&longitude);
 
        if(!IsFakeNode(result->node))
-          resultnode=LookupNode(nodes,result->node,6);
+          resultnodep=LookupNode(nodes,result->node,6);
 
        /* Calculate the next result */
 
@@ -370,19 +370,19 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
          {
           if(IsFakeSegment(result->segment))
             {
-             resultsegment=LookupFakeSegment(result->segment);
+             resultsegmentp=LookupFakeSegment(result->segment);
              realsegment=IndexRealSegment(result->segment);
             }
           else
             {
-             resultsegment=LookupSegment(segments,result->segment,2);
+             resultsegmentp=LookupSegment(segments,result->segment,2);
              realsegment=result->segment;
             }
 
-          resultway=LookupWay(ways,resultsegment->way,1);
+          resultwayp=LookupWay(ways,resultsegmentp->way,1);
 
-          seg_distance+=DISTANCE(resultsegment->distance);
-          seg_duration+=Duration(resultsegment,resultway,profile);
+          seg_distance+=DISTANCE(resultsegmentp->distance);
+          seg_duration+=Duration(resultsegmentp,resultwayp,profile);
 
           /* Calculate the cumulative distance/duration */
 
@@ -398,12 +398,12 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
          {
           if(IsFakeSegment(next_result->segment))
             {
-             next_resultsegment=LookupFakeSegment(next_result->segment);
+             next_resultsegmentp=LookupFakeSegment(next_result->segment);
              next_realsegment=IndexRealSegment(next_result->segment);
             }
           else
             {
-             next_resultsegment=LookupSegment(segments,next_result->segment,1);
+             next_resultsegmentp=LookupSegment(segments,next_result->segment,1);
              next_realsegment=next_result->segment;
             }
          }
@@ -412,9 +412,9 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
 
        if(next_result)
          {
-          next_resultway=LookupWay(ways,next_resultsegment->way,2);
+          next_resultwayp=LookupWay(ways,next_resultsegmentp->way,2);
 
-          if(next_resultway->type&Way_Roundabout)
+          if(next_resultwayp->type&Highway_Roundabout)
             {
              if(roundabout==0)
                {
@@ -423,18 +423,18 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
                }
              else
                {
-                Segment *segment=FirstSegment(segments,resultnode,3);
+                Segment *segmentp=FirstSegment(segments,resultnodep,3);
 
                 do
                   {
-                   index_t othernode=OtherNode(segment,result->node);
+                   index_t othernode=OtherNode(segmentp,result->node);
 
-                   if(othernode!=result->prev->node && IndexSegment(segments,segment)!=realsegment)
-                      if(IsNormalSegment(segment) && (!profile->oneway || !IsOnewayTo(segment,result->node)))
+                   if(othernode!=result->prev->node && IndexSegment(segments,segmentp)!=realsegment)
+                      if(IsNormalSegment(segmentp) && (!profile->oneway || !IsOnewayTo(segmentp,result->node)))
                         {
-                         Way *way=LookupWay(ways,segment->way,3);
+                         Way *wayp=LookupWay(ways,segmentp->way,3);
 
-                         if(!(way->type&Way_Roundabout))
+                         if(!(wayp->type&Highway_Roundabout))
                             if(othernode!=next_result->node)
                               {
                                roundabout++;
@@ -442,9 +442,9 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
                               }
                         }
 
-                   segment=NextSegment(segments,segment,result->node);
+                   segmentp=NextSegment(segments,segmentp,result->node);
                   }
-                while(segment);
+                while(segmentp);
                }
             }
           else
@@ -467,30 +467,30 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
           important=IMP_IGNORE;
        else if(realsegment==next_realsegment) /* U-turn */
           important=IMP_UTURN;
-       else if(resultnode && (resultnode->flags&NODE_MINIRNDBT))
+       else if(resultnodep && (resultnodep->flags&NODE_MINIRNDBT))
           important=IMP_MINI_RB; /* mini-roundabout */
        else
          {
-          Segment *segment=FirstSegment(segments,resultnode,3);
+          Segment *segmentp=FirstSegment(segments,resultnodep,3);
 
           do
             {
-             index_t seg=IndexSegment(segments,segment);
+             index_t seg=IndexSegment(segments,segmentp);
 
              if(seg!=realsegment)
-                if(IsNormalSegment(segment) && (!profile->oneway || !IsOnewayTo(segment,result->node)))
+                if(IsNormalSegment(segmentp) && (!profile->oneway || !IsOnewayTo(segmentp,result->node)))
                   {
-                   Way *way=LookupWay(ways,segment->way,3);
+                   Way *wayp=LookupWay(ways,segmentp->way,3);
 
                    if(seg==next_realsegment) /* the next segment that we follow */
                      {
-                      if(HIGHWAY(way->type)!=HIGHWAY(resultway->type))
+                      if(HIGHWAY(wayp->type)!=HIGHWAY(resultwayp->type))
                          if(important<IMP_CHANGE)
                             important=IMP_CHANGE;
                      }
                    else /* a segment that we don't follow */
                      {
-                      if(junction_other_way[HIGHWAY(resultway->type)-1][HIGHWAY(way->type)-1])
+                      if(junction_other_way[HIGHWAY(resultwayp->type)-1][HIGHWAY(wayp->type)-1])
                          if(important<IMP_JUNCT_IMPORT)
                             important=IMP_JUNCT_IMPORT;
 
@@ -499,44 +499,44 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
                      }
                   }
 
-             segment=NextSegment(segments,segment,result->node);
+             segmentp=NextSegment(segments,segmentp,result->node);
             }
-          while(segment);
+          while(segmentp);
          }
 
        /* Calculate the strings to be used */
 
-       if(resultway && textallfile)
+       if(resultwayp && textallfile)
          {
-          waynameraw=WayName(ways,resultway);
+          waynameraw=WayName(ways,resultwayp);
           if(!*waynameraw)
-             waynameraw=translate_raw_highway[HIGHWAY(resultway->type)];
+             waynameraw=translate_raw_highway[HIGHWAY(resultwayp->type)];
 
-          bearing_int=(int)BearingAngle(nodes,resultsegment,result->node);
+          bearing_int=(int)BearingAngle(nodes,resultsegmentp,result->node);
 
-          seg_speed=profile->speed[HIGHWAY(resultway->type)];
+          seg_speed=profile->speed[HIGHWAY(resultwayp->type)];
          }
 
        if(next_result && important>IMP_JUNCT_CONT)
          {
-          if(resultsegment && (htmlfile || textfile))
+          if(resultsegmentp && (htmlfile || textfile))
             {
-             turn_int=(int)TurnAngle(nodes,resultsegment,next_resultsegment,result->node);
+             turn_int=(int)TurnAngle(nodes,resultsegmentp,next_resultsegmentp,result->node);
              turn=translate_xml_turn[((202+turn_int)/45)%8];
             }
 
           if(gpxroutefile || htmlfile)
             {
-             next_waynameraw=WayName(ways,next_resultway);
+             next_waynameraw=WayName(ways,next_resultwayp);
              if(!*next_waynameraw)
-                next_waynameraw=translate_raw_highway[HIGHWAY(next_resultway->type)];
+                next_waynameraw=translate_raw_highway[HIGHWAY(next_resultwayp->type)];
 
              next_wayname=ParseXML_Encode_Safe_XML(next_waynameraw);
             }
 
           if(htmlfile || gpxroutefile || textfile)
             {
-             next_bearing_int=(int)BearingAngle(nodes,next_resultsegment,next_result->node);
+             next_bearing_int=(int)BearingAngle(nodes,next_resultsegmentp,next_result->node);
              next_bearing=translate_xml_heading[(4+(22+next_bearing_int)/45)%8];
             }
          }
@@ -758,7 +758,7 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
                 fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t\t\t\n",
                                     radians_to_degrees(latitude),radians_to_degrees(longitude),
                                     IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
-                                    (resultnode && IsSuperNode(resultnode))?'*':' ',type,
+                                    (resultnodep && IsSuperNode(resultnodep))?'*':' ',type,
                                     0.0,0.0,0.0,0.0);
                }
              else               /* not the first point */
@@ -766,7 +766,7 @@ void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,W
                 fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n",
                                     radians_to_degrees(latitude),radians_to_degrees(longitude),
                                     IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
-                                    (resultnode && IsSuperNode(resultnode))?'*':' ',type,
+                                    (resultnodep && IsSuperNode(resultnodep))?'*':' ',type,
                                     distance_to_km(seg_distance),duration_to_minutes(seg_duration),
                                     distance_to_km(cum_distance),duration_to_minutes(cum_duration),
                                     speed_to_kph(seg_speed),
diff --git a/src/planetsplitter.c b/src/planetsplitter.c
index b39da9e..0105ef5 100644
--- a/src/planetsplitter.c
+++ b/src/planetsplitter.c
@@ -76,6 +76,7 @@ int main(int argc,char** argv)
  int         max_iterations=5;
  char       *dirname=NULL,*prefix=NULL,*tagging=NULL,*errorlog=NULL;
  int         option_parse_only=0,option_process_only=0;
+ int         option_append=0,option_keep=0,option_changes=0;
  int         option_filenames=0;
  int         option_prune_isolated=500,option_prune_short=5,option_prune_straight=3;
  int         arg;
@@ -104,6 +105,12 @@ int main(int argc,char** argv)
        option_parse_only=1;
     else if(!strcmp(argv[arg],"--process-only"))
        option_process_only=1;
+    else if(!strcmp(argv[arg],"--append"))
+       option_append=1;
+    else if(!strcmp(argv[arg],"--keep"))
+       option_keep=1;
+    else if(!strcmp(argv[arg],"--changes"))
+       option_changes=1;
     else if(!strcmp(argv[arg],"--loggable"))
        option_loggable=1;
     else if(!strcmp(argv[arg],"--logtime"))
@@ -140,6 +147,9 @@ int main(int argc,char** argv)
  if(option_parse_only && option_process_only)
     print_usage(0,NULL,"Cannot use '--parse-only' and '--process-only' at the same time.");
 
+ if(option_append && option_process_only)
+    print_usage(0,NULL,"Cannot use '--append' and '--process-only' at the same time.");
+
  if(option_filenames && option_process_only)
     print_usage(0,NULL,"Cannot use '--process-only' and filenames at the same time.");
 
@@ -162,7 +172,6 @@ int main(int argc,char** argv)
        option_tmpdirname=dirname;
    }
 
- 
  if(!option_process_only)
    {
     if(tagging)
@@ -195,18 +204,18 @@ int main(int argc,char** argv)
 
  /* Create new node, segment, way and relation variables */
 
- Nodes=NewNodeList(option_parse_only||option_process_only);
+ Nodes=NewNodeList(option_append||option_changes,option_process_only);
 
- Segments=NewSegmentList(option_parse_only||option_process_only);
+ Segments=NewSegmentList(option_append||option_changes,option_process_only);
 
- Ways=NewWayList(option_parse_only||option_process_only);
+ Ways=NewWayList(option_append||option_changes,option_process_only);
 
- Relations=NewRelationList(option_parse_only||option_process_only);
+ Relations=NewRelationList(option_append||option_changes,option_process_only);
 
  /* Create the error log file */
 
  if(errorlog)
-    open_errorlog(FileName(dirname,prefix,errorlog),option_parse_only||option_process_only);
+    open_errorlog(FileName(dirname,prefix,errorlog),option_append||option_changes||option_process_only);
 
  /* Parse the file */
 
@@ -229,27 +238,54 @@ if(!option_process_only)
             exit(EXIT_FAILURE);
            }
 
-         printf("\nParse OSM Data [%s]\n==============\n\n",argv[arg]);
-         fflush(stdout);
+         if(option_changes)
+           {
+            printf("\nParse OSC Data [%s]\n==============\n\n",argv[arg]);
+            fflush(stdout);
 
-         if(ParseOSM(file,Nodes,Segments,Ways,Relations))
-            exit(EXIT_FAILURE);
+            if(ParseOSC(file,Nodes,Segments,Ways,Relations))
+               exit(EXIT_FAILURE);
+           }
+         else
+           {
+            printf("\nParse OSM Data [%s]\n==============\n\n",argv[arg]);
+            fflush(stdout);
+
+            if(ParseOSM(file,Nodes,Segments,Ways,Relations))
+               exit(EXIT_FAILURE);
+           }
 
          fclose(file);
         }
      }
    else
      {
-      printf("\nParse OSM Data\n==============\n\n");
-      fflush(stdout);
+      if(option_changes)
+        {
+         printf("\nParse OSC Data\n==============\n\n");
+         fflush(stdout);
+
+         if(ParseOSC(stdin,Nodes,Segments,Ways,Relations))
+            exit(EXIT_FAILURE);
+        }
+      else
+        {
+         printf("\nParse OSM Data\n==============\n\n");
+         fflush(stdout);
 
-      if(ParseOSM(stdin,Nodes,Segments,Ways,Relations))
-         exit(EXIT_FAILURE);
+         if(ParseOSM(stdin,Nodes,Segments,Ways,Relations))
+            exit(EXIT_FAILURE);
+        }
      }
 
    DeleteXMLTaggingRules();
   }
 
+ FinishNodeList(Nodes);
+ FinishSegmentList(Segments);
+ FinishWayList(Ways);
+ FinishRelationList(Relations);
+
  if(option_parse_only)
    {
     FreeNodeList(Nodes,1);
@@ -260,38 +296,47 @@ if(!option_process_only)
     return(0);
    }
 
- /* Process the data */
 
- printf("\nProcess OSM Data\n================\n\n");
+ /* Sort the data */
+
+ printf("\nSort OSM Data\n=============\n\n");
  fflush(stdout);
 
  /* Sort the nodes, segments, ways and relations */
 
  SortNodeList(Nodes);
 
- SortSegmentList(Segments,0);
+ if(option_changes)
+    ApplySegmentChanges(Segments);
+
+ SortSegmentList(Segments);
 
  SortWayList(Ways);
 
  SortRelationList(Relations);
 
- /* Remove bad segments (must be after sorting the nodes and segments) */
+ /* Process the data */
 
- RemoveBadSegments(Nodes,Segments);
+ printf("\nProcess OSM Data\n================\n\n");
+ fflush(stdout);
 
- /* Remove non-highway nodes (must be after removing the bad segments) */
+ /* Extract the way names (must be before using the ways) */
 
- RemoveNonHighwayNodes(Nodes,Segments);
+ ExtractWayNames(Ways,option_keep||option_changes);
 
- /* Process the route relations and first part of turn relations (must be before compacting the ways) */
+ /* Remove bad segments (must be after sorting the nodes, segments and ways) */
+
+ RemoveBadSegments(Segments,Nodes,Ways,option_keep||option_changes);
+
+ /* Remove non-highway nodes (must be after removing the bad segments) */
 
- ProcessRouteRelations(Relations,Ways);
+ RemoveNonHighwayNodes(Nodes,Segments,option_keep||option_changes);
 
- ProcessTurnRelations1(Relations,Nodes,Ways);
+ /* Process the route relations and first part of turn relations (must be before compacting the ways) */
 
- /* Compact the ways (must be before measuring the segments) */
+ ProcessRouteRelations(Relations,Ways,option_keep||option_changes);
 
- CompactWayList(Ways);
+ ProcessTurnRelations1(Relations,Nodes,Ways,option_keep||option_changes);
 
  /* Measure the segments and replace node/way id with index (must be after removing non-highway nodes) */
 
@@ -299,16 +344,27 @@ if(!option_process_only)
 
  /* Index the segments */
 
- IndexSegments(Segments,Nodes);
+ IndexSegments(Segments,Nodes,Ways);
 
  /* Convert the turn relations from ways into nodes */
 
  ProcessTurnRelations2(Relations,Nodes,Segments,Ways);
 
+ /* Compact the ways (must be after turn relations 2) */
+
+ CompactWayList(Ways,Segments);
+
+ /* Index the segments */
+
+ IndexSegments(Segments,Nodes,Ways);
+
  /* Prune unwanted nodes/segments. */
 
  if(option_prune_straight || option_prune_isolated || option_prune_short)
    {
+    printf("\nPrune Unneeded Data\n===================\n\n");
+    fflush(stdout);
+
     StartPruning(Nodes,Segments,Ways);
 
     if(option_prune_straight)
@@ -321,6 +377,14 @@ if(!option_process_only)
        PruneShortSegments(Nodes,Segments,Ways,option_prune_short);
 
     FinishPruning(Nodes,Segments,Ways);
+
+    /* Remove the pruned nodes and segments and update the indexes */
+
+    RemovePrunedNodes(Nodes,Segments);
+    RemovePrunedSegments(Segments,Ways);
+    CompactWayList(Ways,Segments);
+    RemovePrunedTurnRelations(Relations,Nodes);
+    IndexSegments(Segments,Nodes,Ways);
    }
 
  /* Repeated iteration on Super-Nodes and Super-Segments */
@@ -363,17 +427,13 @@ if(!option_process_only)
        SuperSegments=SuperSegments2;
       }
 
-    /* Sort the super-segments */
-
-    SortSegmentList(SuperSegments,0);
-
-    /* Remove duplicated super-segments */
+    /* Sort the super-segments and remove duplicates */
 
-    DeduplicateSegments(SuperSegments,Nodes,Ways);
+    DeduplicateSuperSegments(SuperSegments,Ways);
 
     /* Index the segments */
 
-    IndexSegments(SuperSegments,Nodes);
+    IndexSegments(SuperSegments,Nodes,Ways);
 
     /* Check for end condition */
 
@@ -402,38 +462,28 @@ if(!option_process_only)
 
  Segments=MergedSegments;
 
- /* Sort and re-index the segments */
+ /* Re-index the merged segments */
 
- SortSegmentList(Segments,0);
-
- IndexSegments(Segments,Nodes);
+ IndexSegments(Segments,Nodes,Ways);
 
  /* Cross reference the nodes and segments */
 
  printf("\nCross-Reference Nodes and Segments\n==================================\n\n");
  fflush(stdout);
 
- /* Sort the nodes geographically and update the segment indexes accordingly */
+ /* Sort the nodes and segments geographically */
 
  SortNodeListGeographically(Nodes);
 
- UpdateSegments(Segments,Nodes,Ways);
-
- /* Sort the segments geographically and re-index them */
-
- SortSegmentList(Segments,0);
-
- IndexSegments(Segments,Nodes);
-
- /* Update the nodes */
+ SortSegmentListGeographically(Segments,Nodes);
 
- UpdateNodes(Nodes,Segments);
+ /* Re-index the segments */
 
- /* Fix the turn relations after sorting nodes geographically */
+ IndexSegments(Segments,Nodes,Ways);
 
- UpdateTurnRelations(Relations,Nodes,Segments);
+ /* Sort the turn relations geographically */
 
- SortTurnRelationList(Relations);
+ SortTurnRelationListGeographically(Relations,Nodes,Segments);
 
  /* Output the results */
 
@@ -442,7 +492,7 @@ if(!option_process_only)
 
  /* Write out the nodes */
 
- SaveNodeList(Nodes,FileName(dirname,prefix,"nodes.mem"));
+ SaveNodeList(Nodes,FileName(dirname,prefix,"nodes.mem"),Segments);
 
  FreeNodeList(Nodes,0);
 
@@ -508,6 +558,7 @@ static void print_usage(int detail,const char *argerr,const char *err)
          "                      [--loggable] [--logtime]\n"
          "                      [--errorlog[=<name>]]\n"
          "                      [--parse-only | --process-only]\n"
+         "                      [--append] [--keep] [--changes]\n"
          "                      [--max-iterations=<number>]\n"
          "                      [--prune-none]\n"
          "                      [--prune-isolated=<len>]\n"
@@ -556,15 +607,18 @@ static void print_usage(int detail,const char *argerr,const char *err)
             "--errorlog[=<name>]       Log parsing errors to 'error.log' or the given name\n"
             "                          (the '--dir' and '--prefix' options are applied).\n"
             "\n"
-            "--parse-only              Parse the input OSM files and store the results.\n"
+            "--parse-only              Parse the OSM/OSC file(s) and store the results.\n"
             "--process-only            Process the stored results from previous option.\n"
+            "--append                  Parse the OSM file(s) and append to existing results.\n"
+            "--keep                    Keep the intermediate files after parsing & sorting.\n"
+            "--changes                 Parse the data as an OSC file and apply the changes.\n"
             "\n"
             "--max-iterations=<number> The number of iterations for finding super-nodes\n"
             "                          (defaults to 5).\n"
             "\n"
             "--prune-none              Disable the prune options below, they are re-enabled\n"
             "                          by adding them to the command line after this option.\n"
-            "--prune-isolated=<len>    Remove small disconnected groups of segments\n"
+            "--prune-isolated=<len>    Remove access from small disconnected segment groups\n"
             "                          (defaults to removing groups under 500m).\n"
             "--prune-short=<len>       Remove short segments (defaults to removing segments\n"
             "                          up to a maximum length of 5m).\n"
diff --git a/src/profiles.c b/src/profiles.c
index 2404632..db21742 100644
--- a/src/profiles.c
+++ b/src/profiles.c
@@ -209,7 +209,7 @@ static int speedType_function(const char *_tag_,int _type_,const char *highway,c
 
     highwaytype=HighwayType(highway);
 
-    if(highwaytype==Way_Count)
+    if(highwaytype==Highway_None)
        XMLPARSE_INVALID(_tag_,highway);
 
     XMLPARSE_ASSERT_FLOATING(_tag_,kph); speed=atof(kph);
@@ -262,7 +262,7 @@ static int preferenceType_function(const char *_tag_,int _type_,const char *high
 
     highwaytype=HighwayType(highway);
 
-    if(highwaytype==Way_Count)
+    if(highwaytype==Highway_None)
        XMLPARSE_INVALID(_tag_,highway);
 
     XMLPARSE_ASSERT_FLOATING(_tag_,percent); p=atof(percent);
@@ -315,7 +315,7 @@ static int propertyType_function(const char *_tag_,int _type_,const char *type,c
 
     property=PropertyType(type);
 
-    if(property==Property_Count)
+    if(property==Property_None)
        XMLPARSE_INVALID(_tag_,type);
 
     XMLPARSE_ASSERT_FLOATING(_tag_,percent); p=atof(percent);
@@ -697,7 +697,7 @@ int UpdateProfile(Profile *profile,Ways *ways)
 
  /* Normalise the highway preferences into the range ~0 -> 1 */
 
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     if(profile->highway[i]<0)
        profile->highway[i]=0;
@@ -709,7 +709,7 @@ int UpdateProfile(Profile *profile,Ways *ways)
  if(hmax==0)
     return(1);
 
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     profile->highway[i]/=hmax;
 
@@ -748,7 +748,7 @@ int UpdateProfile(Profile *profile,Ways *ways)
 
  profile->max_speed=0;
 
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
     if(profile->speed[i]>profile->max_speed)
        profile->max_speed=profile->speed[i];
 
@@ -790,12 +790,12 @@ void PrintProfile(const Profile *profile)
 
  printf("\n");
 
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
     printf("Highway %-12s: %3d%%\n",HighwayName(i),(int)profile->highway[i]);
 
  printf("\n");
 
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
     if(profile->highway[i])
        printf("Speed on %-12s: %3d km/h / %2.0f mph\n",HighwayName(i),profile->speed[i],(double)profile->speed[i]/1.6);
 
@@ -835,12 +835,12 @@ void PrintProfilesXML(void)
     printf("  <profile name=\"%s\" transport=\"%s\">\n",loaded_profiles[j]->name,TransportName(loaded_profiles[j]->transport));
 
     printf("    <speeds>\n");
-    for(i=1;i<Way_Count;i++)
+    for(i=1;i<Highway_Count;i++)
        printf("      <speed highway=\"%s\"%s kph=\"%d\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->speed[i]);
     printf("    </speeds>\n");
 
     printf("    <preferences>\n");
-    for(i=1;i<Way_Count;i++)
+    for(i=1;i<Highway_Count;i++)
        printf("      <preference highway=\"%s\"%s percent=\"%.0f\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->highway[i]);
     printf("    </preferences>\n");
 
@@ -890,7 +890,7 @@ void PrintProfilesJSON(void)
 
  printf("  // Highway types\n");
  printf("  highways: { ");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
     printf("%s%s: %d",i==1?"":", ",HighwayName(i),i);
  printf(" },\n");
  printf("\n");
@@ -908,24 +908,24 @@ void PrintProfilesJSON(void)
 
  printf("  // Allowed highways\n");
  printf("  profile_highway: {\n");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     printf("    %12s: { ",HighwayName(i));
     for(j=0;j<nloaded_profiles;j++)
        printf("%s%s: %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->highway[i]);
-    printf(" }%s\n",i==(Way_Count-1)?"":",");
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
    }
  printf("     },\n");
  printf("\n");
 
  printf("  // Speed limits\n");
  printf("  profile_speed: {\n");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     printf("    %12s: { ",HighwayName(i));
     for(j=0;j<nloaded_profiles;j++)
        printf("%s%s: %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->speed[i]);
-    printf(" }%s\n",i==(Way_Count-1)?"":",");
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
    }
  printf("     },\n");
  printf("\n");
@@ -999,7 +999,7 @@ void PrintProfilesPerl(void)
 
  printf("  # Highway types\n");
  printf("  highways => { ");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
     printf("%s%s => %d",i==1?"":", ",HighwayName(i),i);
  printf(" },\n");
  printf("\n");
@@ -1017,24 +1017,24 @@ void PrintProfilesPerl(void)
 
  printf("  # Allowed highways\n");
  printf("  profile_highway => {\n");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     printf("  %12s => {",HighwayName(i));
     for(j=0;j<nloaded_profiles;j++)
        printf("%s %s => %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->highway[i]);
-    printf(" }%s\n",i==(Way_Count-1)?"":",");
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
    }
  printf("     },\n");
  printf("\n");
 
  printf("  # Speed limits\n");
  printf("  profile_speed => {\n");
- for(i=1;i<Way_Count;i++)
+ for(i=1;i<Highway_Count;i++)
    {
     printf("  %12s => {",HighwayName(i));
     for(j=0;j<nloaded_profiles;j++)
        printf("%s %s => %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->speed[i]);
-    printf(" }%s\n",i==(Way_Count-1)?"":",");
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
    }
  printf("     },\n");
  printf("\n");
diff --git a/src/profiles.h b/src/profiles.h
index 08b485f..41975af 100644
--- a/src/profiles.h
+++ b/src/profiles.h
@@ -37,10 +37,10 @@ typedef struct _Profile
 
  transports_t allow;                     /*+ The type of transport expressed as a bitmask. +*/
 
- score_t      highway[Way_Count];        /*+ A floating point preference for travel on the highway. +*/
+ score_t      highway[Highway_Count];    /*+ A floating point preference for travel on the highway. +*/
  score_t      max_pref;                  /*+ The maximum preference for any highway type. +*/
 
- speed_t      speed[Way_Count];          /*+ The maximum speed on each type of highway. +*/
+ speed_t      speed[Highway_Count];      /*+ The maximum speed on each type of highway. +*/
  speed_t      max_speed;                 /*+ The maximum speed for any highway type. +*/
 
  score_t      props_yes[Property_Count]; /*+ A floating point preference for ways with this attribute. +*/
diff --git a/src/prunex.c b/src/prunex.c
index dc10610..ffd7be5 100644
--- a/src/prunex.c
+++ b/src/prunex.c
@@ -21,7 +21,6 @@
 
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "types.h"
 #include "segments.h"
@@ -37,6 +36,11 @@
 #include "logging.h"
 
 
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
 /* Local functions */
 
 static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx);
@@ -63,6 +67,9 @@ void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  SegmentX segmentx;
  index_t index=0,lastnode1=NO_NODE;
 
+ if(segmentsx->number==0)
+    return;
+
  /* Print the start message */
 
  printf_first("Adding Extra Segment Indexes: Segments=0");
@@ -71,11 +78,11 @@ void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
  segmentsx->next1=(index_t*)calloc(segmentsx->number,sizeof(index_t));
 
- assert(segmentsx->next1); /* Check malloc() worked */
+ logassert(segmentsx->next1,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
  /* Open the file read-only */
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
  /* Read the on-disk image */
 
@@ -121,61 +128,10 @@ void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
 void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 {
- index_t i,pruned=0;
- int fd;
+ if(segmentsx->next1)
+    free(segmentsx->next1);
 
-
- /* Delete the pruned segments */
-
- free(segmentsx->next1);
  segmentsx->next1=NULL;
-
- SortSegmentList(segmentsx,1);
-
- IndexSegments(segmentsx,nodesx);
-
-
- /* Delete the pruned nodes */
-
- printf_first("Marking Pruned Nodes: Nodes=0 Pruned=0");
-
- /* Re-open the file read-only and a new file writeable */
-
- nodesx->fd=ReOpenFile(nodesx->filename);
-
- DeleteFile(nodesx->filename);
-
- fd=OpenFileNew(nodesx->filename);
-
- /* Modify the on-disk image */
-
- for(i=0;i<nodesx->number;i++)
-   {
-    NodeX nodex;
-
-    ReadFile(nodesx->fd,&nodex,sizeof(NodeX));
-
-    if(segmentsx->firstnode[i]==NO_SEGMENT)
-      {
-       pruned++;
-       nodex.latitude=NO_LATLONG;
-       nodex.longitude=NO_LATLONG;
-      }
-
-    WriteFile(fd,&nodex,sizeof(NodeX));
-
-    if(!((i+1)%10000))
-       printf_middle("Marking Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,pruned);
-   }
-
- /* Close the files */
-
- nodesx->fd=CloseFile(nodesx->fd);
- CloseFile(fd);
-
- /* Print the final message */
-
- printf_last("Marked Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,pruned);
 }
 
 
@@ -194,166 +150,232 @@ void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
 void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum)
 {
- index_t i,j;
- index_t nregions=0,npruned=0;
+ transport_t transport;
  BitMask *connected,*region;
  index_t *regionsegments,*othersegments;
  int nallocregionsegments,nallocothersegments;
+ index_t nnewways=0;
+ int fd;
 
  if(nodesx->number==0 || segmentsx->number==0)
     return;
 
- /* Print the start message */
-
- printf_first("Pruning Isolated Regions: Segments=0 Pruned=0");
-
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFile(nodesx->filename);
- segmentsx->data=MapFileWriteable(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFile(nodesx->filename);
- segmentsx->fd=ReOpenFileWriteable(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
+ fd=ReOpenFileWriteable(waysx->filename_tmp);
+
  connected=AllocBitMask(segmentsx->number);
  region   =AllocBitMask(segmentsx->number);
 
- assert(connected); /* Check AllocBitMask() worked */
- assert(region);    /* Check AllocBitMask() worked */
+ 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 */
 
  regionsegments=(index_t*)malloc((nallocregionsegments=1024)*sizeof(index_t));
  othersegments =(index_t*)malloc((nallocothersegments =1024)*sizeof(index_t));
 
- assert(regionsegments); /* Check malloc() worked */
- assert(othersegments);  /* Check malloc() worked */
+ 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 */
 
- /* Loop through the segments and find the disconnected ones */
+ /* Loop through the transport types */
 
- for(i=0;i<segmentsx->number;i++)
+ for(transport=Transport_None+1;transport<Transport_Count;transport++)
    {
-    int nregionsegments=0,nothersegments=0;
-    distance_t total=0;
-    SegmentX *segmentx;
+    index_t i,j;
+    index_t nregions=0,npruned=0,nadjusted=0;
+    const char *transport_str=TransportName(transport);
+    transports_t transports=TRANSPORTS(transport);
 
-    segmentx=LookupSegmentX(segmentsx,i,1);
+    /* Print the start message */
 
-    if(IsPrunedSegmentX(segmentx))
-       goto endloop;
+    printf_first("Pruning Isolated Regions (%s): Segments=0 Adjusted=0 Pruned=0",transport_str);
 
-    if(IsBitSet(connected,i))
-       goto endloop;
+    /* Loop through the segments and find the disconnected ones */
 
-    othersegments[nothersegments++]=i;
-    SetBit(region,i);
+    ClearAllBits(connected,segmentsx->number);
+    ClearAllBits(region   ,segmentsx->number);
 
-    do
+    for(i=0;i<segmentsx->number;i++)
       {
-       index_t thissegment,nodes[2];
-       WayX *wayx;
+       int nregionsegments=0,nothersegments=0;
+       distance_t total=0;
+       SegmentX *segmentx;
+       WayX *wayx,tmpwayx;
 
-       thissegment=othersegments[--nothersegments];
+       if(IsBitSet(connected,i))
+          goto endloop;
 
-       if(nregionsegments==nallocregionsegments)
-          regionsegments=(index_t*)realloc(regionsegments,(nallocregionsegments+=1024)*sizeof(index_t));
+       segmentx=LookupSegmentX(segmentsx,i,1);
 
-       regionsegments[nregionsegments++]=thissegment;
+       if(IsPrunedSegmentX(segmentx))
+          goto endloop;
 
-       segmentx=LookupSegmentX(segmentsx,thissegment,1);
+       if(segmentx->way<waysx->number)
+          wayx=LookupWayX(waysx,segmentx->way,1);
+       else
+          SeekReadFile(fd,(wayx=&tmpwayx),sizeof(WayX),segmentx->way*sizeof(WayX));
 
-       nodes[0]=segmentx->node1;
-       nodes[1]=segmentx->node2;
-       total+=DISTANCE(segmentx->distance);
+       if(!(wayx->way.allow&transports))
+          goto endloop;
 
-       wayx=LookupWayX(waysx,segmentx->way,1);
+       othersegments[nothersegments++]=i;
+       SetBit(region,i);
 
-       for(j=0;j<2;j++)
+       do
          {
-          NodeX *nodex=LookupNodeX(nodesx,nodes[j],1);
+          index_t thissegment,nodes[2];
 
-          if(!(nodex->allow&wayx->way.allow)) /* some type of traffic must be allowed */
-             continue;
+          thissegment=othersegments[--nothersegments];
 
-          segmentx=FirstSegmentX(segmentsx,nodes[j],1);
+          if(nregionsegments==nallocregionsegments)
+             regionsegments=(index_t*)realloc(regionsegments,(nallocregionsegments+=1024)*sizeof(index_t));
 
-          while(segmentx)
+          regionsegments[nregionsegments++]=thissegment;
+
+          segmentx=LookupSegmentX(segmentsx,thissegment,1);
+
+          nodes[0]=segmentx->node1;
+          nodes[1]=segmentx->node2;
+          total+=DISTANCE(segmentx->distance);
+
+          for(j=0;j<2;j++)
             {
-             index_t segment=IndexSegmentX(segmentsx,segmentx);
+             NodeX *nodex=LookupNodeX(nodesx,nodes[j],1);
+
+             if(!(nodex->allow&transports))
+                continue;
 
-             if(segment!=thissegment)
+             segmentx=FirstSegmentX(segmentsx,nodes[j],1);
+
+             while(segmentx)
                {
-                WayX *way2x=LookupWayX(waysx,segmentx->way,2);
+                index_t segment=IndexSegmentX(segmentsx,segmentx);
 
-                if(wayx->way.allow&way2x->way.allow) /* some type of traffic must be allowed */
+                if(segment!=thissegment)
                   {
-                   /* Already connected - finish */
+                   if(segmentx->way<waysx->number)
+                      wayx=LookupWayX(waysx,segmentx->way,1);
+                   else
+                      SeekReadFile(fd,(wayx=&tmpwayx),sizeof(WayX),segmentx->way*sizeof(WayX));
 
-                   if(IsBitSet(connected,segment))
+                   if(wayx->way.allow&transports)
                      {
-                      total=minimum;
-                      goto foundconnection;
-                     }
+                      /* Already connected - finish */
 
-                   /* Not in region - add to list */
+                      if(IsBitSet(connected,segment))
+                        {
+                         total=minimum;
+                         goto foundconnection;
+                        }
 
-                   if(!IsBitSet(region,segment))
-                     {
-                      if(nothersegments==nallocothersegments)
-                         othersegments=(index_t*)realloc(othersegments,(nallocothersegments+=1024)*sizeof(index_t));
+                      /* Not in region - add to list */
 
-                      othersegments[nothersegments++]=segment;
-                      SetBit(region,segment);
+                      if(!IsBitSet(region,segment))
+                        {
+                         if(nothersegments==nallocothersegments)
+                            othersegments=(index_t*)realloc(othersegments,(nallocothersegments+=1024)*sizeof(index_t));
+
+                         othersegments[nothersegments++]=segment;
+                         SetBit(region,segment);
+                        }
                      }
                   }
-               }
 
-             segmentx=NextSegmentX(segmentsx,segmentx,nodes[j]);
+                segmentx=NextSegmentX(segmentsx,segmentx,nodes[j]);
+               }
             }
          }
-      }
-    while(nothersegments>0 && total<minimum);
+       while(nothersegments>0 && total<minimum);
 
-   foundconnection:
+      foundconnection:
 
-    /* Prune the segments or mark them as connected */
-
-    if(total<minimum)
-      {
-       nregions++;
+       /* Prune the segments or mark them as connected */
 
-       for(j=0;j<nregionsegments;j++)
+       if(total<minimum)        /* not connected - delete them */
          {
-          SegmentX *segmentx=LookupSegmentX(segmentsx,regionsegments[j],1);
+          nregions++;
+
+          for(j=0;j<nregionsegments;j++)
+            {
+             SegmentX *segmentx;
+             WayX *wayx,tmpwayx;
+
+             SetBit(connected,regionsegments[j]); /* not really connected, but don't need to check again */
+             ClearBit(region,regionsegments[j]);
+
+             segmentx=LookupSegmentX(segmentsx,regionsegments[j],1);
+
+             if(segmentx->way<waysx->number)
+                wayx=LookupWayX(waysx,segmentx->way,1);
+             else
+                SeekReadFile(fd,(wayx=&tmpwayx),sizeof(WayX),segmentx->way*sizeof(WayX));
+
+             if(wayx->way.allow==transports)
+               {
+                prune_segment(segmentsx,segmentx);
+
+                npruned++;
+               }
+             else
+               {
+                if(segmentx->way<waysx->number) /* create a new way */
+                  {
+                   tmpwayx=*wayx;
+
+                   tmpwayx.way.allow&=~transports;
 
-          SetBit(connected,regionsegments[j]);
+                   segmentx->way=waysx->number+nnewways;
 
-          prune_segment(segmentsx,segmentx);
+                   SeekWriteFile(fd,&tmpwayx,sizeof(WayX),segmentx->way*sizeof(WayX));
 
-          npruned++;
+                   nnewways++;
+
+                   PutBackSegmentX(segmentsx,segmentx);
+                  }
+                else            /* modify the existing one */
+                  {
+                   tmpwayx.way.allow&=~transports;
+
+                   SeekWriteFile(fd,&tmpwayx,sizeof(WayX),segmentx->way*sizeof(WayX));
+                  }
+
+                nadjusted++;
+               }
+            }
          }
-      }
-    else
-      {
-       for(j=0;j<nregionsegments;j++)
+       else                     /* connected - mark as part of the main region */
          {
-          SetBit(connected,regionsegments[j]);
-          ClearBit(region,regionsegments[j]);
-         }
+          for(j=0;j<nregionsegments;j++)
+            {
+             SetBit(connected,regionsegments[j]);
+             ClearBit(region,regionsegments[j]);
+            }
 
-       for(j=0;j<nothersegments;j++)
-         {
-          SetBit(connected,othersegments[j]);
-          ClearBit(region,othersegments[j]);
+          for(j=0;j<nothersegments;j++)
+            {
+             SetBit(connected,othersegments[j]);
+             ClearBit(region,othersegments[j]);
+            }
          }
+
+      endloop:
+
+       if(!((i+1)%10000))
+          printf_middle("Pruning Isolated Regions (%s): Segments=%"Pindex_t" Adjusted=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",transport_str,i+1,nadjusted,npruned,nregions);
       }
 
-   endloop:
+    /* Print the final message */
 
-    if(!((i+1)%10000))
-       printf_middle("Pruning Isolated Regions: Segments=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",i+1,npruned,nregions);
+    printf_last("Pruned Isolated Regions (%s): Segments=%"Pindex_t" Adjusted=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",transport_str,segmentsx->number,nadjusted,npruned,nregions);
    }
 
  /* Unmap from memory / close the files */
@@ -365,18 +387,18 @@ void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,dista
  free(othersegments);
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
  waysx->fd=CloseFile(waysx->fd);
 #endif
 
- /* Print the final message */
+ CloseFile(fd);
 
- printf_last("Pruned Isolated Regions: Segments=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",segmentsx->number,npruned,nregions);
+ waysx->number+=nnewways;
 }
 
 
@@ -407,13 +429,13 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFileWriteable(nodesx->filename);
- segmentsx->data=MapFileWriteable(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFileWriteable(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFileWriteable(nodesx->filename);
- segmentsx->fd=ReOpenFileWriteable(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFileWriteable(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  /* Loop through the segments and find the short ones for possible modification */
@@ -498,6 +520,8 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
                 node1=OtherNode(segmentx,node2);
                }
             }
+          else if(segcount2>2)
+             break;
 
           segmentx=NextSegmentX(segmentsx,segmentx,node2);
          }
@@ -518,6 +542,8 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
                 node4=OtherNode(segmentx,node3);
                }
             }
+          else if(segcount3>2)
+             break;
 
           segmentx=NextSegmentX(segmentsx,segmentx,node3);
          }
@@ -630,32 +656,39 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
           segmentx1->distance+=DISTANCE(segmentx2->distance)/2;
           segmentx3->distance+=DISTANCE(segmentx2->distance)-DISTANCE(segmentx2->distance)/2;
 
-          PutBackSegmentX(segmentsx,segmentx1);
-          PutBackSegmentX(segmentsx,segmentx3);
-
-          prune_segment(segmentsx,segmentx2);
-
           if(segmentx1->node1==node1)
             {
              if(segmentx1->node2!=newnode)
                 modify_segment(segmentsx,segmentx1,node1,newnode);
+             else
+                PutBackSegmentX(segmentsx,segmentx1);
             }
           else /* if(segmentx1->node2==node1) */
             {
              if(segmentx1->node1!=newnode)
                 modify_segment(segmentsx,segmentx1,newnode,node1);
+             else
+                PutBackSegmentX(segmentsx,segmentx1);
             }
 
           if(segmentx3->node1==node4)
             {
              if(segmentx3->node2!=newnode)
                 modify_segment(segmentsx,segmentx3,node4,newnode);
+             else
+                PutBackSegmentX(segmentsx,segmentx3);
             }
           else /* if(segmentx3->node2==node4) */
             {
              if(segmentx3->node1!=newnode)
                 modify_segment(segmentsx,segmentx3,newnode,node4);
+             else
+                PutBackSegmentX(segmentsx,segmentx3);
             }
+
+          ReLookupSegmentX(segmentsx,segmentx2);
+
+          prune_segment(segmentsx,segmentx2);
          }
        else                     /* third case in diagram - prune one segment */
          {
@@ -724,14 +757,14 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
 
           segmentx1->distance+=DISTANCE(segmentx2->distance);
 
-          PutBackSegmentX(segmentsx,segmentx1);
-
-          prune_segment(segmentsx,segmentx2);
-
           if(segmentx1->node1==node1)
              modify_segment(segmentsx,segmentx1,node1,node3);
           else /* if(segmentx1->node2==node1) */
              modify_segment(segmentsx,segmentx1,node3,node1);
+
+          ReLookupSegmentX(segmentsx,segmentx2);
+
+          prune_segment(segmentsx,segmentx2);
          }
 
        npruned++;
@@ -746,9 +779,9 @@ void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distanc
  /* Unmap from memory / close the files */
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
@@ -795,30 +828,30 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFile(nodesx->filename);
- segmentsx->data=MapFileWriteable(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFile(nodesx->filename);
- segmentsx->fd=ReOpenFileWriteable(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  checked=AllocBitMask(nodesx->number);
 
- assert(checked); /* Check AllocBitMask() worked */
+ 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));
 
- assert(nodes);    /* Check malloc() worked */
- assert(segments); /* 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));
  lons=(double*)malloc(nalloc*sizeof(double));
 
- assert(lats);    /* Check malloc() worked */
- assert(lons);    /* Check malloc() worked */
+ logassert(lats,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
+ logassert(lons,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
 
  /* Loop through the nodes and find stretchs of simple highway for possible modification */
 
@@ -845,7 +878,22 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
        int segcount=0;
        NodeX *nodex;
 
-       if(!IsBitSet(checked,nodes[current]))
+       /* Get the node data */
+
+       nodex=LookupNodeX(nodesx,nodes[current],1);
+
+       lats[current]=latlong_to_radians(nodex->latitude);
+       lons[current]=latlong_to_radians(nodex->longitude);
+
+       /* Count the segments at the node if not forced to be an end node */
+
+       if(IsBitSet(checked,nodes[current]))
+          ;
+       else if(nodex->flags&NODE_MINIRNDBT)
+          ;
+       else if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
+          ;
+       else
          {
           SegmentX *segmentx;
 
@@ -869,26 +917,13 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
                 node2=OtherNode(segmentx,nodes[current]);
                 way2=segmentx->way;
                }
+             else
+                break;
 
              segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]);
             }
          }
 
-       /* Perform more checks */
-
-       nodex=LookupNodeX(nodesx,nodes[current],1);
-
-       lats[current]=latlong_to_radians(nodex->latitude);
-       lons[current]=latlong_to_radians(nodex->longitude);
-
-       /* Check if allowed due to mini-roundabout and turn restriction */
-
-       if(nodex->flags&NODE_MINIRNDBT)
-          segcount=0;
-
-       if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
-          segcount=0;
-
        /* Check if allowed due to one-way properties */
 
        if(segcount==2)
@@ -1114,8 +1149,6 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
                {
                 segmentx->distance+=distance;
 
-                PutBackSegmentX(segmentsx,segmentx);
-
                 if(segmentx->node1==nodes[lower])
                    modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]);
                 else /* if(segmentx->node2==nodes[lower]) */
@@ -1145,9 +1178,9 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
  free(lons);
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
@@ -1171,6 +1204,7 @@ void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,
 static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx)
 {
  unlink_segment_node1_refs(segmentsx,segmentx);
+
  unlink_segment_node2_refs(segmentsx,segmentx);
 
  segmentx->node1=NO_NODE;
@@ -1204,8 +1238,6 @@ static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newno
     if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
        segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2;
 
-    PutBackSegmentX(segmentsx,segmentx);
-
     temp=newnode1;
     newnode1=newnode2;
     newnode2=temp;
@@ -1223,8 +1255,6 @@ static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newno
 
     segmentsx->next1[thissegment]=segmentsx->firstnode[newnode1];
     segmentsx->firstnode[newnode1]=thissegment;
-
-    PutBackSegmentX(segmentsx,segmentx);
    }
 
  if(newnode2!=segmentx->node2) /* only modify it if the node has changed */
@@ -1233,9 +1263,9 @@ static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newno
 
     segmentx->next2=segmentsx->firstnode[newnode2];
     segmentsx->firstnode[newnode2]=thissegment;
-
-    PutBackSegmentX(segmentsx,segmentx);
    }
+
+ PutBackSegmentX(segmentsx,segmentx);
 }
 
 
diff --git a/src/relationsx.c b/src/relationsx.c
index a3f6099..a55def6 100644
--- a/src/relationsx.c
+++ b/src/relationsx.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -38,18 +37,27 @@
 #include "sorting.h"
 
 
-/* Local functions */
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
 
-static int sort_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b);
-static int deduplicate_by_id(TurnRestrictRelX *relationx,index_t index);
+/* Local variables */
 
-static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b);
+/*+ Temporary file-local variables for use by the sort functions. +*/
+static SegmentsX *sortsegmentsx;
+static NodesX *sortnodesx;
 
+/* Local functions */
 
-/* Variables */
+static int sort_route_by_id(RouteRelX *a,RouteRelX *b);
+static int deduplicate_route_by_id(RouteRelX *relationx,index_t index);
 
-/*+ The command line '--tmpdir' option or its default value. +*/
-extern char *option_tmpdirname;
+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 sort_by_via(TurnRelX *a,TurnRelX *b);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -57,72 +65,87 @@ extern char *option_tmpdirname;
 
   RelationsX *NewRelationList Returns the relation list.
 
-  int append Set to 1 if the file is to be opened for appending (now or later).
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
   ++++++++++++++++++++++++++++++++++++++*/
 
-RelationsX *NewRelationList(int append)
+RelationsX *NewRelationList(int append,int readonly)
 {
  RelationsX *relationsx;
 
  relationsx=(RelationsX*)calloc(1,sizeof(RelationsX));
 
- assert(relationsx); /* Check calloc() worked */
+ logassert(relationsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
 
 
  /* Route Relations */
 
- relationsx->rfilename=(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->rfilename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->rfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- if(append)
-    sprintf(relationsx->rfilename,"%s/relationsx.route.input.tmp",option_tmpdirname);
- else
-    sprintf(relationsx->rfilename,"%s/relationsx.route.%p.tmp",option_tmpdirname,(void*)relationsx);
+ sprintf(relationsx->rfilename    ,"%s/relationsx.route.parsed.mem",option_tmpdirname);
+ sprintf(relationsx->rfilename_tmp,"%s/relationsx.route.%p.tmp"    ,option_tmpdirname,(void*)relationsx);
 
- if(append)
-   {
-    off_t size,position=0;
+ if(append || readonly)
+    if(ExistsFile(relationsx->rfilename))
+      {
+       off_t size,position=0;
+       int rfd;
 
-    relationsx->rfd=OpenFileAppend(relationsx->rfilename);
+       size=SizeFile(relationsx->rfilename);
 
-    size=SizeFile(relationsx->rfilename);
+       rfd=ReOpenFile(relationsx->rfilename);
 
-    while(position<size)
-      {
-       FILESORT_VARINT relationsize;
+       while(position<size)
+         {
+          FILESORT_VARINT relationsize;
 
-       SeekReadFile(relationsx->rfd,&relationsize,FILESORT_VARSIZE,position);
+          SeekReadFile(rfd,&relationsize,FILESORT_VARSIZE,position);
 
-       relationsx->rnumber++;
-       position+=relationsize+FILESORT_VARSIZE;
+          relationsx->rnumber++;
+          position+=relationsize+FILESORT_VARSIZE;
+         }
+
+       CloseFile(rfd);
+
+       RenameFile(relationsx->rfilename ,relationsx->rfilename_tmp);
       }
 
-    SeekFile(relationsx->rfd,size);
-   }
+ if(append)
+    relationsx->rfd=OpenFileAppend(relationsx->rfilename_tmp);
+ else if(!readonly)
+    relationsx->rfd=OpenFileNew(relationsx->rfilename_tmp);
  else
-    relationsx->rfd=OpenFileNew(relationsx->rfilename);
+    relationsx->rfd=-1;
 
 
  /* Turn Restriction Relations */
 
- relationsx->trfilename=(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->trfilename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->trfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- if(append)
-    sprintf(relationsx->trfilename,"%s/relationsx.turn.input.tmp",option_tmpdirname);
- else
-    sprintf(relationsx->trfilename,"%s/relationsx.turn.%p.tmp",option_tmpdirname,(void*)relationsx);
+ sprintf(relationsx->trfilename    ,"%s/relationsx.turn.parsed.mem",option_tmpdirname);
+ sprintf(relationsx->trfilename_tmp,"%s/relationsx.turn.%p.tmp"    ,option_tmpdirname,(void*)relationsx);
 
- if(append)
-   {
-    off_t size;
+ if(append || readonly)
+    if(ExistsFile(relationsx->trfilename))
+      {
+       off_t size;
 
-    relationsx->trfd=OpenFileAppend(relationsx->trfilename);
+       size=SizeFile(relationsx->trfilename);
 
-    size=SizeFile(relationsx->trfilename);
+       relationsx->trnumber=size/sizeof(TurnRelX);
 
-    relationsx->trnumber=size/sizeof(TurnRestrictRelX);
-   }
+       RenameFile(relationsx->trfilename,relationsx->trfilename_tmp);
+      }
+
+ if(append)
+    relationsx->trfd=OpenFileAppend(relationsx->trfilename_tmp);
+ else if(!readonly)
+    relationsx->trfd=OpenFileNew(relationsx->trfilename_tmp);
  else
-    relationsx->trfd=OpenFileNew(relationsx->trfilename);
+    relationsx->trfd=-1;
 
  return(relationsx);
 }
@@ -133,25 +156,31 @@ RelationsX *NewRelationList(int append)
 
   RelationsX *relationsx The set of relations to be freed.
 
-  int keep Set to 1 if the file is to be kept (for appending later).
+  int keep If set then the results file is to be kept.
   ++++++++++++++++++++++++++++++++++++++*/
 
 void FreeRelationList(RelationsX *relationsx,int keep)
 {
  /* Route relations */
 
- if(!keep)
-    DeleteFile(relationsx->rfilename);
+ if(keep)
+    RenameFile(relationsx->rfilename_tmp,relationsx->rfilename);
+ else
+    DeleteFile(relationsx->rfilename_tmp);
 
  free(relationsx->rfilename);
+ free(relationsx->rfilename_tmp);
 
 
  /* Turn Restriction relations */
 
- if(!keep)
-    DeleteFile(relationsx->trfilename);
+ if(keep)
+    RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
+ else
+    DeleteFile(relationsx->trfilename_tmp);
 
  free(relationsx->trfilename);
+ free(relationsx->trfilename_tmp);
 
  free(relationsx);
 }
@@ -175,15 +204,15 @@ void FreeRelationList(RelationsX *relationsx,int keep)
   int nrelations The number of relations that are members of the relation.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void AppendRouteRelation(RelationsX* relationsx,relation_t id,
-                         transports_t routes,
-                         way_t *ways,int nways,
-                         relation_t *relations,int nrelations)
+void AppendRouteRelationList(RelationsX* relationsx,relation_t id,
+                             transports_t routes,
+                             way_t *ways,int nways,
+                             relation_t *relations,int nrelations)
 {
- RouteRelX relationx;
+ RouteRelX relationx={0};
  FILESORT_VARINT size;
- way_t noway=NO_WAY;
- relation_t norelation=NO_RELATION;
+ way_t noway=NO_WAY_ID;
+ relation_t norelation=NO_RELATION_ID;
 
  relationx.id=id;
  relationx.routes=routes;
@@ -201,7 +230,7 @@ void AppendRouteRelation(RelationsX* relationsx,relation_t id,
 
  relationsx->rnumber++;
 
- assert(relationsx->rnumber!=0); /* Zero marks the high-water mark for relations. */
+ logassert(relationsx->rnumber!=0,"Too many route relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
 }
 
 
@@ -223,11 +252,11 @@ void AppendRouteRelation(RelationsX* relationsx,relation_t id,
   transports_t except The set of transports allowed to bypass the restriction.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
-                                way_t from,way_t to,node_t via,
-                                TurnRestriction restriction,transports_t except)
+void AppendTurnRelationList(RelationsX* relationsx,relation_t id,
+                            way_t from,way_t to,node_t via,
+                            TurnRestriction restriction,transports_t except)
 {
- TurnRestrictRelX relationx={0};
+ TurnRelX relationx={0};
 
  relationx.id=id;
  relationx.from=from;
@@ -236,11 +265,27 @@ void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
  relationx.restriction=restriction;
  relationx.except=except;
 
- WriteFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
+ WriteFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
 
  relationsx->trnumber++;
 
- assert(relationsx->trnumber!=0); /* Zero marks the high-water mark for relations. */
+ logassert(relationsx->trnumber!=0,"Too many turn relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending relations and change the filename over.
+
+  RelationsX *relationsx The relations that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishRelationList(RelationsX *relationsx)
+{
+ if(relationsx->rfd!=-1)
+    relationsx->rfd =CloseFile(relationsx->rfd);
+
+ if(relationsx->trfd!=-1)
+    relationsx->trfd=CloseFile(relationsx->trfd);
 }
 
 
@@ -252,15 +297,42 @@ void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
 
 void SortRelationList(RelationsX* relationsx)
 {
- /* Close the files (finished appending) */
+ /* Route Relations */
 
- relationsx->rfd=CloseFile(relationsx->rfd);
+ if(relationsx->rnumber)
+   {
+    index_t rxnumber;
+    int rfd;
 
- relationsx->trfd=CloseFile(relationsx->trfd);
+    /* Print the start message */
 
+    printf_first("Sorting Route Relations");
 
- /* Route Relations */
+    /* Re-open the file read-only and a new file writeable */
+
+    relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
+
+    DeleteFile(relationsx->rfilename_tmp);
+
+    rfd=OpenFileNew(relationsx->rfilename_tmp);
 
+    /* Sort the relations */
+
+    rxnumber=relationsx->rnumber;
+
+    relationsx->rnumber=filesort_vary(relationsx->rfd,rfd,NULL,
+                                                          (int (*)(const void*,const void*))sort_route_by_id,
+                                                          (int (*)(void*,index_t))deduplicate_route_by_id);
+
+    /* Close the files */
+
+    relationsx->rfd=CloseFile(relationsx->rfd);
+    CloseFile(rfd);
+
+    /* Print the final message */
+
+    printf_last("Sorted Route Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,rxnumber,rxnumber-relationsx->rnumber);
+   }
 
  /* Turn Restriction Relations. */
 
@@ -275,18 +347,19 @@ void SortRelationList(RelationsX* relationsx)
 
     /* Re-open the file read-only and a new file writeable */
 
-    relationsx->trfd=ReOpenFile(relationsx->trfilename);
+    relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
 
-    DeleteFile(relationsx->trfilename);
+    DeleteFile(relationsx->trfilename_tmp);
 
-    trfd=OpenFileNew(relationsx->trfilename);
+    trfd=OpenFileNew(relationsx->trfilename_tmp);
 
     /* Sort the relations */
 
     trxnumber=relationsx->trnumber;
-    relationsx->trnumber=0;
 
-    relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))deduplicate_by_id);
+    relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),NULL,
+                                                                               (int (*)(const void*,const void*))sort_turn_by_id,
+                                                                               (int (*)(void*,index_t))deduplicate_turn_by_id);
 
     /* Close the files */
 
@@ -301,16 +374,16 @@ void SortRelationList(RelationsX* relationsx)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the turn restriction relations into id order.
+  Sort the route relations into id order.
 
-  int sort_by_id Returns the comparison of the id fields.
+  int sort_route_by_id Returns the comparison of the id fields.
 
-  TurnRestrictRelX *a The first extended relation.
+  RouteRelX *a The first extended relation.
 
-  TurnRestrictRelX *b The second extended relation.
+  RouteRelX *b The second extended relation.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int sort_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b)
+static int sort_route_by_id(RouteRelX *a,RouteRelX *b)
 {
  relation_t a_id=a->id;
  relation_t b_id=b->id;
@@ -320,120 +393,87 @@ static int sort_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b)
  else if(a_id>b_id)
     return(1);
  else
-    return(0);
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Deduplicate the extended relations using the id after sorting.
+  Deduplicate the route relations using the id after sorting.
 
-  int deduplicate_by_id Return 1 if the value is to be kept, otherwise 0.
+  int deduplicate_route_by_id Return 1 if the value is to be kept, otherwise 0.
 
-  TurnRestrictRelX *relationx The extended relation.
+  RouteRelX *relationx The extended relation.
 
-  index_t index The index of this relation in the total.
+  index_t index The number of sorted relations that have already been written to the output file.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int deduplicate_by_id(TurnRestrictRelX *relationx,index_t index)
+static int deduplicate_route_by_id(RouteRelX *relationx,index_t index)
 {
- static relation_t previd;
+ static relation_t previd=NO_RELATION_ID;
 
- if(index==0 || relationx->id!=previd)
+ if(relationx->id!=previd)
    {
     previd=relationx->id;
 
-    return(1);
+    if(relationx->routes==RELATION_DELETED)
+       return(0);
+    else
+       return(1);
    }
  else
-   {
-    logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
-
     return(0);
-   }
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the list of turn relations.
-
-  RelationsX* relationsx The set of relations to process.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-void SortTurnRelationList(RelationsX* relationsx)
-{
- int trfd;
-
- if(relationsx->trnumber==0)
-    return;
-
- /* Print the start message */
-
- printf_first("Sorting Turn Relations");
-
- /* Re-open the file read-only and a new file writeable */
-
- relationsx->trfd=ReOpenFile(relationsx->trfilename);
-
- DeleteFile(relationsx->trfilename);
-
- trfd=OpenFileNew(relationsx->trfilename);
-
- /* Sort the relations */
+  Sort the turn restriction relations into id order.
 
- filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),(int (*)(const void*,const void*))sort_by_via,NULL);
+  int sort_turn_by_id Returns the comparison of the id fields.
 
- /* Close the files */
+  TurnRelX *a The first extended relation.
 
- relationsx->trfd=CloseFile(relationsx->trfd);
- CloseFile(trfd);
+  TurnRelX *b The second extended relation.
+  ++++++++++++++++++++++++++++++++++++++*/
 
- /* Print the final message */
+static int sort_turn_by_id(TurnRelX *a,TurnRelX *b)
+{
+ relation_t a_id=a->id;
+ relation_t b_id=b->id;
 
- printf_last("Sorted Turn Relations: Relations=%"Pindex_t,relationsx->trnumber);
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the turn restriction relations into via index order (then by from and to segments).
+  Deduplicate the turn restriction relations using the id after sorting.
 
-  int sort_by_via Returns the comparison of the via, from and to fields.
+  int deduplicate_turn_by_id Return 1 if the value is to be kept, otherwise 0.
 
-  TurnRestrictRelX *a The first extended relation.
+  TurnRelX *relationx The extended relation.
 
-  TurnRestrictRelX *b The second extended relation.
+  index_t index The number of sorted relations that have already been written to the output file.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b)
+static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index)
 {
- index_t a_id=a->via;
- index_t b_id=b->via;
+ static relation_t previd=NO_RELATION_ID;
 
- if(a_id<b_id)
-    return(-1);
- else if(a_id>b_id)
-    return(1);
- else
+ if(relationx->id!=previd)
    {
-    index_t a_id=a->from;
-    index_t b_id=b->from;
+    previd=relationx->id;
 
-    if(a_id<b_id)
-       return(-1);
-    else if(a_id>b_id)
-       return(1);
+    if(relationx->except==RELATION_DELETED)
+       return(0);
     else
-      {
-       index_t a_id=a->to;
-       index_t b_id=b->to;
-
-       if(a_id<b_id)
-          return(-1);
-       else if(a_id>b_id)
-          return(1);
-       else
-          return(0);
-      }
+       return(1);
    }
+ else
+    return(0);
 }
 
 
@@ -443,9 +483,11 @@ static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b)
   RelationsX *relationsx The set of relations to use.
 
   WaysX *waysx The set of ways to modify.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
+void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int keep)
 {
  RouteRelX *unmatched=NULL,*lastunmatched=NULL;
  int nunmatched=0,lastnunmatched=0,iteration=1;
@@ -456,14 +498,14 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
  /* Map into memory / open the files */
 
 #if !SLIM
- waysx->data=MapFileWriteable(waysx->filename);
+ waysx->data=MapFileWriteable(waysx->filename_tmp);
 #else
- waysx->fd=ReOpenFileWriteable(waysx->filename);
+ waysx->fd=ReOpenFileWriteable(waysx->filename_tmp);
 #endif
 
  /* Re-open the file read-only */
 
- relationsx->rfd=ReOpenFile(relationsx->rfilename);
+ relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
 
  /* Read through the file. */
 
@@ -524,7 +566,7 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
 
           /* Update the ways that are listed for the relation */
 
-          if(wayid==NO_WAY)
+          if(wayid==NO_WAY_ID)
              continue;
 
           if(routes)
@@ -563,7 +605,7 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
                 logerror("Route Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,wayid);
             }
          }
-       while(wayid!=NO_WAY);
+       while(wayid!=NO_WAY_ID);
 
        /* Loop through the relations */
 
@@ -573,7 +615,7 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
 
           /* Add the relations that are listed for this relation to the list for next time */
 
-          if(relationid==NO_RELATION)
+          if(relationid==NO_RELATION_ID)
              continue;
 
           if(relationid==relationx.id)
@@ -589,7 +631,7 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
              nunmatched++;
             }
          }
-       while(relationid!=NO_RELATION);
+       while(relationid!=NO_RELATION_ID);
 
        if(!((i+1)%1000))
           printf_middle("Processing Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
@@ -617,10 +659,13 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
 
  relationsx->rfd=CloseFile(relationsx->rfd);
 
+ if(keep)
+    RenameFile(relationsx->rfilename_tmp,relationsx->rfilename);
+
  /* Unmap from memory / close the files */
 
 #if !SLIM
- waysx->data=UnmapFile(waysx->filename);
+ waysx->data=UnmapFile(waysx->data);
 #else
  waysx->fd=CloseFile(waysx->fd);
 #endif
@@ -635,9 +680,11 @@ void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
   NodesX *nodesx The set of nodes to use.
 
   WaysX *waysx The set of ways to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
+void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx,int keep)
 {
  int trfd;
  index_t i,deleted=0;
@@ -648,21 +695,23 @@ void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
 
  /* Re-open the file read-only and a new file writeable */
 
- relationsx->trfd=ReOpenFile(relationsx->trfilename);
+ relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
 
- DeleteFile(relationsx->trfilename);
+ if(keep)
+    RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
+ else
+    DeleteFile(relationsx->trfilename_tmp);
 
- trfd=OpenFileNew(relationsx->trfilename);
+ trfd=OpenFileNew(relationsx->trfilename_tmp);
 
  /* Process all of the relations */
 
  for(i=0;i<relationsx->trnumber;i++)
    {
-    TurnRestrictRelX relationx;
-    node_t via;
-    way_t from,to;
+    TurnRelX relationx;
+    index_t via,from,to;
 
-    ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
+    ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
 
     via =IndexNodeX(nodesx,relationx.via);
     from=IndexWayX(waysx,relationx.from);
@@ -684,10 +733,10 @@ void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
     if(relationx.via==NO_NODE || relationx.from==NO_WAY || relationx.to==NO_WAY)
        deleted++;
     else
-       WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
+       WriteFile(trfd,&relationx,sizeof(TurnRelX));
 
     if(!((i+1)%1000))
-       printf_middle("Processing Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,i+1-deleted,deleted);
+       printf_middle("Processing Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,i+1,deleted);
    }
 
  /* Close the files */
@@ -697,7 +746,7 @@ void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
 
  /* Print the final message */
 
- printf_last("Processed Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,relationsx->trnumber-deleted,deleted);
+ printf_last("Processed Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,relationsx->trnumber,deleted);
 
  relationsx->trnumber-=deleted;
 }
@@ -717,7 +766,7 @@ void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
 
 void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 {
- TurnRestrictRelX relationx;
+ TurnRelX relationx;
  int trfd;
  index_t total=0,deleted=0;
 
@@ -731,26 +780,26 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFileWriteable(nodesx->filename);
- segmentsx->data=MapFile(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFileWriteable(nodesx->filename_tmp);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFileWriteable(nodesx->filename);
- segmentsx->fd=ReOpenFile(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFileWriteable(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  /* Re-open the file read-only and a new file writeable */
 
- relationsx->trfd=ReOpenFile(relationsx->trfilename);
+ relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
 
- DeleteFile(relationsx->trfilename);
+ DeleteFile(relationsx->trfilename_tmp);
 
- trfd=OpenFileNew(relationsx->trfilename);
+ trfd=OpenFileNew(relationsx->trfilename_tmp);
 
  /* Process all of the relations */
 
- while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
+ while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX)))
    {
     NodeX *nodex;
     SegmentX *segmentx;
@@ -841,7 +890,7 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
        relationx.from=node_from;
        relationx.to  =node_to;
 
-       WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
+       WriteFile(trfd,&relationx,sizeof(TurnRelX));
 
        total++;
 
@@ -902,7 +951,7 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
                 ;  /* not allowed */
              else
                {
-                assert(nnodes_other<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
+                logassert(nnodes_other<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
 
                 node_other[nnodes_other++]=OtherNode(segmentx,relationx.via);
                }
@@ -939,7 +988,7 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
           relationx.from=node_from;
           relationx.to  =node_other[i];
 
-          WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
+          WriteFile(trfd,&relationx,sizeof(TurnRelX));
 
           total++;
 
@@ -978,9 +1027,9 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
  /* Unmap from memory / close the files */
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
@@ -996,79 +1045,115 @@ void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segm
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Update the node indexes after geographical sorting.
+  Remove pruned turn relations and update the node indexes after pruning nodes.
 
   RelationsX *relationsx The set of relations to modify.
 
   NodesX *nodesx The set of nodes to use.
-
-  SegmentsX *segmentsx The set of segments to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void UpdateTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
+void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
 {
+ TurnRelX relationx;
+ index_t total=0,pruned=0,notpruned=0;
  int trfd;
- index_t i,kept=0;
-
- /* Print the start message */
 
- printf_first("Updating Turn Relations (Deleting Pruned): Relations=0");
+ if(relationsx->trnumber==0)
+    return;
 
- /* Map into memory / open the files */
+ /* Print the start message */
 
-#if !SLIM
- segmentsx->data=MapFile(segmentsx->filename);
-#else
- segmentsx->fd=ReOpenFile(segmentsx->filename);
-#endif
+ printf_first("Deleting Pruned Turn Relations: Relations=0 Pruned=0");
 
  /* Re-open the file read-only and a new file writeable */
 
- relationsx->trfd=ReOpenFile(relationsx->trfilename);
+ relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
 
- DeleteFile(relationsx->trfilename);
+ DeleteFile(relationsx->trfilename_tmp);
 
- trfd=OpenFileNew(relationsx->trfilename);
+ trfd=OpenFileNew(relationsx->trfilename_tmp);
 
  /* Process all of the relations */
 
- for(i=0;i<relationsx->trnumber;i++)
+ while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX)))
    {
-    TurnRestrictRelX relationx;
-    index_t from_node,via_node,to_node;
+    relationx.from=nodesx->pdata[relationx.from];
+    relationx.via =nodesx->pdata[relationx.via];
+    relationx.to  =nodesx->pdata[relationx.to];
 
-    ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
+    if(relationx.from==NO_NODE || relationx.via==NO_NODE || relationx.to==NO_NODE)
+       pruned++;
+    else
+      {
+       WriteFile(trfd,&relationx,sizeof(TurnRelX));
 
-    from_node=nodesx->gdata[relationx.from];
-    via_node =nodesx->gdata[relationx.via];
-    to_node  =nodesx->gdata[relationx.to];
+       notpruned++;
+      }
 
-    if(from_node<nodesx->number && via_node<nodesx->number && to_node<nodesx->number)
-      {
-       SegmentX *segmentx=FirstSegmentX(segmentsx,via_node,1);
+    total++;
 
-       do
-         {
-          if(OtherNode(segmentx,via_node)==from_node)
-             relationx.from=IndexSegmentX(segmentsx,segmentx);
+    if(!(total%1000))
+       printf_middle("Deleting Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+   }
 
-          if(OtherNode(segmentx,via_node)==to_node)
-             relationx.to=IndexSegmentX(segmentsx,segmentx);
+ relationsx->trnumber=notpruned;
 
-          segmentx=NextSegmentX(segmentsx,segmentx,via_node);
-         }
-       while(segmentx);
+ /* Close the files */
 
-       relationx.via=via_node;
+ relationsx->trfd=CloseFile(relationsx->trfd);
+ CloseFile(trfd);
 
-       WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
+ /* Print the final message */
 
-       kept++;
-      }
+ printf_last("Deleted Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+}
 
-    if(!(relationsx->trnumber%1000))
-       printf_middle("Updating Turn Relations (Deleting Pruned): Relations=%"Pindex_t,relationsx->trnumber);
-   }
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the turn relations geographically after updating the node indexes.
+
+  RelationsX *relationsx The set of relations to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
+{
+ int trfd;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Turn Relations Geographically");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+#else
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+#endif
+
+ /* Re-open the file read-only and a new file writeable */
+
+ relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
+
+ DeleteFile(relationsx->trfilename_tmp);
+
+ trfd=OpenFileNew(relationsx->trfilename_tmp);
+
+ /* Update the segments with geographically sorted node indexes and sort them */
+
+ 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);
 
  /* Close the files */
 
@@ -1078,16 +1163,97 @@ void UpdateTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmen
  /* Unmap from memory / close the files */
 
 #if !SLIM
- segmentsx->data=UnmapFile(segmentsx->filename);
+ segmentsx->data=UnmapFile(segmentsx->data);
 #else
  segmentsx->fd=CloseFile(segmentsx->fd);
 #endif
 
  /* Print the final message */
 
- printf_last("Updated Turn Relations: Relations=%"Pindex_t" Deleted=%"Pindex_t,kept,relationsx->trnumber-kept);
+ printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the turn relation indexes.
+
+  int geographically_index 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(TurnRelX *relationx,index_t index)
+{
+ SegmentX *segmentx;
+ index_t from_node,via_node,to_node;
+
+ from_node=sortnodesx->gdata[relationx->from];
+ via_node =sortnodesx->gdata[relationx->via];
+ to_node  =sortnodesx->gdata[relationx->to];
+
+ segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
+
+ do
+   {
+    if(OtherNode(segmentx,via_node)==from_node)
+       relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
+
+    if(OtherNode(segmentx,via_node)==to_node)
+       relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
+
+    segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
+   }
+ while(segmentx);
+
+ relationx->via=via_node;
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the turn restriction relations into via index order (then by from and to segments).
+
+  int sort_by_via Returns the comparison of the via, from and to fields.
+
+  TurnRelX *a The first extended relation.
 
- relationsx->trnumber=kept;
+  TurnRelX *b The second extended relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_via(TurnRelX *a,TurnRelX *b)
+{
+ index_t a_id=a->via;
+ index_t b_id=b->via;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+   {
+    index_t a_id=a->from;
+    index_t b_id=b->from;
+
+    if(a_id<b_id)
+       return(-1);
+    else if(a_id>b_id)
+       return(1);
+    else
+      {
+       index_t a_id=a->to;
+       index_t b_id=b->to;
+
+       if(a_id<b_id)
+          return(-1);
+       else if(a_id>b_id)
+          return(1);
+       else
+          return(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
 }
 
 
@@ -1111,7 +1277,7 @@ void SaveRelationList(RelationsX* relationsx,const char *filename)
 
  /* Re-open the file read-only */
 
- relationsx->trfd=ReOpenFile(relationsx->trfilename);
+ relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
 
  /* Write out the relations data */
 
@@ -1121,10 +1287,10 @@ void SaveRelationList(RelationsX* relationsx,const char *filename)
 
  for(i=0;i<relationsx->trnumber;i++)
    {
-    TurnRestrictRelX relationx;
+    TurnRelX relationx;
     TurnRelation relation={0};
 
-    ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
+    ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
 
     relation.from=relationx.from;
     relation.via=relationx.via;
diff --git a/src/relationsx.h b/src/relationsx.h
index 2b1a5fc..23440a7 100644
--- a/src/relationsx.h
+++ b/src/relationsx.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2011 Andrew M. Bishop
+ This file Copyright 2010-2012 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
@@ -43,7 +43,7 @@ struct _RouteRelX
 
 
 /*+ An extended structure containing a single turn restriction relation. +*/
-struct _TurnRestrictRelX
+struct _TurnRelX
 {
  relation_t      id;           /*+ The relation identifier. +*/
 
@@ -61,15 +61,19 @@ struct _RelationsX
 {
  /* Route relations */
 
- char      *rfilename;         /*+ The name of the temporary file (for the RouteRelX). +*/
- int        rfd;               /*+ The file descriptor of the temporary file (for the RouteRelX). +*/
+ char      *rfilename;         /*+ The name of the intermediate file (for the RouteRelX). +*/
+ char      *rfilename_tmp;     /*+ The name of the temporary file (for the RouteRelX). +*/
+
+ int        rfd;               /*+ The file descriptor of the open file (for the RouteRelX). +*/
 
  index_t    rnumber;           /*+ The number of extended route relations. +*/
 
  /* Turn restriction relations */
 
- char      *trfilename;        /*+ The name of the temporary file (for the TurnRestrictRelX). +*/
- int        trfd;              /*+ The file descriptor of the temporary file (for the TurnRestrictRelX). +*/
+ char      *trfilename;        /*+ The name of the intermediate file (for the TurnRelX). +*/
+ char      *trfilename_tmp;    /*+ The name of the temporary file (for the TurnRelX). +*/
+
+ int        trfd;              /*+ The file descriptor of the temporary file (for the TurnRelX). +*/
 
  index_t    trnumber;          /*+ The number of extended turn restriction relations. +*/
 };
@@ -77,28 +81,28 @@ struct _RelationsX
 
 /* Functions in relationsx.c */
 
-RelationsX *NewRelationList(int append);
+RelationsX *NewRelationList(int append,int readonly);
 void FreeRelationList(RelationsX *relationsx,int keep);
 
-void AppendRouteRelation(RelationsX* relationsx,relation_t id,
-                         transports_t routes,
-                         way_t *ways,int nways,
-                         relation_t *relations,int nrelations);
-
-void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
-                                way_t from,way_t to,node_t via,
-                                TurnRestriction restriction,transports_t except);
+void AppendRouteRelationList(RelationsX* relationsx,relation_t id,
+                             transports_t routes,
+                             way_t *ways,int nways,
+                             relation_t *relations,int nrelations);
+void AppendTurnRelationList(RelationsX* relationsx,relation_t id,
+                            way_t from,way_t to,node_t via,
+                            TurnRestriction restriction,transports_t except);
+void FinishRelationList(RelationsX *relationsx);
 
 void SortRelationList(RelationsX *relationsx);
 
-void SortTurnRelationList(RelationsX* relationsx);
+void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int keep);
 
-void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx);
-
-void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx);
+void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx,int keep);
 void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx);
 
-void UpdateTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx);
+void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx);
+
+void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx);
 
 void SaveRelationList(RelationsX* relationsx,const char *filename);
 
diff --git a/src/results.c b/src/results.c
index 83ca674..f295a3b 100644
--- a/src/results.c
+++ b/src/results.c
@@ -22,10 +22,11 @@
 
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
 
 #include "results.h"
 
+#include "logging.h"
+
 
 /*+ The maximum number of collisions in a bin for the Results 'point' arrays before worrying. +*/
 #define MAX_COLLISIONS 32
@@ -168,7 +169,7 @@ Result *InsertResult(Results *results,index_t node,index_t segment)
 
  if(results->count[bin]==results->npoint1)
    {
-    assert(results->npoint1<255);
+    logassert(results->npoint1<255,"Results are more numerous than expected (report a bug)");
 
     results->npoint1++;
 
diff --git a/src/router.c b/src/router.c
index d4cb690..f798949 100644
--- a/src/router.c
+++ b/src/router.c
@@ -164,7 +164,7 @@ int main(int argc,char** argv)
    {
     if(ExistsFile(FileName(dirname,prefix,"profiles.xml")))
        profiles=FileName(dirname,prefix,"profiles.xml");
-    else if(ExistsFile(FileName(DATADIR,NULL,"tagging.xml")))
+    else if(ExistsFile(FileName(DATADIR,NULL,"profiles.xml")))
        profiles=FileName(DATADIR,NULL,"profiles.xml");
     else
       {
@@ -284,7 +284,7 @@ int main(int argc,char** argv)
 
        highway=HighwayType(string);
 
-       if(highway==Way_Count)
+       if(highway==Highway_None)
           print_usage(0,argv[arg],NULL);
 
        profile->highway[highway]=atof(equal+1);
@@ -305,7 +305,7 @@ int main(int argc,char** argv)
 
        highway=HighwayType(string);
 
-       if(highway==Way_Count)
+       if(highway==Highway_None)
           print_usage(0,argv[arg],NULL);
 
        profile->speed[highway]=kph_to_speed(atof(equal+1));
@@ -326,7 +326,7 @@ int main(int argc,char** argv)
 
        property=PropertyType(string);
 
-       if(property==Property_Count)
+       if(property==Property_None)
           print_usage(0,argv[arg],NULL);
 
        profile->props_yes[property]=atof(equal+1);
diff --git a/src/segments.c b/src/segments.c
index a73a45d..7fb83e5 100644
--- a/src/segments.c
+++ b/src/segments.c
@@ -99,44 +99,44 @@ Segments *LoadSegmentList(const char *filename)
 
 index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,index_t node1,double heading,Profile *profile)
 {
- Segment *segment;
+ Segment *segmentp;
  index_t best_seg=NO_SEGMENT;
  double best_difference=360;
 
  if(IsFakeNode(node1))
-    segment=FirstFakeSegment(node1);
+    segmentp=FirstFakeSegment(node1);
  else
    {
-    Node *node=LookupNode(nodes,node1,3);
+    Node *nodep=LookupNode(nodes,node1,3);
 
-    segment=FirstSegment(segments,node,1);
+    segmentp=FirstSegment(segments,nodep,1);
    }
 
- while(segment)
+ while(segmentp)
    {
-    Way *way;
+    Way *wayp;
     index_t node2,seg2;
     double bearing,difference;
 
-    node2=OtherNode(segment,node1);  /* need this here because we use node2 at the end of the loop */
+    node2=OtherNode(segmentp,node1);  /* need this here because we use node2 at the end of the loop */
 
-    if(!IsNormalSegment(segment))
+    if(!IsNormalSegment(segmentp))
        goto endloop;
 
-    if(profile->oneway && IsOnewayFrom(segment,node1))
+    if(profile->oneway && IsOnewayFrom(segmentp,node1))
        goto endloop;
 
     if(IsFakeNode(node1) || IsFakeNode(node2))
-       seg2=IndexFakeSegment(segment);
+       seg2=IndexFakeSegment(segmentp);
     else
-       seg2=IndexSegment(segments,segment);
+       seg2=IndexSegment(segments,segmentp);
 
-    way=LookupWay(ways,segment->way,1);
+    wayp=LookupWay(ways,segmentp->way,1);
 
-    if(!(way->allow&profile->allow))
+    if(!(wayp->allow&profile->allow))
        goto endloop;
 
-    bearing=BearingAngle(nodes,segment,node1);
+    bearing=BearingAngle(nodes,segmentp,node1);
 
     difference=(heading-bearing);
 
@@ -154,11 +154,11 @@ index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,ind
    endloop:
 
     if(IsFakeNode(node1))
-       segment=NextFakeSegment(segment,node1);
+       segmentp=NextFakeSegment(segmentp,node1);
     else if(IsFakeNode(node2))
-       segment=NULL; /* cannot call NextSegment() with a fake segment */
+       segmentp=NULL; /* cannot call NextSegment() with a fake segment */
     else
-       segment=NextSegment(segments,segment,node1);
+       segmentp=NextSegment(segments,segmentp,node1);
    }
 
  return(best_seg);
@@ -208,18 +208,18 @@ distance_t Distance(double lat1,double lon1,double lat2,double lon2)
 
   duration_t Duration Returns the duration of travel.
 
-  Segment *segment The segment to traverse.
+  Segment *segmentp The segment to traverse.
 
-  Way *way The way that the segment belongs to.
+  Way *wayp The way that the segment belongs to.
 
   Profile *profile The profile of the transport being used.
   ++++++++++++++++++++++++++++++++++++++*/
 
-duration_t Duration(Segment *segment,Way *way,Profile *profile)
+duration_t Duration(Segment *segmentp,Way *wayp,Profile *profile)
 {
- speed_t    speed1=way->speed;
- speed_t    speed2=profile->speed[HIGHWAY(way->type)];
- distance_t distance=DISTANCE(segment->distance);
+ speed_t    speed1=wayp->speed;
+ speed_t    speed2=profile->speed[HIGHWAY(wayp->type)];
+ distance_t distance=DISTANCE(segmentp->distance);
 
  if(speed1==0)
    {
@@ -247,9 +247,9 @@ duration_t Duration(Segment *segment,Way *way,Profile *profile)
 
   Nodes *nodes The set of nodes to use.
 
-  Segment *segment1 The current segment.
+  Segment *segment1p The current segment.
 
-  Segment *segment2 The next segment.
+  Segment *segment2p The next segment.
 
   index_t node The node at which they join.
 
@@ -257,15 +257,15 @@ duration_t Duration(Segment *segment,Way *way,Profile *profile)
   Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
   ++++++++++++++++++++++++++++++++++++++*/
 
-double TurnAngle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node)
+double TurnAngle(Nodes *nodes,Segment *segment1p,Segment *segment2p,index_t node)
 {
  double lat1,latm,lat2;
  double lon1,lonm,lon2;
  double angle1,angle2,angle;
  index_t node1,node2;
 
- node1=OtherNode(segment1,node);
- node2=OtherNode(segment2,node);
+ node1=OtherNode(segment1p,node);
+ node2=OtherNode(segment2p,node);
 
  if(IsFakeNode(node1))
     GetFakeLatLong(node1,&lat1,&lon1);
@@ -303,14 +303,14 @@ double TurnAngle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node)
 
   Nodes *nodes The set of nodes to use.
 
-  Segment *segment The segment.
+  Segment *segmentp The segment.
 
   index_t node The node to finish.
 
   Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
   ++++++++++++++++++++++++++++++++++++++*/
 
-double BearingAngle(Nodes *nodes,Segment *segment,index_t node)
+double BearingAngle(Nodes *nodes,Segment *segmentp,index_t node)
 {
  double lat1,lat2;
  double lon1,lon2;
@@ -318,7 +318,7 @@ double BearingAngle(Nodes *nodes,Segment *segment,index_t node)
  index_t node1,node2;
 
  node1=node;
- node2=OtherNode(segment,node);
+ node2=OtherNode(segmentp,node);
 
  if(IsFakeNode(node1))
     GetFakeLatLong(node1,&lat1,&lon1);
diff --git a/src/segments.h b/src/segments.h
index 671429a..f6f70d6 100644
--- a/src/segments.h
+++ b/src/segments.h
@@ -90,13 +90,13 @@ index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,ind
 
 distance_t Distance(double lat1,double lon1,double lat2,double lon2);
 
-duration_t Duration(Segment *segment,Way *way,Profile *profile);
+duration_t Duration(Segment *segmentp,Way *wayp,Profile *profile);
 
-double TurnAngle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node);
-double BearingAngle(Nodes *nodes,Segment *segment,index_t node);
+double TurnAngle(Nodes *nodes,Segment *segment1p,Segment *segment2p,index_t node);
+double BearingAngle(Nodes *nodes,Segment *segmentp,index_t node);
 
 
-static inline Segment *NextSegment(Segments *segments,Segment *segment,index_t node);
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node);
 
 
 /* Macros and inline functions */
@@ -135,28 +135,28 @@ static inline Segment *NextSegment(Segments *segments,Segment *segment,index_t n
 
   Segments *segments The set of segments to use.
 
-  Segment *segment The current segment.
+  Segment *segmentp The current segment.
 
   index_t node The wanted node.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static inline Segment *NextSegment(Segments *segments,Segment *segment,index_t node)
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node)
 {
- if(segment->node1==node)
+ if(segmentp->node1==node)
    {
-    segment++;
+    segmentp++;
 
-    if(IndexSegment(segments,segment)>=segments->file.number || segment->node1!=node)
+    if(IndexSegment(segments,segmentp)>=segments->file.number || segmentp->node1!=node)
        return(NULL);
     else
-       return(segment);
+       return(segmentp);
    }
  else
    {
-    if(segment->next2==NO_SEGMENT)
+    if(segmentp->next2==NO_SEGMENT)
        return(NULL);
     else
-       return(LookupSegment(segments,segment->next2,1));
+       return(LookupSegment(segments,segmentp->next2,1));
    }
 }
 
@@ -164,7 +164,7 @@ static inline Segment *NextSegment(Segments *segments,Segment *segment,index_t n
 
 static Segment *LookupSegment(Segments *segments,index_t index,int position);
 
-static index_t IndexSegment(Segments *segments,Segment *segment);
+static index_t IndexSegment(Segments *segments,Segment *segmentp);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -199,12 +199,12 @@ static inline Segment *LookupSegment(Segments *segments,index_t index,int positi
 
   Segments *segments The set of segments to use.
 
-  Segment *segment The segment whose index is to be found.
+  Segment *segmentp The segment whose index is to be found.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static inline index_t IndexSegment(Segments *segments,Segment *segment)
+static inline index_t IndexSegment(Segments *segments,Segment *segmentp)
 {
- int position1=segment-&segments->cached[0];
+ int position1=segmentp-&segments->cached[0];
 
  return(segments->incache[position1]);
 }
@@ -217,37 +217,37 @@ static inline index_t IndexSegment(Segments *segments,Segment *segment)
 
   Segments *segments The set of segments to use.
 
-  Segment *segment The current segment.
+  Segment *segmentp The current segment.
 
   index_t node The wanted node.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static inline Segment *NextSegment(Segments *segments,Segment *segment,index_t node)
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node)
 {
- int position=segment-&segments->cached[-1];
+ int position=segmentp-&segments->cached[-1];
 
- if(segment->node1==node)
+ if(segmentp->node1==node)
    {
-    index_t index=IndexSegment(segments,segment);
+    index_t index=IndexSegment(segments,segmentp);
 
     index++;
 
     if(index>=segments->file.number)
        return(NULL);
 
-    segment=LookupSegment(segments,index,position);
+    segmentp=LookupSegment(segments,index,position);
 
-    if(segment->node1!=node)
+    if(segmentp->node1!=node)
        return(NULL);
     else
-       return(segment);
+       return(segmentp);
    }
  else
    {
-    if(segment->next2==NO_SEGMENT)
+    if(segmentp->next2==NO_SEGMENT)
        return(NULL);
     else
-       return(LookupSegment(segments,segment->next2,position));
+       return(LookupSegment(segments,segmentp->next2,position));
    }
 }
 
diff --git a/src/segmentsx.c b/src/segmentsx.c
index 56f0008..130aca2 100644
--- a/src/segmentsx.c
+++ b/src/segmentsx.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
@@ -44,11 +43,27 @@
 /*+ The command line '--tmpdir' option or its default value. +*/
 extern char *option_tmpdirname;
 
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions. +*/
+static NodesX *sortnodesx;
+static SegmentsX *sortsegmentsx;
+static WaysX *sortwaysx;
+
 /* Local functions */
 
+static int sort_by_way_id(SegmentX *a,SegmentX *b);
+static int apply_changes(SegmentX *segmentx,index_t index);
+
 static int sort_by_id(SegmentX *a,SegmentX *b);
+static int deduplicate(SegmentX *segmentx,index_t index);
+
 static int delete_pruned(SegmentX *segmentx,index_t index);
 
+static int deduplicate_super(SegmentX *segmentx,index_t index);
+
+static int geographically_index(SegmentX *segmentx,index_t index);
+
 static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2);
 
 
@@ -57,36 +72,43 @@ static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2);
 
   SegmentsX *NewSegmentList Returns the segment list.
 
-  int append Set to 1 if the file is to be opened for appending (now or later).
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
   ++++++++++++++++++++++++++++++++++++++*/
 
-SegmentsX *NewSegmentList(int append)
+SegmentsX *NewSegmentList(int append,int readonly)
 {
  SegmentsX *segmentsx;
 
  segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX));
 
- assert(segmentsx); /* Check calloc() worked */
+ logassert(segmentsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
 
- segmentsx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
+ segmentsx->filename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ segmentsx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- if(append)
-    sprintf(segmentsx->filename,"%s/segmentsx.input.tmp",option_tmpdirname);
- else
-    sprintf(segmentsx->filename,"%s/segmentsx.%p.tmp",option_tmpdirname,(void*)segmentsx);
+ sprintf(segmentsx->filename    ,"%s/segmentsx.parsed.mem",option_tmpdirname);
+ sprintf(segmentsx->filename_tmp,"%s/segmentsx.%p.tmp"    ,option_tmpdirname,(void*)segmentsx);
 
- if(append)
-   {
-    off_t size;
+ if(append || readonly)
+    if(ExistsFile(segmentsx->filename))
+      {
+       off_t size;
 
-    segmentsx->fd=OpenFileAppend(segmentsx->filename);
+       size=SizeFile(segmentsx->filename);
 
-    size=SizeFile(segmentsx->filename);
+       segmentsx->number=size/sizeof(SegmentX);
 
-    segmentsx->number=size/sizeof(SegmentX);
-   }
+       RenameFile(segmentsx->filename,segmentsx->filename_tmp);
+      }
+
+ if(append)
+    segmentsx->fd=OpenFileAppend(segmentsx->filename_tmp);
+ else if(!readonly)
+    segmentsx->fd=OpenFileNew(segmentsx->filename_tmp);
  else
-    segmentsx->fd=OpenFileNew(segmentsx->filename);
+    segmentsx->fd=-1;
 
  return(segmentsx);
 }
@@ -97,15 +119,18 @@ SegmentsX *NewSegmentList(int append)
 
   SegmentsX *segmentsx The set of segments to be freed.
 
-  int keep Set to 1 if the file is to be kept (for appending later).
+  int keep If set then the results file is to be kept.
   ++++++++++++++++++++++++++++++++++++++*/
 
 void FreeSegmentList(SegmentsX *segmentsx,int keep)
 {
- if(!keep)
-    DeleteFile(segmentsx->filename);
+ if(keep)
+    RenameFile(segmentsx->filename_tmp,segmentsx->filename);
+ else
+    DeleteFile(segmentsx->filename_tmp);
 
  free(segmentsx->filename);
+ free(segmentsx->filename_tmp);
 
  if(segmentsx->firstnode)
     free(segmentsx->firstnode);
@@ -134,7 +159,7 @@ void FreeSegmentList(SegmentsX *segmentsx,int keep)
   distance_t distance The distance between the nodes (or just the flags).
   ++++++++++++++++++++++++++++++++++++++*/
 
-void AppendSegment(SegmentsX *segmentsx,way_t way,node_t node1,node_t node2,distance_t distance)
+void AppendSegmentList(SegmentsX *segmentsx,way_t way,node_t node1,node_t node2,distance_t distance)
 {
  SegmentX segmentx;
 
@@ -160,127 +185,20 @@ void AppendSegment(SegmentsX *segmentsx,way_t way,node_t node1,node_t node2,dist
 
  segmentsx->number++;
 
- assert(segmentsx->number<SEGMENT_FAKE); /* SEGMENT_FAKE marks the high-water mark for real segments. */
+ logassert(segmentsx->number<SEGMENT_FAKE,"Too many segments (change index_t to 64-bits?)"); /* SEGMENT_FAKE marks the high-water mark for real segments. */
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the segment list.
-
-  SegmentsX *segmentsx The set of segments to sort and modify.
+  Finish appending segments and change the filename over.
 
-  int delete Set to true if pruned segments are to be deleted.
+  SegmentsX *segmentsx The segments that have been appended.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void SortSegmentList(SegmentsX *segmentsx,int delete)
+void FinishSegmentList(SegmentsX *segmentsx)
 {
- int fd;
- index_t kept;
-
- /* Print the start message */
-
- if(delete)
-    printf_first("Sorting Segments (Deleting Pruned)");
- else
-    printf_first("Sorting Segments");
-
- /* Close the file (finished appending) */
-
  if(segmentsx->fd!=-1)
     segmentsx->fd=CloseFile(segmentsx->fd);
-
- /* Re-open the file read-only and a new file writeable */
-
- segmentsx->fd=ReOpenFile(segmentsx->filename);
-
- DeleteFile(segmentsx->filename);
-
- fd=OpenFileNew(segmentsx->filename);
-
- /* Sort by node indexes */
-
- if(delete)
-    kept=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))delete_pruned);
- else
-    filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(const void*,const void*))sort_by_id,NULL);
-
- /* Close the files */
-
- segmentsx->fd=CloseFile(segmentsx->fd);
- CloseFile(fd);
-
- /* Print the final message */
-
- if(delete)
-   {
-    printf_last("Sorted Segments: Segments=%"Pindex_t" Deleted=%"Pindex_t,kept,segmentsx->number-kept);
-    segmentsx->number=kept;
-   }
- else
-    printf_last("Sorted Segments: Segments=%"Pindex_t,segmentsx->number);
-}
-
-
-/*++++++++++++++++++++++++++++++++++++++
-  Sort the segments into id order, first by node1 then by node2, finally by distance.
-
-  int sort_by_id Returns the comparison of the node fields.
-
-  SegmentX *a The first segment.
-
-  SegmentX *b The second segment.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-static int sort_by_id(SegmentX *a,SegmentX *b)
-{
- node_t a_id1=a->node1;
- node_t b_id1=b->node1;
-
- if(a_id1<b_id1)
-    return(-1);
- else if(a_id1>b_id1)
-    return(1);
- else /* if(a_id1==b_id1) */
-   {
-    node_t a_id2=a->node2;
-    node_t b_id2=b->node2;
-
-    if(a_id2<b_id2)
-       return(-1);
-    else if(a_id2>b_id2)
-       return(1);
-    else
-      {
-       distance_t a_distance=DISTANCE(a->distance);
-       distance_t b_distance=DISTANCE(b->distance);
-
-       if(a_distance<b_distance)
-          return(-1);
-       else if(a_distance>b_distance)
-          return(1);
-       else
-          return(0);
-      }
-   }
-}
-
-
-/*++++++++++++++++++++++++++++++++++++++
-  Delete the pruned segments.
-
-  int delete_pruned Return 1 if the value is to be kept, otherwise 0.
-
-  SegmentX *segmentx The extended segment.
-
-  index_t index The index of this segment in the total.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-static int delete_pruned(SegmentX *segmentx,index_t index)
-{
- if(IsPrunedSegmentX(segmentx))
-    return(0);
-
- return(1);
 }
 
 
@@ -375,310 +293,344 @@ SegmentX *NextSegmentX(SegmentsX *segmentsx,SegmentX *segmentx,index_t nodeindex
  
  
 /*++++++++++++++++++++++++++++++++++++++
-  Remove bad segments (duplicated, zero length or with missing nodes).
+  Apply the changes to the segments (no unique id to use).
 
-  NodesX *nodesx The set of nodes to use.
-
-  SegmentsX *segmentsx The set of segments to modify.
+  SegmentsX *segmentsx The set of segments to sort and modify.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx)
+void ApplySegmentChanges(SegmentsX *segmentsx)
 {
- index_t duplicate=0,loop=0,nonode=0,good=0,total=0;
- SegmentX segmentx;
  int fd;
- node_t prevnode1=NO_NODE_ID,prevnode2=NO_NODE_ID;
- distance_t prevdist=0;
+ index_t xnumber;
 
  /* Print the start message */
 
- printf_first("Checking Segments: Segments=0 Duplicate=0 Loop=0 No-Node=0");
-
- /* Allocate the array of node flags */
+ printf_first("Applying Segment Changes");
 
- segmentsx->usednode=AllocBitMask(nodesx->number);
+ /* Re-open the file read-only and a new file writeable */
 
- assert(segmentsx->usednode); /* Check AllocBitMask() worked */
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
- /* Re-open the file read-only and a new file writeable */
+ DeleteFile(segmentsx->filename_tmp);
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ fd=OpenFileNew(segmentsx->filename_tmp);
 
- DeleteFile(segmentsx->filename);
+ /* Sort by node indexes */
 
- fd=OpenFileNew(segmentsx->filename);
+ xnumber=segmentsx->number;
 
- /* Modify the on-disk image */
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),NULL,
+                                                                    (int (*)(const void*,const void*))sort_by_way_id,
+                                                                    (int (*)(void*,index_t))apply_changes);
 
- while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
-   {
-    index_t index1=IndexNodeX(nodesx,segmentx.node1);
-    index_t index2=IndexNodeX(nodesx,segmentx.node2);
+ /* Close the files */
 
-    if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
-      {
-       if(!prevdist && !DISTANCE(segmentx.distance))
-          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated.\n",segmentx.node1,segmentx.node2);
+ segmentsx->fd=CloseFile(segmentsx->fd);
+ CloseFile(fd);
 
-       if(!prevdist && DISTANCE(segmentx.distance))
-          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the area).\n",segmentx.node1,segmentx.node2);
+ /* Print the final message */
 
-       if(prevdist && !DISTANCE(segmentx.distance))
-          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the non-area).\n",segmentx.node1,segmentx.node2);
+ printf_last("Applying Segment Changes: Segments=%"Pindex_t" Changed=%"Pindex_t,xnumber,xnumber-segmentsx->number);
+}
 
-       if(prevdist && DISTANCE(segmentx.distance))
-          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (both are areas).\n",segmentx.node1,segmentx.node2);
 
-       duplicate++;
-      }
-    else if(segmentx.node1==segmentx.node2)
-      {
-       logerror("Segment connects node %"Pnode_t" to itself.\n",segmentx.node1);
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the segments into way id order.
 
-       loop++;
-      }
-    else if(index1==NO_NODE || index2==NO_NODE)
-      {
-       if(index1==NO_NODE && index2==NO_NODE)
-          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but neither exist.\n",segmentx.node1,segmentx.node2);
+  int sort_by_way_id Returns the comparison of the way fields.
 
-       if(index1==NO_NODE && index2!=NO_NODE)
-          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but the first one does not exist.\n",segmentx.node1,segmentx.node2);
+  SegmentX *a The first segment.
 
-       if(index1!=NO_NODE && index2==NO_NODE)
-          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but the second one does not exist.\n",segmentx.node1,segmentx.node2);
+  SegmentX *b The second segment.
+  ++++++++++++++++++++++++++++++++++++++*/
 
-       nonode++;
-      }
-    else
-      {
-       WriteFile(fd,&segmentx,sizeof(SegmentX));
+static int sort_by_way_id(SegmentX *a,SegmentX *b)
+{
+ way_t a_id=a->way;
+ way_t b_id=b->way;
 
-       SetBit(segmentsx->usednode,index1);
-       SetBit(segmentsx->usednode,index2);
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else /* if(a_id==b_id) */
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
 
-       good++;
 
-       prevnode1=segmentx.node1;
-       prevnode2=segmentx.node2;
-       prevdist=DISTANCE(segmentx.distance);
-      }
+/*++++++++++++++++++++++++++++++++++++++
+  Apply the changes to the segments.
 
-    total++;
+  int apply_changes Return 1 if the value is to be kept, otherwise 0.
 
-    if(!(total%10000))
-       printf_middle("Checking Segments: Segments=%"Pindex_t" Duplicate=%"Pindex_t" Loop=%"Pindex_t" No-Node=%"Pindex_t,total,duplicate,loop,nonode);
-   }
+  SegmentX *segmentx The extended segment.
 
- segmentsx->number=good;
+  index_t index The number of sorted segments that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
 
- /* Close the files */
+static int apply_changes(SegmentX *segmentx,index_t index)
+{
+ static way_t prevway=NO_WAY_ID;
+ static int deleted=0;
 
- segmentsx->fd=CloseFile(segmentsx->fd);
- CloseFile(fd);
+ if(prevway!=segmentx->way)
+   {
+    prevway=segmentx->way;
+    deleted=0;
+   }
 
- /* Print the final message */
+ if(!deleted)
+    if(segmentx->node1==NO_NODE_ID)
+       deleted=1;
 
- printf_last("Checked Segments: Segments=%"Pindex_t" Duplicate=%"Pindex_t" Loop=%"Pindex_t" No-Node=%"Pindex_t,total,duplicate,loop,nonode);
+ if(deleted)
+    return(0);
+ else
+    return(1);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Measure the segments and replace node/way ids with indexes.
+  Sort the segment list and deduplicate it.
 
-  SegmentsX *segmentsx The set of segments to process.
-
-  NodesX *nodesx The set of nodes to use.
-
-  WaysX *waysx The set of ways to use.
+  SegmentsX *segmentsx The set of segments to sort and modify.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void MeasureSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+void SortSegmentList(SegmentsX *segmentsx)
 {
- index_t index=0;
  int fd;
- SegmentX segmentx;
+ index_t xnumber;
 
  /* Print the start message */
 
- printf_first("Measuring Segments: Segments=0");
-
- /* Map into memory /  open the file */
-
-#if !SLIM
- nodesx->data=MapFile(nodesx->filename);
-#else
- nodesx->fd=ReOpenFile(nodesx->filename);
-#endif
+ printf_first("Sorting Segments");
 
  /* Re-open the file read-only and a new file writeable */
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
-
- DeleteFile(segmentsx->filename);
-
- fd=OpenFileNew(segmentsx->filename);
-
- /* Modify the on-disk image */
-
- while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
-   {
-    index_t node1=IndexNodeX(nodesx,segmentx.node1);
-    index_t node2=IndexNodeX(nodesx,segmentx.node2);
-    index_t way  =IndexWayX (waysx ,segmentx.way);
-
-    NodeX *nodex1=LookupNodeX(nodesx,node1,1);
-    NodeX *nodex2=LookupNodeX(nodesx,node2,2);
-
-    /* Replace the node and way ids with their indexes */
-
-    segmentx.node1=node1;
-    segmentx.node2=node2;
-    segmentx.way  =way;
-
-    /* Set the distance but preserve the other flags */
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
-    segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2));
+ DeleteFile(segmentsx->filename_tmp);
 
-    /* Write the modified segment */
+ fd=OpenFileNew(segmentsx->filename_tmp);
 
-    WriteFile(fd,&segmentx,sizeof(SegmentX));
+ /* Sort by node indexes */
 
-    index++;
+ xnumber=segmentsx->number;
 
-    if(!(index%10000))
-       printf_middle("Measuring Segments: Segments=%"Pindex_t,index);
-   }
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),NULL,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    (int (*)(void*,index_t))deduplicate);
 
  /* Close the files */
 
  segmentsx->fd=CloseFile(segmentsx->fd);
  CloseFile(fd);
 
- /* Free the other now-unneeded indexes */
-
- free(nodesx->idata);
- nodesx->idata=NULL;
-
- free(waysx->idata);
- waysx->idata=NULL;
-
- /* Unmap from memory / close the file */
-
-#if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
-#else
- nodesx->fd=CloseFile(nodesx->fd);
-#endif
-
  /* Print the final message */
 
- printf_last("Measured Segments: Segments=%"Pindex_t,segmentsx->number);
+ printf_last("Sorted Segments: Segments=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-segmentsx->number);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Remove the duplicate segments.
+  Sort the segments into id order, first by node1 then by node2, finally by distance.
 
-  SegmentsX *segmentsx The set of segments to modify.
+  int sort_by_id Returns the comparison of the node fields.
 
-  NodesX *nodesx The set of nodes to use.
+  SegmentX *a The first segment.
 
-  WaysX *waysx The set of ways to use.
+  SegmentX *b The second segment.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void DeduplicateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+static int sort_by_id(SegmentX *a,SegmentX *b)
 {
- index_t duplicate=0,good=0;
- index_t index=0;
- int fd,nprev=0;
- index_t prevnode1=NO_NODE,prevnode2=NO_NODE;
- SegmentX prevsegx[MAX_SEG_PER_NODE],segmentx;
- Way prevway[MAX_SEG_PER_NODE];
-
- /* Print the start message */
+ node_t a_id1=a->node1;
+ node_t b_id1=b->node1;
 
- printf_first("Deduplicating Segments: Segments=0 Duplicate=0");
+ if(a_id1<b_id1)
+    return(-1);
+ else if(a_id1>b_id1)
+    return(1);
+ else /* if(a_id1==b_id1) */
+   {
+    node_t a_id2=a->node2;
+    node_t b_id2=b->node2;
 
- /* Map into memory / open the file */
+    if(a_id2<b_id2)
+       return(-1);
+    else if(a_id2>b_id2)
+       return(1);
+    else
+      {
+       distance_t a_distance=DISTANCE(a->distance);
+       distance_t b_distance=DISTANCE(b->distance);
+
+       if(a_distance<b_distance)
+          return(-1);
+       else if(a_distance>b_distance)
+          return(1);
+       else
+         {
+          distance_t a_distflag=DISTFLAG(a->distance);
+          distance_t b_distflag=DISTFLAG(b->distance);
+
+          if(a_distflag<b_distflag)
+             return(-1);
+          else if(a_distflag>b_distflag)
+             return(1);
+          else
+             return(FILESORT_PRESERVE_ORDER(a,b)); /* preserve order */
+         }
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Discard duplicate segments.
+
+  int deduplicate Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended segment.
+
+  index_t index The number of sorted segments that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate(SegmentX *segmentx,index_t index)
+{
+ static node_t prevnode1=NO_NODE_ID,prevnode2=NO_NODE_ID;
+ static way_t prevway=NO_WAY_ID;
+ static distance_t prevdist=0;
+
+ if(prevnode1!=segmentx->node1 || prevnode2!=segmentx->node2 || prevway!=segmentx->way || prevdist!=segmentx->distance)
+   {
+    prevnode1=segmentx->node1;
+    prevnode2=segmentx->node2;
+    prevway=segmentx->way;
+    prevdist=segmentx->distance;
+
+    return(1);
+   }
+ else
+    return(0);
+}
 
-#if !SLIM
- waysx->data=MapFile(waysx->filename);
-#else
- waysx->fd=ReOpenFile(waysx->filename);
-#endif
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove bad segments (duplicated, zero length or with missing nodes).
+
+  SegmentsX *segmentsx The set of segments to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  WaysX *waysx The set of ways to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemoveBadSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx,int keep)
+{
+ index_t noway=0,loop=0,nonode=0,duplicate=0,good=0,total=0;
+ node_t prevnode1=NO_NODE_ID,prevnode2=NO_NODE_ID;
+ way_t prevway=NO_WAY_ID;
+ distance_t prevdist=0;
+ SegmentX segmentx;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Checking Segments: Segments=0 Loop=0 No-Way=0 No-Node=0 Duplicate=0");
+
+ /* Allocate the node usage bitmask */
+
+ segmentsx->usednode=AllocBitMask(nodesx->number);
+
+ logassert(segmentsx->usednode,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
  /* Re-open the file read-only and a new file writeable */
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
- DeleteFile(segmentsx->filename);
+ if(keep)
+    RenameFile(segmentsx->filename_tmp,segmentsx->filename);
+ else
+    DeleteFile(segmentsx->filename_tmp);
 
- fd=OpenFileNew(segmentsx->filename);
+ fd=OpenFileNew(segmentsx->filename_tmp);
 
  /* Modify the on-disk image */
 
  while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
    {
-    WayX *wayx=LookupWayX(waysx,segmentx.way,1);
-    int isduplicate=0;
+    index_t index1=IndexNodeX(nodesx,segmentx.node1);
+    index_t index2=IndexNodeX(nodesx,segmentx.node2);
+    index_t indexw=IndexWayX(waysx,segmentx.way);
 
-    if(segmentx.node1==prevnode1 && segmentx.node2==prevnode2)
+    if(indexw==NO_WAY)
       {
-       int offset;
+       logerror("Segment belongs to way %"Pway_t" but it doesn't exist.\n",segmentx.way);
 
-       for(offset=0;offset<nprev;offset++)
-         {
-          if(DISTFLAG(segmentx.distance)==DISTFLAG(prevsegx[offset].distance))
-             if(!WaysCompare(&prevway[offset],&wayx->way))
-               {
-                isduplicate=1;
-                break;
-               }
-         }
+       noway++;
+      }
+    else if(segmentx.node1==segmentx.node2)
+      {
+       logerror("Segment connects node %"Pnode_t" to itself.\n",segmentx.node1);
 
-       if(isduplicate)
-         {
-          nprev--;
+       loop++;
+      }
+    else if(index1==NO_NODE || index2==NO_NODE)
+      {
+       if(index1==NO_NODE && index2==NO_NODE)
+          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but neither exist.\n",segmentx.node1,segmentx.node2);
 
-          for(;offset<nprev;offset++)
-            {
-             prevsegx[offset]=prevsegx[offset+1];
-             prevway[offset] =prevway[offset+1];
-            }
-         }
+       if(index1==NO_NODE && index2!=NO_NODE)
+          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but the first one does not exist.\n",segmentx.node1,segmentx.node2);
+
+       if(index1!=NO_NODE && index2==NO_NODE)
+          logerror("Segment connects nodes %"Pnode_t" and %"Pnode_t" but the second one does not exist.\n",segmentx.node1,segmentx.node2);
+
+       nonode++;
+      }
+    else if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
+      {
+       if(prevway==segmentx.way)
+          ; /* already logged an error - only possible to get here for oneway opposite direction segments */
        else
          {
-          assert(nprev<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
+          if(!(prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated.\n",segmentx.node1,segmentx.node2);
 
-          prevsegx[nprev]=segmentx;
-          prevway[nprev] =wayx->way;
+          if(!(prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the area).\n",segmentx.node1,segmentx.node2);
 
-          nprev++;
+          if((prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the non-area).\n",segmentx.node1,segmentx.node2);
+
+          if((prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (both are areas).\n",segmentx.node1,segmentx.node2);
          }
-      }
-    else
-      {
-       nprev=1;
-       prevnode1=segmentx.node1;
-       prevnode2=segmentx.node2;
-       prevsegx[0]=segmentx;
-       prevway[0] =wayx->way;
-      }
 
-    if(isduplicate)
        duplicate++;
+      }
     else
       {
        WriteFile(fd,&segmentx,sizeof(SegmentX));
 
+       SetBit(segmentsx->usednode,index1);
+       SetBit(segmentsx->usednode,index2);
+
+       prevnode1=segmentx.node1;
+       prevnode2=segmentx.node2;
+       prevway=segmentx.way;
+       prevdist=DISTANCE(segmentx.distance);
+
        good++;
       }
 
-    index++;
+    total++;
 
-    if(!(index%10000))
-       printf_middle("Deduplicating Segments: Segments=%"Pindex_t" Duplicate=%"Pindex_t,index,duplicate);
+    if(!(total%10000))
+       printf_middle("Checking Segments: Segments=%"Pindex_t" Loop=%"Pindex_t" No-Way=%"Pindex_t" No-Node=%"Pindex_t" Duplicate=%"Pindex_t,total,loop,noway,nonode,duplicate);
    }
 
  segmentsx->number=good;
@@ -688,17 +640,115 @@ void DeduplicateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
  segmentsx->fd=CloseFile(segmentsx->fd);
  CloseFile(fd);
 
+ /* Print the final message */
+
+ printf_last("Checked Segments: Segments=%"Pindex_t" Loop=%"Pindex_t" No-Way=%"Pindex_t" No-Node=%"Pindex_t" Duplicate=%"Pindex_t,total,loop,noway,nonode,duplicate);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Measure the segments and replace node/way ids with indexes.
+
+  SegmentsX *segmentsx The set of segments to process.
+
+  NodesX *nodesx The set of nodes to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void MeasureSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+{
+ index_t index=0;
+ int fd;
+ SegmentX segmentx;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Measuring Segments: Segments=0");
+
+ /* Map into memory /  open the file */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename_tmp);
+#else
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
+#endif
+
+ /* Allocate the way usage bitmask */
+
+ segmentsx->usedway=AllocBitMask(waysx->number);
+
+ logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+
+ DeleteFile(segmentsx->filename_tmp);
+
+ fd=OpenFileNew(segmentsx->filename_tmp);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
+   {
+    index_t node1=IndexNodeX(nodesx,segmentx.node1);
+    index_t node2=IndexNodeX(nodesx,segmentx.node2);
+    index_t way  =IndexWayX (waysx ,segmentx.way);
+
+    NodeX *nodex1=LookupNodeX(nodesx,node1,1);
+    NodeX *nodex2=LookupNodeX(nodesx,node2,2);
+
+    /* Replace the node and way ids with their indexes */
+
+    segmentx.node1=node1;
+    segmentx.node2=node2;
+    segmentx.way  =way;
+
+    SetBit(segmentsx->usedway,segmentx.way);
+
+    /* Set the distance but keep the other flags except for area */
+
+    segmentx.distance=DISTANCE(DistanceX(nodex1,nodex2))|DISTFLAG(segmentx.distance);
+    segmentx.distance&=~SEGMENT_AREA;
+
+    /* Write the modified segment */
+
+    WriteFile(fd,&segmentx,sizeof(SegmentX));
+
+    index++;
+
+    if(!(index%10000))
+       printf_middle("Measuring Segments: Segments=%"Pindex_t,index);
+   }
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFile(segmentsx->fd);
+ CloseFile(fd);
+
+ /* Free the other now-unneeded indexes */
+
+ free(nodesx->idata);
+ nodesx->idata=NULL;
+
+ free(waysx->idata);
+ waysx->idata=NULL;
+
  /* Unmap from memory / close the file */
 
 #if !SLIM
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
 #else
- waysx->fd=CloseFile(waysx->fd);
+ nodesx->fd=CloseFile(nodesx->fd);
 #endif
 
  /* Print the final message */
 
- printf_last("Deduplicated Segments: Segments=%"Pindex_t" Duplicate=%"Pindex_t" Unique=%"Pindex_t,index,duplicate,good);
+ printf_last("Measured Segments: Segments=%"Pindex_t,segmentsx->number);
 }
 
 
@@ -707,10 +757,12 @@ void DeduplicateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 
   SegmentsX *segmentsx The set of segments to modify.
 
-  NodesX *nodesx The sset of nodes to use.
+  NodesX *nodesx The set of nodes to use.
+
+  WaysX *waysx The set of ways to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
+void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
 {
  index_t index,i;
 
@@ -723,12 +775,12 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
 
  /* Allocate the array of indexes */
 
- if(!segmentsx->firstnode)
-   {
-    segmentsx->firstnode=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ if(segmentsx->firstnode)
+    free(segmentsx->firstnode);
 
-    assert(segmentsx->firstnode); /* Check malloc() worked */
-   }
+ segmentsx->firstnode=(index_t*)malloc(nodesx->number*sizeof(index_t));
+
+ logassert(segmentsx->firstnode,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
  for(i=0;i<nodesx->number;i++)
     segmentsx->firstnode[i]=NO_SEGMENT;
@@ -736,9 +788,9 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
  /* Map into memory / open the files */
 
 #if !SLIM
- segmentsx->data=MapFileWriteable(segmentsx->filename);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
 #else
- segmentsx->fd=ReOpenFileWriteable(segmentsx->filename);
+ segmentsx->fd=ReOpenFileWriteable(segmentsx->filename_tmp);
 #endif
 
  /* Read through the segments in reverse order */
@@ -747,6 +799,15 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
    {
     SegmentX *segmentx=LookupSegmentX(segmentsx,index,1);
 
+    if(nodesx->pdata)
+      {
+       segmentx->node1=nodesx->pdata[segmentx->node1];
+       segmentx->node2=nodesx->pdata[segmentx->node2];
+      }
+
+    if(waysx->cdata)
+       segmentx->way=waysx->cdata[segmentx->way];
+
     segmentx->next2=segmentsx->firstnode[segmentx->node2];
 
     PutBackSegmentX(segmentsx,segmentx);
@@ -761,11 +822,25 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
  /* Unmap from memory / close the files */
 
 #if !SLIM
- segmentsx->data=UnmapFile(segmentsx->filename);
+ segmentsx->data=UnmapFile(segmentsx->data);
 #else
  segmentsx->fd=CloseFile(segmentsx->fd);
 #endif
 
+ /* Free the memory */
+
+ if(nodesx->pdata)
+   {
+    free(nodesx->pdata);
+    nodesx->pdata=NULL;
+   }
+
+ if(waysx->cdata)
+   {
+    free(waysx->cdata);
+    waysx->cdata=NULL;
+   }
+
  /* Print the final message */
 
  printf_last("Indexed Segments: Segments=%"Pindex_t,segmentsx->number);
@@ -773,90 +848,287 @@ void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Update the segment indexes after geographical sorting.
+  Prune the deleted segments while resorting the list.
 
-  SegmentsX *segmentsx The set of segments to modify.
+  SegmentsX *segmentsx The set of segments to sort and modify.
 
-  NodesX *nodesx The set of nodes to use.
+  WaysX *waysx The set of ways to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemovePrunedSegments(SegmentsX *segmentsx,WaysX *waysx)
+{
+ int fd;
+ index_t xnumber;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting and Pruning Segments");
+
+ /* Allocate the way usage bitmask */
+
+ segmentsx->usedway=AllocBitMask(waysx->number);
+
+ logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+
+ DeleteFile(segmentsx->filename_tmp);
+
+ fd=OpenFileNew(segmentsx->filename_tmp);
+
+ /* Sort by node indexes */
+
+ xnumber=segmentsx->number;
+
+ sortsegmentsx=segmentsx;
+
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(void*,index_t))delete_pruned,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    NULL);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFile(segmentsx->fd);
+ CloseFile(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted and Pruned Segments: Segments=%"Pindex_t" Deleted=%"Pindex_t,xnumber,xnumber-segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete the pruned segments.
+
+  int delete_pruned Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended segment.
+
+  index_t index The number of unsorted segments that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int delete_pruned(SegmentX *segmentx,index_t index)
+{
+ if(IsPrunedSegmentX(segmentx))
+    return(0);
+
+ SetBit(sortsegmentsx->usedway,segmentx->way);
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove the duplicate super-segments.
+
+  SegmentsX *segmentsx The set of super-segments to modify.
 
   WaysX *waysx The set of ways to use.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void UpdateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+void DeduplicateSuperSegments(SegmentsX *segmentsx,WaysX *waysx)
 {
- index_t i;
  int fd;
+ index_t xnumber;
+
+ if(waysx->number==0)
+    return;
 
  /* Print the start message */
 
- printf_first("Updating Segments: Segments=0");
+ printf_first("Sorting and Deduplicating Super-Segments");
 
- /* Map into memory / open the files */
+ /* Map into memory / open the file */
 
 #if !SLIM
- waysx->data=MapFile(waysx->filename);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- waysx->fd=ReOpenFile(waysx->filename);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  /* Re-open the file read-only and a new file writeable */
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
- DeleteFile(segmentsx->filename);
+ DeleteFile(segmentsx->filename_tmp);
 
- fd=OpenFileNew(segmentsx->filename);
+ fd=OpenFileNew(segmentsx->filename_tmp);
 
- /* Modify the on-disk image */
+ /* Sort by node indexes */
 
- for(i=0;i<segmentsx->number;i++)
+ xnumber=segmentsx->number;
+
+ sortsegmentsx=segmentsx;
+ sortwaysx=waysx;
+
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),NULL,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    (int (*)(void*,index_t))deduplicate_super);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFile(segmentsx->fd);
+ CloseFile(fd);
+
+ /* Unmap from memory / close the file */
+
+#if !SLIM
+ waysx->data=UnmapFile(waysx->data);
+#else
+ waysx->fd=CloseFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Sorted and Deduplicated Super-Segments: Super-Segments=%"Pindex_t" Duplicate=%"Pindex_t,xnumber,xnumber-segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  De-duplicate super-segments.
+
+  int deduplicate_super Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended super-segment.
+
+  index_t index The number of sorted super-segments that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_super(SegmentX *segmentx,index_t index)
+{
+ static int nprev=0;
+ static index_t prevnode1=NO_NODE,prevnode2=NO_NODE;
+ static SegmentX prevsegx[MAX_SEG_PER_NODE];
+ static Way prevway[MAX_SEG_PER_NODE];
+
+ WayX *wayx=LookupWayX(sortwaysx,segmentx->way,1);
+ int isduplicate=0;
+
+ if(index==0 || segmentx->node1!=prevnode1 || segmentx->node2!=prevnode2)
    {
-    SegmentX segmentx;
-    WayX *wayx;
+    nprev=1;
+    prevnode1=segmentx->node1;
+    prevnode2=segmentx->node2;
+    prevsegx[0]=*segmentx;
+    prevway[0] =wayx->way;
+   }
+ else
+   {
+    int offset;
 
-    ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX));
+    for(offset=0;offset<nprev;offset++)
+      {
+       if(DISTFLAG(segmentx->distance)==DISTFLAG(prevsegx[offset].distance))
+          if(!WaysCompare(&prevway[offset],&wayx->way))
+            {
+             isduplicate=1;
+             break;
+            }
+      }
 
-    segmentx.node1=nodesx->gdata[segmentx.node1];
-    segmentx.node2=nodesx->gdata[segmentx.node2];
+    if(isduplicate)
+      {
+       nprev--;
 
-    if(segmentx.node1>segmentx.node2)
+       for(;offset<nprev;offset++)
+         {
+          prevsegx[offset]=prevsegx[offset+1];
+          prevway[offset] =prevway[offset+1];
+         }
+      }
+    else
       {
-       index_t temp;
+       logassert(nprev<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
 
-       temp=segmentx.node1;
-       segmentx.node1=segmentx.node2;
-       segmentx.node2=temp;
+       prevsegx[nprev]=*segmentx;
+       prevway[nprev] =wayx->way;
 
-       if(segmentx.distance&(ONEWAY_2TO1|ONEWAY_1TO2))
-          segmentx.distance^=ONEWAY_2TO1|ONEWAY_1TO2;
+       nprev++;
       }
+   }
 
-    wayx=LookupWayX(waysx,segmentx.way,1);
+ return(!isduplicate);
+}
 
-    segmentx.way=wayx->prop;
 
-    WriteFile(fd,&segmentx,sizeof(SegmentX));
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the segments geographically after updating the node indexes.
 
-    if(!((i+1)%10000))
-       printf_middle("Updating Segments: Segments=%"Pindex_t,i+1);
-   }
+  SegmentsX *segmentsx The set of segments to modify.
+
+  NodesX *nodesx The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortSegmentListGeographically(SegmentsX *segmentsx,NodesX *nodesx)
+{
+ int fd;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Segments Geographically");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+
+ DeleteFile(segmentsx->filename_tmp);
+
+ fd=OpenFileNew(segmentsx->filename_tmp);
+
+ /* Update the segments with geographically sorted node indexes and sort them */
 
+ sortnodesx=nodesx;
+
+ filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(void*,index_t))geographically_index,
+                                                  (int (*)(const void*,const void*))sort_by_id,
+                                                  NULL);
  /* Close the files */
 
  segmentsx->fd=CloseFile(segmentsx->fd);
  CloseFile(fd);
 
- /* Unmap from memory / close the files */
+ /* Print the final message */
 
-#if !SLIM
- waysx->data=UnmapFile(waysx->filename);
-#else
- waysx->fd=CloseFile(waysx->fd);
-#endif
+ printf_last("Sorted Segments Geographically: Segments=%"Pindex_t,segmentsx->number);
+}
 
- /* Print the final message */
 
- printf_last("Updated Segments: Segments=%"Pindex_t,segmentsx->number);
+/*++++++++++++++++++++++++++++++++++++++
+  Update the segment indexes.
+
+  int geographically_index Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended segment.
+
+  index_t index The number of unsorted segments that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int geographically_index(SegmentX *segmentx,index_t index)
+{
+ segmentx->node1=sortnodesx->gdata[segmentx->node1];
+ segmentx->node2=sortnodesx->gdata[segmentx->node2];
+
+ if(segmentx->node1>segmentx->node2)
+   {
+    index_t temp;
+
+    temp=segmentx->node1;
+    segmentx->node1=segmentx->node2;
+    segmentx->node2=temp;
+
+    if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
+       segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2;
+   }
+
+ return(1);
 }
 
 
@@ -881,7 +1153,7 @@ void SaveSegmentList(SegmentsX *segmentsx,const char *filename)
 
  /* Re-open the file */
 
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
 
  /* Write out the segments data */
 
diff --git a/src/segmentsx.h b/src/segmentsx.h
index 23a4621..0071f20 100644
--- a/src/segmentsx.h
+++ b/src/segmentsx.h
@@ -52,8 +52,10 @@ struct _SegmentX
 /*+ A structure containing a set of segments (memory format). +*/
 struct _SegmentsX
 {
- char      *filename;           /*+ The name of the temporary file. +*/
- int        fd;                 /*+ The file descriptor of the temporary file. +*/
+ char      *filename;           /*+ The name of the intermediate file (for the SegmentsX). +*/
+ char      *filename_tmp;       /*+ The name of the temporary file (for the SegmentsX). +*/
+
+ int        fd;                 /*+ The file descriptor of the open file (for the SegmentsX). +*/
 
  index_t    number;             /*+ The number of extended segments still being considered. +*/
 
@@ -73,35 +75,39 @@ struct _SegmentsX
  index_t   *next1;              /*+ The index of the next segment with the same node1 (used while pruning). +*/
 
  BitMask   *usednode;           /*+ A flag to indicate if a node is used (used for removing bad segments). +*/
+
+ BitMask   *usedway;            /*+ A flag to indicate if a way is used (used for removing pruned ways). +*/
 };
 
 
 /* Functions in segmentsx.c */
 
-
-SegmentsX *NewSegmentList(int append);
+SegmentsX *NewSegmentList(int append,int readonly);
 void FreeSegmentList(SegmentsX *segmentsx,int keep);
 
-void SaveSegmentList(SegmentsX *segmentsx,const char *filename);
+void AppendSegmentList(SegmentsX *segmentsx,way_t way,node_t node1,node_t node2,distance_t distance);
+void FinishSegmentList(SegmentsX *segmentsx);
 
 SegmentX *FirstSegmentX(SegmentsX *segmentsx,index_t nodeindex,int position);
 SegmentX *NextSegmentX(SegmentsX *segmentsx,SegmentX *segmentx,index_t nodeindex);
 
-void AppendSegment(SegmentsX *segmentsx,way_t way,node_t node1,node_t node2,distance_t distance);
+void ApplySegmentChanges(SegmentsX *segmentsx);
+
+void SortSegmentList(SegmentsX *segmentsx);
 
-void SortSegmentList(SegmentsX *segmentsx,int delete);
+void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
 
-void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx);
+void RemoveBadSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx,int keep);
 
 void MeasureSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
 
-void DeduplicateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
+void RemovePrunedSegments(SegmentsX *segmentsx,WaysX *waysx);
 
-void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx);
+void DeduplicateSuperSegments(SegmentsX *segmentsx,WaysX *waysx);
 
-void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx);
+void SortSegmentListGeographically(SegmentsX *segmentsx,NodesX *nodesx);
 
-void UpdateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
+void SaveSegmentList(SegmentsX *segmentsx,const char *filename);
 
 
 /* Macros / inline functions */
@@ -117,6 +123,8 @@ void UpdateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
 #define IndexSegmentX(segmentsx,segmentx)                (index_t)((segmentx)-&(segmentsx)->data[0])
 
 #define PutBackSegmentX(segmentsx,segmentx)              /* nop */
+
+#define ReLookupSegmentX(segmentsx,segmentx)             /* nop */
   
 #else
 
@@ -126,6 +134,8 @@ static index_t IndexSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
 
 static void PutBackSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
 
+static void ReLookupSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
+
 
 /*++++++++++++++++++++++++++++++++++++++
   Lookup a particular extended segment with the specified id from the file on disk.
@@ -182,6 +192,22 @@ static inline void PutBackSegmentX(SegmentsX *segmentsx,SegmentX *segmentx)
  SeekWriteFile(segmentsx->fd,&segmentsx->cached[position1],sizeof(SegmentX),(off_t)segmentsx->incache[position1]*sizeof(SegmentX));
 }
 
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup an extended segment's data from the disk into file again after the disk was updated.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The extended segment to refresh.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void ReLookupSegmentX(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ int position1=segmentx-&segmentsx->cached[0];
+
+ SeekReadFile(segmentsx->fd,&segmentsx->cached[position1],sizeof(SegmentX),(off_t)segmentsx->incache[position1]*sizeof(SegmentX));
+}
+
 #endif /* SLIM */
 
 
diff --git a/src/sorting.c b/src/sorting.c
index 290ae75..2562db8 100644
--- a/src/sorting.c
+++ b/src/sorting.c
@@ -23,7 +23,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #if defined(USE_PTHREADS) && USE_PTHREADS
 #include <pthread.h>
@@ -31,6 +30,7 @@
 
 #include "types.h"
 
+#include "logging.h"
 #include "files.h"
 #include "sorting.h"
 
@@ -100,18 +100,27 @@ static void *filesort_vary_heapsort_thread(thread_data *thread);
 
   size_t itemsize The size of each item in the file that needs sorting.
 
-  int (*compare)(const void*, const void*) The comparison function (identical to qsort if the
-                                           data to be sorted is an array of things not pointers).
+  int (*pre_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item before they have been sorted.  The second parameter is the number of objects
+     previously read from the input file.  If the function returns 1 then the object is kept
+     and it is sorted, otherwise it is ignored.
 
-  int (*keep)(void *,index_t) If non-NULL then this function is called for each item, if it
-                              returns 1 then the object is kept and written to the output file.
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
+
+  int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item after they have been sorted.  The second parameter is the number of objects
+     already written to the output file.  If the function returns 1 then the object is written
+     to the output file., otherwise it is ignored.
   ++++++++++++++++++++++++++++++++++++++*/
 
-index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const void*,const void*),int (*keep)(void*,index_t))
+index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_function)(void*,index_t),
+                                                            int (*compare_function)(const void*,const void*),
+                                                            int (*post_sort_function)(void*,index_t))
 {
  int *fds=NULL,*heap=NULL;
  int nfiles=0,ndata=0;
- index_t count=0,total=0;
+ index_t count_out=0,count_in=0,total=0;
  size_t nitems=option_filesort_ramsize/(option_filesort_threads*(itemsize+sizeof(void*)));
  void *data,**datap;
  thread_data *threads;
@@ -134,7 +143,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
     threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
 
     threads[i].itemsize=itemsize;
-    threads[i].compare=compare;
+    threads[i].compare=compare_function;
    }
 
  /* Loop around, fill the buffer, sort the data and write a temporary file */
@@ -162,7 +171,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
     /* Read in the data and create pointers */
 
-    for(i=0;i<nitems;i++)
+    for(i=0;i<nitems;)
       {
        threads[thread].datap[i]=threads[thread].data+i*itemsize;
 
@@ -172,7 +181,13 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
           break;
          }
 
-       total++;
+       if(!pre_sort_function || pre_sort_function(threads[thread].datap[i],count_in))
+         {
+          i++;
+          total++;
+         }
+
+       count_in++;
       }
 
     threads[thread].n=i;
@@ -270,10 +285,10 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
    {
     for(i=0;i<threads[0].n;i++)
       {
-       if(!keep || keep(threads[0].datap[i],count))
+       if(!post_sort_function || post_sort_function(threads[0].datap[i],count_out))
          {
           WriteFile(fd_out,threads[0].datap[i],itemsize);
-          count++;
+          count_out++;
          }
       }
 
@@ -284,7 +299,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
  /* Check that number of files is less than file size */
 
- assert(nfiles<nitems);
+ logassert(nfiles<nitems,"Too many temporary files (use more sorting memory?)");
 
  /* Open all of the temporary files */
 
@@ -331,7 +346,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
        newindex=index/2;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])>=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])>=0)
           break;
 
        temp=heap[index];
@@ -350,10 +365,10 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
    {
     int index=1;
 
-    if(!keep || keep(datap[heap[index]],count))
+    if(!post_sort_function || post_sort_function(datap[heap[index]],count_out))
       {
        WriteFile(fd_out,datap[heap[index]],itemsize);
-       count++;
+       count_out++;
       }
 
     if(ReadFile(fds[heap[index]],datap[heap[index]],itemsize))
@@ -371,10 +386,10 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
        newindex=2*index;
 
-       if(compare(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
+       if(compare_function(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
           newindex=newindex+1;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])<=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
           break;
 
        temp=heap[newindex];
@@ -391,7 +406,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
        newindex=2*index;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])<=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
           ; /* break */
        else
          {
@@ -425,7 +440,7 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
     free(threads[i].filename);
    }
 
- return(count);
+ return(count_out);
 }
 
 
@@ -445,18 +460,27 @@ index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const
 
   int fd_out The file descriptor of the output file (opened for writing and empty).
 
-  int (*compare)(const void*, const void*) The comparison function (identical to qsort if the
-                                           data to be sorted is an array of things not pointers).
+  int (*pre_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item before they have been sorted.  The second parameter is the number of objects
+     previously read from the input file.  If the function returns 1 then the object is kept
+     and it is sorted, otherwise it is ignored.
 
-  int (*keep)(void *,index_t) If non-NULL then this function is called for each item, if it
-                              returns 1 then the object is kept and written to the output file.
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
+
+  int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item after they have been sorted.  The second parameter is the number of objects
+     already written to the output file.  If the function returns 1 then the object is written
+     to the output file., otherwise it is ignored.
   ++++++++++++++++++++++++++++++++++++++*/
 
-index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void*),int (*keep)(void*,index_t))
+index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_t),
+                                           int (*compare_function)(const void*,const void*),
+                                           int (*post_sort_function)(void*,index_t))
 {
  int *fds=NULL,*heap=NULL;
  int nfiles=0,ndata=0;
- index_t count=0,total=0;
+ index_t count_out=0,count_in=0,total=0;
  size_t datasize=option_filesort_ramsize/option_filesort_threads;
  FILESORT_VARINT nextitemsize,largestitemsize=0;
  void *data,**datap;
@@ -479,7 +503,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
     threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
 
-    threads[i].compare=compare;
+    threads[i].compare=compare_function;
    }
 
  /* Loop around, fill the buffer, sort the data and write a temporary file */
@@ -528,15 +552,20 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
        ReadFile(fd_in,threads[thread].data+ramused,itemsize);
 
-       *--threads[thread].datap=threads[thread].data+ramused; /* points to real data */
+       if(!pre_sort_function || pre_sort_function(threads[thread].data+ramused,count_in))
+         {
+          *--threads[thread].datap=threads[thread].data+ramused; /* points to real data */
+
+          ramused+=itemsize;
 
-       ramused+=itemsize;
+          ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARSIZE-1)/FILESORT_VARALIGN);
+          ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE;
 
-       ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARSIZE-1)/FILESORT_VARALIGN);
-       ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE;
+          total++;
+          threads[thread].n++;
+         }
 
-       total++;
-       threads[thread].n++;
+       count_in++;
 
        if(ReadFile(fd_in,&nextitemsize,FILESORT_VARSIZE))
          {
@@ -636,12 +665,12 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
    {
     for(i=0;i<threads[0].n;i++)
       {
-       if(!keep || keep(threads[0].datap[i],count))
+       if(!post_sort_function || post_sort_function(threads[0].datap[i],count_out))
          {
           FILESORT_VARINT itemsize=*(FILESORT_VARINT*)(threads[0].datap[i]-FILESORT_VARSIZE);
 
           WriteFile(fd_out,threads[0].datap[i]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
-          count++;
+          count_out++;
          }
       }
 
@@ -654,7 +683,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
  largestitemsize=FILESORT_VARALIGN*(1+(largestitemsize+FILESORT_VARALIGN-FILESORT_VARSIZE)/FILESORT_VARALIGN);
 
- assert(nfiles<((datasize-nfiles*sizeof(void*))/largestitemsize));
+ logassert(nfiles<((datasize-nfiles*sizeof(void*))/largestitemsize),"Too many temporary files (use more sorting memory?)");
 
  /* Open all of the temporary files */
 
@@ -706,7 +735,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
        newindex=index/2;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])>=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])>=0)
           break;
 
        temp=heap[index];
@@ -726,12 +755,12 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
     int index=1;
     FILESORT_VARINT itemsize;
 
-    if(!keep || keep(datap[heap[index]],count))
+    if(!post_sort_function || post_sort_function(datap[heap[index]],count_out))
       {
        itemsize=*(FILESORT_VARINT*)(datap[heap[index]]-FILESORT_VARSIZE);
 
        WriteFile(fd_out,datap[heap[index]]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
-       count++;
+       count_out++;
       }
 
     if(ReadFile(fds[heap[index]],&itemsize,FILESORT_VARSIZE))
@@ -755,10 +784,10 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
        newindex=2*index;
 
-       if(compare(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
+       if(compare_function(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
           newindex=newindex+1;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])<=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
           break;
 
        temp=heap[newindex];
@@ -775,7 +804,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
 
        newindex=2*index;
 
-       if(compare(datap[heap[index]],datap[heap[newindex]])<=0)
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
           ; /* break */
        else
          {
@@ -808,7 +837,7 @@ index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void
     free(threads[i].filename);
    }
 
- return(count);
+ return(count_out);
 }
 
 
@@ -915,11 +944,11 @@ static void *filesort_vary_heapsort_thread(thread_data *thread)
 
   size_t nitems The number of items of data to sort.
 
-  int(*compare)(const void *, const void *) The comparison function (identical to qsort if the
-                                            data to be sorted was an array of things not pointers).
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*))
+void filesort_heapsort(void **datap,size_t nitems,int(*compare_function)(const void*, const void*))
 {
  void **datap1=&datap[-1];
  int i;
@@ -939,7 +968,7 @@ void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, con
 
        newindex=index/2;
 
-       if(compare(datap1[index],datap1[newindex])<=0) /* reversed compared to filesort_fixed() above */
+       if(compare_function(datap1[index],datap1[newindex])<=0) /* reversed comparison to filesort_fixed() above */
           break;
 
        temp=datap1[index];
@@ -970,10 +999,10 @@ void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, con
 
        newindex=2*index;
 
-       if(compare(datap1[newindex],datap1[newindex+1])<=0) /* reversed compared to filesort_fixed() above */
+       if(compare_function(datap1[newindex],datap1[newindex+1])<=0) /* reversed comparison to filesort_fixed() above */
           newindex=newindex+1;
 
-       if(compare(datap1[index],datap1[newindex])>=0) /* reversed compared to filesort_fixed() above */
+       if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
           break;
 
        temp=datap1[newindex];
@@ -990,7 +1019,7 @@ void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, con
 
        newindex=2*index;
 
-       if(compare(datap1[index],datap1[newindex])>=0) /* reversed compared to filesort_fixed() above */
+       if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
           ; /* break */
        else
          {
diff --git a/src/sorting.h b/src/sorting.h
index 597bc7b..8e9033e 100644
--- a/src/sorting.h
+++ b/src/sorting.h
@@ -28,16 +28,30 @@
 #include "types.h"
 
 
-/* Functions in sorting.c */
+/* Constants */
 
 /*+ The type, size and alignment of variable to store the variable length +*/
 #define FILESORT_VARINT   unsigned short
 #define FILESORT_VARSIZE  sizeof(FILESORT_VARINT)
 #define FILESORT_VARALIGN sizeof(void*)
 
-index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const void*,const void*),int (*keep)(void*,index_t));
 
-index_t filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void*),int (*keep)(void*,index_t));
+/* Macros */
+
+/*+ A macro to use as a last resort in the comparison function to preserve
+    on the output the input order of items that compare equally. +*/
+#define FILESORT_PRESERVE_ORDER(a,b) ( ((a)<(b)) ? -1 : +1)
+
+
+/* Functions in sorting.c */
+
+index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_function)(void*,index_t),
+                                                            int (*compare_function)(const void*,const void*),
+                                                            int (*post_sort_function)(void*,index_t));
+
+index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_t),
+                                           int (*compare_function)(const void*,const void*),
+                                           int (*post_sort_function)(void*,index_t));
 
 void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*));
 
diff --git a/src/superx.c b/src/superx.c
index 894c282..4404a3b 100644
--- a/src/superx.c
+++ b/src/superx.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include "types.h"
@@ -40,7 +39,7 @@
 
 /* Local functions */
 
-static Results *FindRoutesWay(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match);
+static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -71,21 +70,21 @@ void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
    {
     nodesx->super=AllocBitMask(nodesx->number);
 
-    assert(nodesx->super); /* Check AllocBitMask() worked */
+    logassert(nodesx->super,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
 
-    SetAllBits1(nodesx->super,nodesx->number);
+    SetAllBits(nodesx->super,nodesx->number);
    }
 
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFile(nodesx->filename);
- segmentsx->data=MapFile(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFile(nodesx->filename);
- segmentsx->fd=ReOpenFile(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  /* Find super-nodes */
@@ -97,9 +96,7 @@ void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
        int issuper=0;
        NodeX *nodex=LookupNodeX(nodesx,i,1);
 
-       if(IsPrunedNodeX(nodex))
-          issuper=0;
-       else if(nodex->flags&(NODE_TURNRSTRCT|NODE_TURNRSTRCT2))
+       if(nodex->flags&(NODE_TURNRSTRCT|NODE_TURNRSTRCT2))
           issuper=1;
        else
          {
@@ -115,7 +112,7 @@ void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
              /* Segments that are loops count twice */
 
-             assert(count<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
+             logassert(count<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
 
              if(segmentx->node1==segmentx->node2)
                 segmentweight[count]=2;
@@ -179,9 +176,9 @@ void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  /* Unmap from memory / close the files */
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
@@ -212,10 +209,14 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  SegmentsX *supersegmentsx;
  index_t sn=0,ss=0;
 
- supersegmentsx=NewSegmentList(0);
+ supersegmentsx=NewSegmentList(0,0);
 
  if(segmentsx->number==0 || waysx->number==0)
+   {
+    FinishSegmentList(supersegmentsx);
+
     return(supersegmentsx);
+   }
 
  /* Print the start message */
 
@@ -224,13 +225,13 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  /* Map into memory / open the files */
 
 #if !SLIM
- nodesx->data=MapFile(nodesx->filename);
- segmentsx->data=MapFile(segmentsx->filename);
- waysx->data=MapFile(waysx->filename);
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
 #else
- nodesx->fd=ReOpenFile(nodesx->filename);
- segmentsx->fd=ReOpenFile(segmentsx->filename);
- waysx->fd=ReOpenFile(waysx->filename);
+ nodesx->fd=ReOpenFile(nodesx->filename_tmp);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 #endif
 
  /* Create super-segments for each super-node. */
@@ -265,7 +266,7 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
                   }
             }
 
-          assert(count<MAX_SEG_PER_NODE); /* Only a limited amount of history stored. */
+          logassert(count<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of history stored. */
 
           prevway[count++]=wayx->way;
 
@@ -273,17 +274,17 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
           if(!match)
             {
-             Results *results=FindRoutesWay(nodesx,segmentsx,waysx,i,&wayx->way);
+             Results *results=FindSuperRoutes(nodesx,segmentsx,waysx,i,&wayx->way);
              Result *result=FirstResult(results);
 
              while(result)
                {
                 if(IsBitSet(nodesx->super,result->node) && result->segment!=NO_SEGMENT)
                   {
-                   if(wayx->way.type&Way_OneWay && result->node!=i)
-                      AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2);
+                   if(wayx->way.type&Highway_OneWay && result->node!=i)
+                      AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2);
                    else
-                      AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score));
+                      AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score));
 
                    ss++;
                   }
@@ -307,9 +308,9 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
  /* Unmap from memory / close the files */
 
 #if !SLIM
- nodesx->data=UnmapFile(nodesx->filename);
- segmentsx->data=UnmapFile(segmentsx->filename);
- waysx->data=UnmapFile(waysx->filename);
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
 #else
  nodesx->fd=CloseFile(nodesx->fd);
  segmentsx->fd=CloseFile(segmentsx->fd);
@@ -320,6 +321,8 @@ SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
 
  printf_last("Created Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
 
+ FinishSegmentList(supersegmentsx);
+
  return(supersegmentsx);
 }
 
@@ -340,10 +343,14 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
  index_t merged=0,added=0;
  SegmentsX *mergedsegmentsx;
 
- mergedsegmentsx=NewSegmentList(0);
+ mergedsegmentsx=NewSegmentList(0,0);
 
  if(segmentsx->number==0)
+   {
+    FinishSegmentList(mergedsegmentsx);
+
     return(mergedsegmentsx);
+   }
 
  /* Print the start message */
 
@@ -352,13 +359,13 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
  /* Map into memory / open the files */
 
 #if !SLIM
- segmentsx->data=MapFile(segmentsx->filename);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
  if(supersegmentsx->number>0)
-    supersegmentsx->data=MapFile(supersegmentsx->filename);
+    supersegmentsx->data=MapFile(supersegmentsx->filename_tmp);
 #else
- segmentsx->fd=ReOpenFile(segmentsx->filename);
+ segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
  if(supersegmentsx->number>0)
-    supersegmentsx->fd=ReOpenFile(supersegmentsx->filename);
+    supersegmentsx->fd=ReOpenFile(supersegmentsx->filename_tmp);
 #endif
 
  /* Loop through and create a new list of combined segments */
@@ -389,7 +396,7 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
                (segmentx->node1>supersegmentx->node1))
          {
           /* mark as super-segment */
-          AppendSegment(mergedsegmentsx,supersegmentx->way,supersegmentx->node1,supersegmentx->node2,supersegmentx->distance|SEGMENT_SUPER);
+          AppendSegmentList(mergedsegmentsx,supersegmentx->way,supersegmentx->node1,supersegmentx->node2,supersegmentx->distance|SEGMENT_SUPER);
           added++;
           j++;
          }
@@ -401,9 +408,9 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
       }
 
     if(super)
-       AppendSegment(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_SUPER|SEGMENT_NORMAL);
+       AppendSegmentList(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_SUPER|SEGMENT_NORMAL);
     else
-       AppendSegment(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_NORMAL);
+       AppendSegmentList(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_NORMAL);
 
     if(!((i+1)%10000))
        printf_middle("Merging Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,i+1,j,merged,added);
@@ -412,9 +419,9 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
  /* Unmap from memory / close the files */
 
 #if !SLIM
- segmentsx->data=UnmapFile(segmentsx->filename);
+ segmentsx->data=UnmapFile(segmentsx->data);
  if(supersegmentsx->number>0)
-    supersegmentsx->data=UnmapFile(supersegmentsx->filename);
+    supersegmentsx->data=UnmapFile(supersegmentsx->data);
 #else
  segmentsx->fd=CloseFile(segmentsx->fd);
  if(supersegmentsx->number>0)
@@ -425,6 +432,8 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
 
  printf_last("Merged Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,segmentsx->number,supersegmentsx->number,merged,added);
 
+ FinishSegmentList(mergedsegmentsx);
+
  return(mergedsegmentsx);
 }
 
@@ -432,7 +441,7 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
 /*++++++++++++++++++++++++++++++++++++++
   Find all routes from a specified super-node to any other super-node that follows a certain type of way.
 
-  Results *FindRoutesWay Returns a set of results.
+  Results *FindSuperRoutes Returns a set of results.
 
   NodesX *nodesx The set of nodes to use.
 
@@ -445,7 +454,7 @@ SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
   Way *match A template for the type of way that the route must follow.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static Results *FindRoutesWay(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match)
+static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match)
 {
  Results *results;
  Queue *queue;
diff --git a/src/tagging.c b/src/tagging.c
index cf19b8c..47ec539 100644
--- a/src/tagging.c
+++ b/src/tagging.c
@@ -531,11 +531,8 @@ void DeleteTagList(TagList *tags)
     if(tags->v[i]) free(tags->v[i]);
    }
 
- if(tags->ntags)
-   {
-    free(tags->k);
-    free(tags->v);
-   }
+ if(tags->k) free(tags->k);
+ if(tags->v) free(tags->v);
 
  free(tags);
 }
@@ -553,14 +550,14 @@ void DeleteTagList(TagList *tags)
 
 void AppendTag(TagList *tags,const char *k,const char *v)
 {
- if((tags->ntags%16)==0)
+ if((tags->ntags%8)==0)
    {
     int i;
 
-    tags->k=(char**)realloc((void*)tags->k,(tags->ntags+16)*sizeof(char*));
-    tags->v=(char**)realloc((void*)tags->v,(tags->ntags+16)*sizeof(char*));
+    tags->k=(char**)realloc((void*)tags->k,(tags->ntags+8)*sizeof(char*));
+    tags->v=(char**)realloc((void*)tags->v,(tags->ntags+8)*sizeof(char*));
 
-    for(i=tags->ntags;i<(tags->ntags+16);i++)
+    for(i=tags->ntags;i<(tags->ntags+8);i++)
        tags->k[i]=tags->v[i]=NULL;
    }
 
@@ -721,11 +718,11 @@ static void apply_actions(TaggingRuleList *rules,TaggingRule *rule,int match,Tag
     if(rule->actions[i].action==TAGACTION_LOGERROR)
       {
        if(rules==&NodeRules)
-          logerror("Node %"Pnode_t" has an unrecognised tag value '%s' = '%s' (in tagging rules).\n",id,k,v);
+          logerror("Node %"Pnode_t" has an unrecognised tag value '%s' = '%s' (in tagging rules); ignoring it.\n",id,k,v);
        if(rules==&WayRules)
-          logerror("Way %"Pway_t" has an unrecognised tag value '%s' = '%s' (in tagging rules).\n",id,k,v);
+          logerror("Way %"Pway_t" has an unrecognised tag value '%s' = '%s' (in tagging rules); ignoring it.\n",id,k,v);
        if(rules==&RelationRules)
-          logerror("Relation %"Prelation_t" has an unrecognised tag value '%s' = '%s' (in tagging rules).\n",id,k,v);
+          logerror("Relation %"Prelation_t" has an unrecognised tag value '%s' = '%s' (in tagging rules); ignoring it.\n",id,k,v);
       }
    }
 }
diff --git a/src/tagmodifier.c b/src/tagmodifier.c
index 8e37186..aa72544 100644
--- a/src/tagmodifier.c
+++ b/src/tagmodifier.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2011 Andrew M. Bishop
+ This file Copyright 2010-2012 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
@@ -272,7 +272,7 @@ static int nodeType_function(const char *_tag_,int _type_,const char *id,const c
 
     XMLPARSE_ASSERT_INTEGER(_tag_,id);   llid=atoll(id); /* need long long conversion */
     node_id=(node_t)llid;
-    assert((long long)node_id==llid);      /* check node id can be stored in node_t data type. */
+    logassert((long long)node_id==llid,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
    }
 
  if(_type_&XMLPARSE_TAG_END)
@@ -399,7 +399,7 @@ static int wayType_function(const char *_tag_,int _type_,const char *id,const ch
     XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */
 
     way_id=(way_t)llid;
-    assert((long long)way_id==llid);   /* check way id can be stored in way_t data type. */
+    logassert((long long)way_id==llid,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
    }
 
  if(_type_&XMLPARSE_TAG_END)
@@ -476,7 +476,7 @@ static int relationType_function(const char *_tag_,int _type_,const char *id,con
     XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */
 
     relation_id=(relation_t)llid;
-    assert((long long)relation_id==llid);   /* check relation id can be stored in relation_t data type. */
+    logassert((long long)relation_id==llid,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
    }
 
  if(_type_&XMLPARSE_TAG_END)
diff --git a/src/translations.c b/src/translations.c
index f13d1f5..daff2db 100644
--- a/src/translations.c
+++ b/src/translations.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2011 Andrew M. Bishop
+ This file Copyright 2010-2012 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
@@ -43,7 +43,7 @@ char *translate_xml_heading[9] ={"South","South-West","West","North-West","North
 char *translate_xml_turn[9]    ={"Very sharp left","Sharp left","Left","Slight left","Straight on","Slight right","Right","Sharp right","Very sharp right"};
 char *translate_xml_ordinal[10]={"First","Second","Third","Fourth","Fifth","Sixth","Seventh","Eighth","Ninth","Tenth"};
 
-char *translate_raw_highway[Way_Count]={"","motorway","trunk road","primary road","secondary road","tertiary road","unclassified road","residential road","service road","track","cycleway","path","steps","ferry"};
+char *translate_raw_highway[Highway_Count]={"","motorway","trunk road","primary road","secondary road","tertiary road","unclassified road","residential road","service road","track","cycleway","path","steps","ferry"};
 
 char *translate_xml_route_shortest="Shortest";
 char *translate_xml_route_quickest="Quickest";
@@ -561,7 +561,7 @@ static int HighwayType_function(const char *_tag_,int _type_,const char *type,co
 
     highway=HighwayType(type);
 
-    if(highway==Way_Count)
+    if(highway==Highway_None)
        XMLPARSE_INVALID(_tag_,type);
 
     translate_raw_highway[highway]=strcpy(malloc(strlen(string)+1),string);
diff --git a/src/translations.h b/src/translations.h
index d875bed..e98ec8c 100644
--- a/src/translations.h
+++ b/src/translations.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2011 Andrew M. Bishop
+ This file Copyright 2010-2012 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
@@ -40,7 +40,7 @@ extern char *translate_xml_heading[9];
 extern char *translate_xml_turn[9];
 extern char *translate_xml_ordinal[10];
 
-extern char *translate_raw_highway[Way_Count];
+extern char *translate_raw_highway[Highway_Count];
 
 extern char *translate_xml_route_shortest;
 extern char *translate_xml_route_quickest;
diff --git a/src/types.c b/src/types.c
index cc1b3fd..d7842cf 100644
--- a/src/types.c
+++ b/src/types.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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
@@ -38,47 +38,47 @@ Highway HighwayType(const char *highway)
  switch(*highway)
    {
    case 'c':
-    if(!strcmp(highway,"cycleway")) return(Way_Cycleway);
-    return(Way_Count);
+    if(!strcmp(highway,"cycleway")) return(Highway_Cycleway);
+    break;
 
    case 'f':
-    if(!strcmp(highway,"ferry")) return(Way_Ferry);
-    return(Way_Count);
+    if(!strcmp(highway,"ferry")) return(Highway_Ferry);
+    break;
 
    case 'm':
-    if(!strcmp(highway,"motorway")) return(Way_Motorway);
-    return(Way_Count);
+    if(!strcmp(highway,"motorway")) return(Highway_Motorway);
+    break;
 
    case 'p':
-    if(!strcmp(highway,"primary")) return(Way_Primary);
-    if(!strcmp(highway,"path")) return(Way_Path);
-    return(Way_Count);
+    if(!strcmp(highway,"primary")) return(Highway_Primary);
+    if(!strcmp(highway,"path")) return(Highway_Path);
+    break;
 
    case 'r':
-    if(!strcmp(highway,"residential")) return(Way_Residential);
-    return(Way_Count);
+    if(!strcmp(highway,"residential")) return(Highway_Residential);
+    break;
 
    case 's':
-    if(!strcmp(highway,"secondary")) return(Way_Secondary);
-    if(!strcmp(highway,"service")) return(Way_Service);
-    if(!strcmp(highway,"steps")) return(Way_Steps);
-    return(Way_Count);
+    if(!strcmp(highway,"secondary")) return(Highway_Secondary);
+    if(!strcmp(highway,"service")) return(Highway_Service);
+    if(!strcmp(highway,"steps")) return(Highway_Steps);
+    break;
 
    case 't':
-    if(!strcmp(highway,"trunk")) return(Way_Trunk);
-    if(!strcmp(highway,"tertiary")) return(Way_Tertiary);
-    if(!strcmp(highway,"track")) return(Way_Track);
-    return(Way_Count);
+    if(!strcmp(highway,"trunk")) return(Highway_Trunk);
+    if(!strcmp(highway,"tertiary")) return(Highway_Tertiary);
+    if(!strcmp(highway,"track")) return(Highway_Track);
+    break;
 
    case 'u':
-    if(!strcmp(highway,"unclassified")) return(Way_Unclassified);
-    return(Way_Count);
+    if(!strcmp(highway,"unclassified")) return(Highway_Unclassified);
+    break;
 
    default:
     ;
    }
 
- return(Way_Count);
+ return(Highway_None);
 }
 
 
@@ -203,39 +203,42 @@ const char *HighwayName(Highway highway)
 {
  switch(highway)
    {
-   case Way_Motorway:
+   case Highway_None:
+    return("NONE");
+
+   case Highway_Motorway:
     return("motorway");
-   case Way_Trunk:
+   case Highway_Trunk:
     return("trunk");
-   case Way_Primary:
+   case Highway_Primary:
     return("primary");
-   case Way_Secondary:
+   case Highway_Secondary:
     return("secondary");
-   case Way_Tertiary:
+   case Highway_Tertiary:
     return("tertiary");
-   case Way_Unclassified:
+   case Highway_Unclassified:
     return("unclassified");
-   case Way_Residential:
+   case Highway_Residential:
     return("residential");
-   case Way_Service:
+   case Highway_Service:
     return("service");
-   case Way_Track:
+   case Highway_Track:
     return("track");
-   case Way_Cycleway:
+   case Highway_Cycleway:
     return("cycleway");
-   case Way_Path:
+   case Highway_Path:
     return("path");
-   case Way_Steps:
+   case Highway_Steps:
     return("steps");
-   case Way_Ferry:
+   case Highway_Ferry:
     return("ferry");
 
-   case Way_Count:
+   case Highway_Count:
     ;
 
-   case Way_OneWay:
+   case Highway_OneWay:
     ;
-   case Way_Roundabout:
+   case Highway_Roundabout:
     ;
    }
 
diff --git a/src/types.h b/src/types.h
index c72ffae..44a1b74 100644
--- a/src/types.h
+++ b/src/types.h
@@ -40,16 +40,16 @@
 
 
 /*+ An undefined node index. +*/
-#define NO_NODE        (~(index_t)0)
+#define NO_NODE        ((index_t)~0)
 
 /*+ An undefined segment index. +*/
-#define NO_SEGMENT     (~(index_t)0)
+#define NO_SEGMENT     ((index_t)~0)
 
 /*+ An undefined way index. +*/
-#define NO_WAY         (~(index_t)0)
+#define NO_WAY         ((index_t)~0)
 
 /*+ An undefined relation index. +*/
-#define NO_RELATION    (~(index_t)0)
+#define NO_RELATION    ((index_t)~0)
 
 /*+ An undefined location. +*/
 #define NO_LATLONG     ((latlong_t)0x80000000)
@@ -68,39 +68,46 @@
 /*+ The latitude and longitude integer range within each bin. +*/
 #define LAT_LONG_BIN   65536
 
+
 /*+ A flag to mark a node as a super-node. +*/
-#define NODE_SUPER     ((uint16_t)0x8000)
+#define NODE_SUPER       ((nodeflags_t)0x8000)
 
 /*+ A flag to mark a node as suitable for a U-turn. +*/
-#define NODE_UTURN     ((uint16_t)0x4000)
+#define NODE_UTURN       ((nodeflags_t)0x4000)
 
 /*+ A flag to mark a node as a mini-roundabout. +*/
-#define NODE_MINIRNDBT ((uint16_t)0x2000)
+#define NODE_MINIRNDBT   ((nodeflags_t)0x2000)
 
 /*+ A flag to mark a node as a turn relation via node. +*/
-#define NODE_TURNRSTRCT ((uint16_t)0x1000)
+#define NODE_TURNRSTRCT  ((nodeflags_t)0x1000)
 
-/*+ A flag to mark a node as a turn relation via node. +*/
-#define NODE_TURNRSTRCT2 ((uint16_t)0x0800)
+/*+ A flag to mark a node as adjacent to a turn relation via node. +*/
+#define NODE_TURNRSTRCT2 ((nodeflags_t)0x0800)
+
+/*+ A flag to mark a node as deleted. +*/
+#define NODE_DELETED     ((nodeflags_t)0x0400)
 
 
+/*+ A flag to mark a segment as being part of an area (must be the highest valued flag). +*/
+#define SEGMENT_AREA   ((distance_t)0x80000000)
+
 /*+ A flag to mark a segment as one-way from node1 to node2. +*/
-#define ONEWAY_1TO2    ((distance_t)0x80000000)
+#define ONEWAY_1TO2    ((distance_t)0x40000000)
 
 /*+ A flag to mark a segment as one-way from node2 to node1. +*/
-#define ONEWAY_2TO1    ((distance_t)0x40000000)
+#define ONEWAY_2TO1    ((distance_t)0x20000000)
 
 /*+ A flag to mark a segment as a super-segment. +*/
-#define SEGMENT_SUPER  ((distance_t)0x20000000)
+#define SEGMENT_SUPER  ((distance_t)0x10000000)
 
 /*+ A flag to mark a segment as a normal segment. +*/
-#define SEGMENT_NORMAL ((distance_t)0x10000000)
+#define SEGMENT_NORMAL ((distance_t)0x08000000)
 
 /*+ The real distance ignoring the other flags. +*/
-#define DISTANCE(xx)   ((distance_t)((xx)&(~(ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL))))
+#define DISTANCE(xx)   ((distance_t)((xx)&(~(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL))))
 
 /*+ The distance flags selecting only the flags. +*/
-#define DISTFLAG(xx)   ((distance_t)((xx)&(ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL)))
+#define DISTFLAG(xx)   ((distance_t)((xx)&(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL)))
 
 
 /*+ A very large almost infinite distance. +*/
@@ -110,6 +117,14 @@
 #define INF_SCORE      (score_t)1E30
 
 
+/*+ A flag to mark a deleted way. +*/
+#define WAY_DELETED ((highway_t)~0)
+
+
+/*+ A flag to mark a deleted relation. +*/
+#define RELATION_DELETED ((transports_t)~0)
+
+
 /* Simple Types */
 
 
@@ -161,6 +176,9 @@ typedef uint16_t ll_off_t;
 #define degrees_to_radians(xxx) ((xxx)*(M_PI/180.0))
 
 
+/*+ Node flags. +*/
+typedef uint16_t nodeflags_t;
+
 /*+ A distance, measured in metres. +*/
 typedef uint32_t distance_t;
 
@@ -196,24 +214,26 @@ typedef uint8_t highway_t;
 /*+ The different types of a highway. +*/
 typedef enum _Highway
  {
-  Way_Motorway    = 1,
-  Way_Trunk       = 2,
-  Way_Primary     = 3,
-  Way_Secondary   = 4,
-  Way_Tertiary    = 5,
-  Way_Unclassified= 6,
-  Way_Residential = 7,
-  Way_Service     = 8,
-  Way_Track       = 9,
-  Way_Cycleway    =10,
-  Way_Path        =11,
-  Way_Steps       =12,
-  Way_Ferry       =13,
-
-  Way_Count       =14,       /* One more than the number of highway types. */
-
-  Way_OneWay      =32,
-  Way_Roundabout  =64
+  Highway_None         =  0,
+
+  Highway_Motorway     =  1,
+  Highway_Trunk        =  2,
+  Highway_Primary      =  3,
+  Highway_Secondary    =  4,
+  Highway_Tertiary     =  5,
+  Highway_Unclassified =  6,
+  Highway_Residential  =  7,
+  Highway_Service      =  8,
+  Highway_Track        =  9,
+  Highway_Cycleway     = 10,
+  Highway_Path         = 11,
+  Highway_Steps        = 12,
+  Highway_Ferry        = 13,
+
+  Highway_Count        = 14,       /* One more than the number of highway types. */
+
+  Highway_OneWay       = 32,
+  Highway_Roundabout   = 64
  }
  Highway;
 
@@ -229,19 +249,19 @@ typedef enum _Highways
  {
   Highways_None         = 0,
 
-  Highways_Motorway     = HIGHWAYS(Way_Motorway    ),
-  Highways_Trunk        = HIGHWAYS(Way_Trunk       ),
-  Highways_Primary      = HIGHWAYS(Way_Primary     ),
-  Highways_Secondary    = HIGHWAYS(Way_Secondary   ),
-  Highways_Tertiary     = HIGHWAYS(Way_Tertiary    ),
-  Highways_Unclassified = HIGHWAYS(Way_Unclassified),
-  Highways_Residential  = HIGHWAYS(Way_Residential ),
-  Highways_Service      = HIGHWAYS(Way_Service     ),
-  Highways_Track        = HIGHWAYS(Way_Track       ),
-  Highways_Cycleway     = HIGHWAYS(Way_Cycleway    ),
-  Highways_Path         = HIGHWAYS(Way_Path        ),
-  Highways_Steps        = HIGHWAYS(Way_Steps       ),
-  Highways_Ferry        = HIGHWAYS(Way_Ferry       )
+  Highways_Motorway     = HIGHWAYS(Highway_Motorway    ),
+  Highways_Trunk        = HIGHWAYS(Highway_Trunk       ),
+  Highways_Primary      = HIGHWAYS(Highway_Primary     ),
+  Highways_Secondary    = HIGHWAYS(Highway_Secondary   ),
+  Highways_Tertiary     = HIGHWAYS(Highway_Tertiary    ),
+  Highways_Unclassified = HIGHWAYS(Highway_Unclassified),
+  Highways_Residential  = HIGHWAYS(Highway_Residential ),
+  Highways_Service      = HIGHWAYS(Highway_Service     ),
+  Highways_Track        = HIGHWAYS(Highway_Track       ),
+  Highways_Cycleway     = HIGHWAYS(Highway_Cycleway    ),
+  Highways_Path         = HIGHWAYS(Highway_Path        ),
+  Highways_Steps        = HIGHWAYS(Highway_Steps       ),
+  Highways_Ferry        = HIGHWAYS(Highway_Ferry       )
  }
  Highways;
 
diff --git a/src/typesx.h b/src/typesx.h
index fac3c06..b1b1204 100644
--- a/src/typesx.h
+++ b/src/typesx.h
@@ -33,13 +33,13 @@
 /* Constants and macros for handling them */
 
 /*+ An undefined node ID. +*/
-#define NO_NODE_ID     (~(node_t)0)
+#define NO_NODE_ID     ((node_t)~0)
 
 /*+ An undefined way ID. +*/
-#define NO_WAY_ID      (~(way_t)0)
+#define NO_WAY_ID      ((way_t)~0)
 
 /*+ An undefined relation ID. +*/
-#define NO_RELATION_ID (~(relation_t)0)
+#define NO_RELATION_ID ((relation_t)~0)
 
 /*+ The maximum number of segments per node (used to size temporary storage). +*/
 #define MAX_SEG_PER_NODE 32
@@ -49,14 +49,15 @@
 
 #define BitMask uint32_t
 
-#define AllocBitMask(xx)   (BitMask*)calloc((1+(xx)/32),sizeof(BitMask))
+#define AllocBitMask(xx)    (BitMask*)calloc((1+(xx)/32),sizeof(BitMask))
 
-#define SetAllBits0(xx,yy) memset((xx), 0,(1+(yy)/32)*sizeof(BitMask))
-#define SetAllBits1(xx,yy) memset((xx),~0,(1+(yy)/32)*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))
 
-#define ClearBit(xx,yy)    (xx)[(yy)/32]&=~(((BitMask)1)<<((yy)%32))
-#define SetBit(xx,yy)      (xx)[(yy)/32]|= (((BitMask)1)<<((yy)%32))
-#define IsBitSet(xx,yy)   ((xx)[(yy)/32]&  (((BitMask)1)<<((yy)%32)))
+#define ClearBit(xx,yy)     (xx)[(yy)/32]&=~(((BitMask)1)<<((yy)%32))
+#define SetBit(xx,yy)       (xx)[(yy)/32]|= (((BitMask)1)<<((yy)%32))
+
+#define IsBitSet(xx,yy)    ((xx)[(yy)/32]&  (((BitMask)1)<<((yy)%32)))
 
 
 /* Simple Types */
@@ -114,7 +115,7 @@ typedef struct _WaysX WaysX;
 
 typedef struct _RouteRelX RouteRelX;
 
-typedef struct _TurnRestrictRelX TurnRestrictRelX;
+typedef struct _TurnRelX TurnRelX;
 
 typedef struct _RelationsX RelationsX;
 
diff --git a/src/visualiser.c b/src/visualiser.c
index 4572eb0..0d1403c 100644
--- a/src/visualiser.c
+++ b/src/visualiser.c
@@ -61,7 +61,7 @@ static double LonMin;
 static double LonMax;
 
 static int limit_type=0;
-static Highway highways=Way_Count;
+static Highway highways=Highway_None;
 static Transports transports=Transports_None;
 
 /* Local functions */
@@ -130,26 +130,26 @@ void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relat
 static void output_junctions(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment;
- Way *firstway;
+ Segment *segmentp;
+ Way *firstwayp;
  int count=0,difference=0;
 
- segment=FirstSegment(OSMSegments,nodep,1);
- firstway=LookupWay(OSMWays,segment->way,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+ firstwayp=LookupWay(OSMWays,segmentp->way,1);
 
  do
    {
-    Way *way=LookupWay(OSMWays,segment->way,2);
+    Way *wayp=LookupWay(OSMWays,segmentp->way,2);
 
-    if(IsNormalSegment(segment))
+    if(IsNormalSegment(segmentp))
        count++;
 
-    if(WaysCompare(firstway,way))
+    if(WaysCompare(firstwayp,wayp))
        difference=1;
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 
  if(count!=2 || difference)
     printf("%.6f %.6f %d\n",radians_to_degrees(latitude),radians_to_degrees(longitude),count);
@@ -209,20 +209,20 @@ void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations
 static void output_super(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment;
+ Segment *segmentp;
 
  if(!IsSuperNode(nodep))
     return;
 
  printf("%.6f %.6f n\n",radians_to_degrees(latitude),radians_to_degrees(longitude));
 
- segment=FirstSegment(OSMSegments,nodep,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
 
  do
    {
-    if(IsSuperSegment(segment))
+    if(IsSuperSegment(segmentp))
       {
-       index_t othernode=OtherNode(segment,node);
+       index_t othernode=OtherNode(segmentp,node);
        double lat,lon;
 
        GetLatLong(OSMNodes,othernode,&lat,&lon);
@@ -231,9 +231,9 @@ static void output_super(index_t node,double latitude,double longitude)
           printf("%.6f %.6f s\n",radians_to_degrees(lat),radians_to_degrees(lon));
       }
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 }
 
 
@@ -290,15 +290,15 @@ void OutputOneway(Nodes *nodes,Segments *segments,Ways *ways,Relations *relation
 static void output_oneway(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment;
+ Segment *segmentp;
 
- segment=FirstSegment(OSMSegments,nodep,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
 
  do
    {
-    if(IsNormalSegment(segment))
+    if(IsNormalSegment(segmentp))
       {
-       index_t othernode=OtherNode(segment,node);
+       index_t othernode=OtherNode(segmentp,node);
 
        if(node>othernode)
          {
@@ -306,16 +306,16 @@ static void output_oneway(index_t node,double latitude,double longitude)
 
           GetLatLong(OSMNodes,othernode,&lat,&lon);
 
-          if(IsOnewayFrom(segment,node))
+          if(IsOnewayFrom(segmentp,node))
              printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
-          else if(IsOnewayFrom(segment,othernode))
+          else if(IsOnewayFrom(segmentp,othernode))
              printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(lat),radians_to_degrees(lon),radians_to_degrees(latitude),radians_to_degrees(longitude));
          }
       }
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 }
 
 
@@ -376,21 +376,21 @@ void OutputHighway(Nodes *nodes,Segments *segments,Ways *ways,Relations *relatio
 static void output_highway(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment;
+ Segment *segmentp;
 
- segment=FirstSegment(OSMSegments,nodep,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
 
  do
    {
-    if(IsNormalSegment(segment))
+    if(IsNormalSegment(segmentp))
       {
-       index_t othernode=OtherNode(segment,node);
+       index_t othernode=OtherNode(segmentp,node);
 
        if(node>othernode)
          {
-          Way *way=LookupWay(OSMWays,segment->way,1);
+          Way *wayp=LookupWay(OSMWays,segmentp->way,1);
 
-          if(HIGHWAY(way->type)==highways)
+          if(HIGHWAY(wayp->type)==highways)
             {
              double lat,lon;
 
@@ -401,9 +401,9 @@ static void output_highway(index_t node,double latitude,double longitude)
          }
       }
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 }
 
 
@@ -464,21 +464,21 @@ void OutputTransport(Nodes *nodes,Segments *segments,Ways *ways,Relations *relat
 static void output_transport(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment;
+ Segment *segmentp;
 
- segment=FirstSegment(OSMSegments,nodep,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
 
  do
    {
-    if(IsNormalSegment(segment))
+    if(IsNormalSegment(segmentp))
       {
-       index_t othernode=OtherNode(segment,node);
+       index_t othernode=OtherNode(segmentp,node);
 
        if(node>othernode)
          {
-          Way *way=LookupWay(OSMWays,segment->way,1);
+          Way *wayp=LookupWay(OSMWays,segmentp->way,1);
 
-          if(way->allow&transports)
+          if(wayp->allow&transports)
             {
              double lat,lon;
 
@@ -489,9 +489,9 @@ static void output_transport(index_t node,double latitude,double longitude)
          }
       }
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 }
 
 
@@ -621,17 +621,17 @@ static void output_turnrestriction(index_t node,double latitude,double longitude
  do
    {
     TurnRelation *relation;
-    Segment *from_segment,*to_segment;
+    Segment *from_segmentp,*to_segmentp;
     index_t from_node,to_node;
     double from_lat,from_lon,to_lat,to_lon;
 
     relation=LookupTurnRelation(OSMRelations,turnrelation,1);
 
-    from_segment=LookupSegment(OSMSegments,relation->from,1);
-    to_segment  =LookupSegment(OSMSegments,relation->to  ,2);
+    from_segmentp=LookupSegment(OSMSegments,relation->from,1);
+    to_segmentp  =LookupSegment(OSMSegments,relation->to  ,2);
 
-    from_node=OtherNode(from_segment,node);
-    to_node=OtherNode(to_segment,node);
+    from_node=OtherNode(from_segmentp,node);
+    to_node=OtherNode(to_segmentp,node);
 
     GetLatLong(OSMNodes,from_node,&from_lat,&from_lon);
     GetLatLong(OSMNodes,to_node,&to_lat,&to_lon);
@@ -869,37 +869,37 @@ void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *re
 static void output_limits(index_t node,double latitude,double longitude)
 {
  Node *nodep=LookupNode(OSMNodes,node,1);
- Segment *segment,segments[MAX_SEG_PER_NODE];
+ Segment *segmentp,segmentps[MAX_SEG_PER_NODE];
  int limits[MAX_SEG_PER_NODE];
  int count=0;
  int i,j,same=0;
 
- segment=FirstSegment(OSMSegments,nodep,1);
+ segmentp=FirstSegment(OSMSegments,nodep,1);
 
  do
    {
-    if(IsNormalSegment(segment) && count<MAX_SEG_PER_NODE)
+    if(IsNormalSegment(segmentp) && count<MAX_SEG_PER_NODE)
       {
-       Way *way=LookupWay(OSMWays,segment->way,1);
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
 
-       segments[count]=*segment;
+       segmentps[count]=*segmentp;
 
        switch(limit_type)
          {
-         case SPEED_LIMIT:  limits[count]=way->speed;  break;
-         case WEIGHT_LIMIT: limits[count]=way->weight; break;
-         case HEIGHT_LIMIT: limits[count]=way->height; break;
-         case WIDTH_LIMIT:  limits[count]=way->width;  break;
-         case LENGTH_LIMIT: limits[count]=way->length; break;
+         case SPEED_LIMIT:  limits[count]=wayp->speed;  break;
+         case WEIGHT_LIMIT: limits[count]=wayp->weight; break;
+         case HEIGHT_LIMIT: limits[count]=wayp->height; break;
+         case WIDTH_LIMIT:  limits[count]=wayp->width;  break;
+         case LENGTH_LIMIT: limits[count]=wayp->length; break;
          }
 
-       if(limits[count] || HIGHWAY(way->type)<Way_Track)
+       if(limits[count] || HIGHWAY(wayp->type)<Highway_Track)
           count++;
       }
 
-    segment=NextSegment(OSMSegments,segment,node);
+    segmentp=NextSegment(OSMSegments,segmentp,node);
    }
- while(segment);
+ while(segmentp);
 
  /* Nodes with only one limit are not interesting */
 
@@ -931,7 +931,7 @@ static void output_limits(index_t node,double latitude,double longitude)
       {
        double lat,lon;
 
-       GetLatLong(OSMNodes,OtherNode(&segments[i],node),&lat,&lon);
+       GetLatLong(OSMNodes,OtherNode(&segmentps[i],node),&lat,&lon);
 
        switch(limit_type)
          {
@@ -988,10 +988,10 @@ static void find_all_nodes(Nodes *nodes,callback_t callback)
 
        for(i=index1;i<index2;i++)
          {
-          Node *node=LookupNode(nodes,i,1);
+          Node *nodep=LookupNode(nodes,i,1);
 
-          double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
-          double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));
+          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));
 
           if(lat>LatMin && lat<LatMax && lon>LonMin && lon<LonMax)
              (*callback)(i,lat,lon);
diff --git a/src/ways.c b/src/ways.c
index 92aadb8..f911887 100644
--- a/src/ways.c
+++ b/src/ways.c
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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,39 +85,39 @@ Ways *LoadWayList(const char *filename)
 
   int WaysCompare Returns a comparison.
 
-  Way *way1 The first way.
+  Way *way1p The first way.
 
-  Way *way2 The second way.
+  Way *way2p The second way.
   ++++++++++++++++++++++++++++++++++++++*/
 
-int WaysCompare(Way *way1,Way *way2)
+int WaysCompare(Way *way1p,Way *way2p)
 {
- if(way1==way2)
+ if(way1p==way2p)
     return(0);
 
- if(way1->type!=way2->type)
-    return((int)way1->type - (int)way2->type);
+ if(way1p->type!=way2p->type)
+    return((int)way1p->type - (int)way2p->type);
 
- if(way1->allow!=way2->allow)
-    return((int)way1->allow - (int)way2->allow);
+ if(way1p->allow!=way2p->allow)
+    return((int)way1p->allow - (int)way2p->allow);
 
- if(way1->props!=way2->props)
-    return((int)way1->props - (int)way2->props);
+ if(way1p->props!=way2p->props)
+    return((int)way1p->props - (int)way2p->props);
 
- if(way1->speed!=way2->speed)
-    return((int)way1->speed - (int)way2->speed);
+ if(way1p->speed!=way2p->speed)
+    return((int)way1p->speed - (int)way2p->speed);
 
- if(way1->weight!=way2->weight)
-    return((int)way1->weight - (int)way2->weight);
+ if(way1p->weight!=way2p->weight)
+    return((int)way1p->weight - (int)way2p->weight);
 
- if(way1->height!=way2->height)
-    return((int)way1->height - (int)way2->height);
+ if(way1p->height!=way2p->height)
+    return((int)way1p->height - (int)way2p->height);
 
- if(way1->width!=way2->width)
-    return((int)way1->width - (int)way2->width);
+ if(way1p->width!=way2p->width)
+    return((int)way1p->width - (int)way2p->width);
 
- if(way1->length!=way2->length)
-    return((int)way1->length - (int)way2->length);
+ if(way1p->length!=way2p->length)
+    return((int)way1p->length - (int)way2p->length);
 
  return(0);
 }
diff --git a/src/ways.h b/src/ways.h
index 36fd44e..6650370 100644
--- a/src/ways.h
+++ b/src/ways.h
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2011 Andrew M. Bishop
+ This file Copyright 2008-2012 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,8 +57,7 @@ struct _Way
 /*+ A structure containing the header from the file. +*/
 typedef struct _WaysFile
 {
- index_t      number;           /*+ The number of ways stored. +*/
- index_t      onumber;          /*+ The number of ways originally. +*/
+ index_t      number;           /*+ The number of ways. +*/
 
  highways_t   highways;         /*+ The types of highways that were seen when parsing. +*/
  transports_t allow;            /*+ The types of traffic that were seen when parsing. +*/
@@ -97,7 +96,7 @@ struct _Ways
 
 Ways *LoadWayList(const char *filename);
 
-int WaysCompare(Way *way1,Way *way2);
+int WaysCompare(Way *way1p,Way *way2p);
 
 
 /* Macros and inline functions */
@@ -114,7 +113,7 @@ int WaysCompare(Way *way1,Way *way2);
 
 static Way *LookupWay(Ways *ways,index_t index,int position);
 
-static char *WayName(Ways *ways,Way *way);
+static char *WayName(Ways *ways,Way *wayp);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -149,16 +148,16 @@ static inline Way *LookupWay(Ways *ways,index_t index,int position)
 
   Ways *ways The set of ways to use.
 
-  Way *way The Way pointer.
+  Way *wayp The Way pointer.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static inline char *WayName(Ways *ways,Way *way)
+static inline char *WayName(Ways *ways,Way *wayp)
 {
- int position=way-&ways->cached[-1];
+ int position=wayp-&ways->cached[-1];
 
  int n=0;
 
- SeekFile(ways->fd,ways->namesoffset+way->name);
+ SeekFile(ways->fd,ways->namesoffset+wayp->name);
 
  if(!ways->ncached[position-1])
     ways->ncached[position-1]=(char*)malloc(32);
diff --git a/src/waysx.c b/src/waysx.c
index ace79f9..584cd19 100644
--- a/src/waysx.c
+++ b/src/waysx.c
@@ -20,7 +20,6 @@
  ***************************************/
 
 
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -28,6 +27,7 @@
 #include "ways.h"
 
 #include "typesx.h"
+#include "segmentsx.h"
 #include "waysx.h"
 
 #include "files.h"
@@ -40,20 +40,23 @@
 /*+ The command line '--tmpdir' option or its default value. +*/
 extern char *option_tmpdirname;
 
-
 /* Local variables */
 
-/*+ A temporary file-local variable for use by the sort functions. +*/
+/*+ Temporary file-local variables for use by the sort functions. +*/
 static WaysX *sortwaysx;
+static SegmentsX *sortsegmentsx;
 
-
-/* Functions */
+/* Local functions */
 
 static int sort_by_id(WayX *a,WayX *b);
-static int sort_by_name_and_id(WayX *a,WayX *b);
-static int sort_by_name_and_prop_and_id(WayX *a,WayX *b);
+static int deduplicate_by_id(WayX *wayx,index_t index);
 
-static int deduplicate_and_index_by_id(WayX *wayx,index_t index);
+static int sort_by_name(WayX *a,WayX *b);
+static int index_by_id(WayX *wayx,index_t index);
+
+static int delete_unused(WayX *wayx,index_t index);
+static int sort_by_name_and_prop_and_id(WayX *a,WayX *b);
+static int deduplicate_and_index_by_compact_id(WayX *wayx,index_t index);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -61,49 +64,61 @@ static int deduplicate_and_index_by_id(WayX *wayx,index_t index);
 
   WaysX *NewWayList Returns the way list.
 
-  int append Set to 1 if the file is to be opened for appending (now or later).
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
   ++++++++++++++++++++++++++++++++++++++*/
 
-WaysX *NewWayList(int append)
+WaysX *NewWayList(int append,int readonly)
 {
  WaysX *waysx;
 
  waysx=(WaysX*)calloc(1,sizeof(WaysX));
 
- assert(waysx); /* Check calloc() worked */
+ logassert(waysx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
 
- waysx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
+ waysx->filename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ waysx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- if(append)
-    sprintf(waysx->filename,"%s/waysx.input.tmp",option_tmpdirname);
- else
-    sprintf(waysx->filename,"%s/waysx.%p.tmp",option_tmpdirname,(void*)waysx);
+ sprintf(waysx->filename    ,"%s/waysx.parsed.mem",option_tmpdirname);
+ sprintf(waysx->filename_tmp,"%s/waysx.%p.tmp"    ,option_tmpdirname,(void*)waysx);
 
- if(append)
-   {
-    off_t size,position=0;
+ if(append || readonly)
+    if(ExistsFile(waysx->filename))
+      {
+       off_t size,position=0;
+       int fd;
 
-    waysx->fd=OpenFileAppend(waysx->filename);
+       size=SizeFile(waysx->filename);
 
-    size=SizeFile(waysx->filename);
+       fd=ReOpenFile(waysx->filename);
 
-    while(position<size)
-      {
-       FILESORT_VARINT waysize;
+       while(position<size)
+         {
+          FILESORT_VARINT waysize;
+
+          SeekReadFile(fd,&waysize,FILESORT_VARSIZE,position);
 
-       SeekReadFile(waysx->fd,&waysize,FILESORT_VARSIZE,position);
+          waysx->number++;
+          position+=waysize+FILESORT_VARSIZE;
+         }
 
-       waysx->number++;
-       position+=waysize+FILESORT_VARSIZE;
+       CloseFile(fd);
+
+       RenameFile(waysx->filename,waysx->filename_tmp);
       }
 
-    SeekFile(waysx->fd,size);
-   }
+ if(append)
+    waysx->fd=OpenFileAppend(waysx->filename_tmp);
+ else if(!readonly)
+    waysx->fd=OpenFileNew(waysx->filename_tmp);
  else
-    waysx->fd=OpenFileNew(waysx->filename);
+    waysx->fd=-1;
+
+
+ waysx->nfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
 
- waysx->nfilename=(char*)malloc(strlen(option_tmpdirname)+32);
- sprintf(waysx->nfilename,"%s/waynames.%p.tmp",option_tmpdirname,(void*)waysx);
+ sprintf(waysx->nfilename_tmp,"%s/waynames.%p.tmp",option_tmpdirname,(void*)waysx);
 
  return(waysx);
 }
@@ -114,22 +129,28 @@ WaysX *NewWayList(int append)
 
   WaysX *waysx The set of ways to be freed.
 
-  int keep Set to 1 if the file is to be kept (for appending later).
+  int keep If set then the results file is to be kept.
   ++++++++++++++++++++++++++++++++++++++*/
 
 void FreeWayList(WaysX *waysx,int keep)
 {
- if(!keep)
-    DeleteFile(waysx->filename);
+ if(keep)
+    RenameFile(waysx->filename_tmp,waysx->filename);
+ else
+    DeleteFile(waysx->filename_tmp);
 
  free(waysx->filename);
+ free(waysx->filename_tmp);
 
  if(waysx->idata)
     free(waysx->idata);
 
- DeleteFile(waysx->nfilename);
+ if(waysx->cdata)
+    free(waysx->cdata);
+
+ DeleteFile(waysx->nfilename_tmp);
 
- free(waysx->nfilename);
+ free(waysx->nfilename_tmp);
 
  free(waysx);
 }
@@ -147,13 +168,12 @@ void FreeWayList(WaysX *waysx,int keep)
   const char *name The name or reference of the way.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void AppendWay(WaysX *waysx,way_t id,Way *way,const char *name)
+void AppendWayList(WaysX *waysx,way_t id,Way *way,const char *name)
 {
  WayX wayx;
  FILESORT_VARINT size;
 
  wayx.id=id;
- wayx.prop=0;
  wayx.way=*way;
 
  size=sizeof(WayX)+strlen(name)+1;
@@ -164,7 +184,79 @@ void AppendWay(WaysX *waysx,way_t id,Way *way,const char *name)
 
  waysx->number++;
 
- assert(waysx->number!=0); /* Zero marks the high-water mark for ways. */
+ logassert(waysx->number!=0,"Too many ways (change index_t to 64-bits?)"); /* Zero marks the high-water mark for ways. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending ways and change the filename over.
+
+  WaysX *waysx The ways that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishWayList(WaysX *waysx)
+{
+ if(waysx->fd!=-1)
+    waysx->fd=CloseFile(waysx->fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular way index.
+
+  index_t IndexWayX Returns the index of the extended way with the specified id.
+
+  WaysX *waysx The set of ways to process.
+
+  way_t id The way id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexWayX(WaysX *waysx,way_t id)
+{
+ index_t start=0;
+ index_t end=waysx->number-1;
+ index_t mid;
+
+ if(waysx->number==0)           /* There are no ways */
+    return(NO_WAY);
+
+ if(id<waysx->idata[start])     /* Key is before start */
+    return(NO_WAY);
+
+ if(id>waysx->idata[end])       /* Key is after end */
+    return(NO_WAY);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;            /* Choose mid point */
+
+    if(waysx->idata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(waysx->idata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                          /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(waysx->idata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(waysx->idata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_WAY);
 }
 
 
@@ -176,7 +268,103 @@ void AppendWay(WaysX *waysx,way_t id,Way *way,const char *name)
 
 void SortWayList(WaysX *waysx)
 {
- index_t i,xnumber;
+ index_t xnumber;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Sorting Ways");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
+
+ DeleteFile(waysx->filename_tmp);
+
+ fd=OpenFileNew(waysx->filename_tmp);
+
+ /* Sort the ways by ID and index them */
+
+ xnumber=waysx->number;
+
+ waysx->number=filesort_vary(waysx->fd,fd,NULL,
+                                          (int (*)(const void*,const void*))sort_by_id,
+                                          (int (*)(void*,index_t))deduplicate_by_id);
+
+ /* Close the files */
+
+ waysx->fd=CloseFile(waysx->fd);
+ CloseFile(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Ways: Ways=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-waysx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the ways into id order.
+
+  int sort_by_id Returns the comparison of the id fields.
+
+  WayX *a The first extended way.
+
+  WayX *b The second extended way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_id(WayX *a,WayX *b)
+{
+ way_t a_id=a->id;
+ way_t b_id=b->id;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Discard duplicate ways.
+
+  int deduplicate_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  WayX *wayx The extended way.
+
+  index_t index The number of sorted ways that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_by_id(WayX *wayx,index_t index)
+{
+ static way_t previd=NO_WAY_ID;
+
+ if(wayx->id!=previd)
+   {
+    previd=wayx->id;
+
+    if(wayx->way.type==WAY_DELETED)
+       return(0);
+    else
+       return(1);
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Extract the way names from the ways and reference the list of names from the ways.
+
+  WaysX *waysx The set of ways to process.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ExtractWayNames(WaysX *waysx,int keep)
+{
+ index_t i;
  int fd;
  char *names[2]={NULL,NULL};
  int namelen[2]={0,0};
@@ -187,21 +375,22 @@ void SortWayList(WaysX *waysx)
 
  printf_first("Sorting Ways by Name");
 
- /* Close the file (finished appending) */
-
- waysx->fd=CloseFile(waysx->fd);
-
  /* Re-open the file read-only and a new file writeable */
 
- waysx->fd=ReOpenFile(waysx->filename);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 
- DeleteFile(waysx->filename);
+ if(keep)
+    RenameFile(waysx->filename_tmp,waysx->filename);
+ else
+    DeleteFile(waysx->filename_tmp);
 
- fd=OpenFileNew(waysx->filename);
+ fd=OpenFileNew(waysx->filename_tmp);
 
  /* Sort the ways to allow separating the names */
 
- filesort_vary(waysx->fd,fd,(int (*)(const void*,const void*))sort_by_name_and_id,NULL);
+ filesort_vary(waysx->fd,fd,NULL,
+                            (int (*)(const void*,const void*))sort_by_name,
+                            NULL);
 
  /* Close the files */
 
@@ -219,13 +408,13 @@ void SortWayList(WaysX *waysx)
 
  /* Re-open the file read-only and new files writeable */
 
- waysx->fd=ReOpenFile(waysx->filename);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 
- DeleteFile(waysx->filename);
+ DeleteFile(waysx->filename_tmp);
 
- fd=OpenFileNew(waysx->filename);
+ fd=OpenFileNew(waysx->filename_tmp);
 
- waysx->nfd=OpenFileNew(waysx->nfilename);
+ waysx->nfd=OpenFileNew(waysx->nfilename_tmp);
 
  /* Copy from the single file into two files */
 
@@ -272,7 +461,7 @@ void SortWayList(WaysX *waysx)
 
  /* Print the final message */
 
- printf_last("Separated Way Names: Ways=%"Pindex_t" Names=%"Pindex_t" ",waysx->number,nnames);
+ printf_last("Separated Way Names: Ways=%"Pindex_t" Names=%"Pindex_t,waysx->number,nnames);
 
 
  /* Print the start message */
@@ -281,26 +470,25 @@ void SortWayList(WaysX *waysx)
 
  /* Re-open the file read-only and a new file writeable */
 
- waysx->fd=ReOpenFile(waysx->filename);
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 
- DeleteFile(waysx->filename);
+ DeleteFile(waysx->filename_tmp);
 
- fd=OpenFileNew(waysx->filename);
+ fd=OpenFileNew(waysx->filename_tmp);
 
  /* Allocate the array of indexes */
 
  waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
 
- assert(waysx->idata); /* Check malloc() worked */
+ logassert(waysx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
- /* Sort the ways by index and index them */
-
- xnumber=waysx->number;
- waysx->number=0;
+ /* Sort the ways by ID */
 
  sortwaysx=waysx;
 
- waysx->number=filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))deduplicate_and_index_by_id);
+ filesort_fixed(waysx->fd,fd,sizeof(WayX),NULL,
+                                          (int (*)(const void*,const void*))sort_by_id,
+                                          (int (*)(void*,index_t))index_by_id);
 
  /* Close the files */
 
@@ -309,84 +497,95 @@ void SortWayList(WaysX *waysx)
 
  /* Print the final message */
 
- printf_last("Sorted Ways: Ways=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-waysx->number);
+ printf_last("Sorted Ways: Ways=%"Pindex_t,waysx->number);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Compact the list of ways.
+  Sort the ways into name order and then id order.
 
-  WaysX *waysx The set of ways to process.
+  int sort_by_name Returns the comparison of the name fields.
+
+  WayX *a The first extended Way.
+
+  WayX *b The second extended Way.
   ++++++++++++++++++++++++++++++++++++++*/
 
-void CompactWayList(WaysX *waysx)
+static int sort_by_name(WayX *a,WayX *b)
 {
- index_t i;
- int fd;
- Way lastway;
-
- /* Print the start message */
+ int compare;
+ char *a_name=(char*)a+sizeof(WayX);
+ char *b_name=(char*)b+sizeof(WayX);
 
- printf_first("Sorting Ways by Properties");
+ compare=strcmp(a_name,b_name);
 
- /* Re-open the file read-only and a new file writeable */
+ if(compare)
+    return(compare);
+ else
+    return(FILESORT_PRESERVE_ORDER(a,b));
+}
 
- waysx->fd=ReOpenFile(waysx->filename);
 
- DeleteFile(waysx->filename);
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index of identifiers.
 
- fd=OpenFileNew(waysx->filename);
+  int index_by_id Return 1 if the value is to be kept, otherwise 0.
 
- /* Sort the ways to allow compacting according to he properties */
+  WayX *wayx The extended way.
 
- filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_name_and_prop_and_id,NULL);
+  index_t index The number of sorted ways that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
 
- /* Close the files */
+static int index_by_id(WayX *wayx,index_t index)
+{
+ sortwaysx->idata[index]=wayx->id;
 
- waysx->fd=CloseFile(waysx->fd);
- CloseFile(fd);
+ return(1);
+}
 
- /* Print the final message */
 
- printf_last("Sorted Ways by Properties: Ways=%"Pindex_t,waysx->number);
+/*++++++++++++++++++++++++++++++++++++++
+  Compact the way list, removing duplicated ways and unused ways.
 
+  WaysX *waysx The set of ways to process.
 
- /* Print the start message */
+  SegmentsX *segmentsx The set of segments to check.
+  ++++++++++++++++++++++++++++++++++++++*/
 
- printf_first("Compacting Ways: Ways=0 Properties=0");
+void CompactWayList(WaysX *waysx,SegmentsX *segmentsx)
+{
+ int fd;
+ index_t cnumber;
 
- /* Re-open the file read-only and a new file writeable */
+ if(waysx->number==0)
+    return;
 
- waysx->fd=ReOpenFile(waysx->filename);
+ /* Print the start message */
 
- DeleteFile(waysx->filename);
+ printf_first("Sorting Ways and Compacting");
 
- fd=OpenFileNew(waysx->filename);
+ /* Allocate the array of indexes */
 
- /* Update the way as we go using the sorted index */
+ waysx->cdata=(index_t*)malloc(waysx->number*sizeof(index_t));
 
- waysx->cnumber=0;
+ logassert(waysx->cdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
 
- for(i=0;i<waysx->number;i++)
-   {
-    WayX wayx;
+ /* Re-open the file read-only and a new file writeable */
 
-    ReadFile(waysx->fd,&wayx,sizeof(WayX));
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
 
-    if(waysx->cnumber==0 || wayx.way.name!=lastway.name || WaysCompare(&lastway,&wayx.way))
-      {
-       lastway=wayx.way;
+ DeleteFile(waysx->filename_tmp);
 
-       waysx->cnumber++;
-      }
+ fd=OpenFileNew(waysx->filename_tmp);
 
-    wayx.prop=waysx->cnumber-1;
+ /* Sort the ways to allow compacting according to the properties */
 
-    WriteFile(fd,&wayx,sizeof(WayX));
+ sortwaysx=waysx;
+ sortsegmentsx=segmentsx;
 
-    if(!((i+1)%1000))
-       printf_middle("Compacting Ways: Ways=%"Pindex_t" Properties=%"Pindex_t,i+1,waysx->cnumber);
-   }
+ cnumber=filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(void*,index_t))delete_unused,
+                                                  (int (*)(const void*,const void*))sort_by_name_and_prop_and_id,
+                                                  (int (*)(void*,index_t))deduplicate_and_index_by_compact_id);
 
  /* Close the files */
 
@@ -395,82 +594,38 @@ void CompactWayList(WaysX *waysx)
 
  /* Print the final message */
 
- printf_last("Compacted Ways: Ways=%"Pindex_t" Properties=%"Pindex_t" ",waysx->number,waysx->cnumber);
-
-
- /* Print the start message */
-
- printf_first("Sorting Ways");
-
- /* Re-open the file read-only and a new file writeable */
-
- waysx->fd=ReOpenFile(waysx->filename);
-
- DeleteFile(waysx->filename);
-
- fd=OpenFileNew(waysx->filename);
-
- /* Sort the ways by index */
-
- filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,NULL);
-
- /* Close the files */
-
- waysx->fd=CloseFile(waysx->fd);
- CloseFile(fd);
+ printf_last("Sorted and Compacted Ways: Ways=%"Pindex_t" Unique=%"Pindex_t,waysx->number,cnumber);
+ waysx->number=cnumber;
 
- /* Print the final message */
-
- printf_last("Sorted Ways: Ways=%"Pindex_t,waysx->number);
+ free(segmentsx->usedway);
+ segmentsx->usedway=NULL;
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Sort the ways into id order.
+  Delete the ways that are no longer being used.
 
-  int sort_by_id Returns the comparison of the id fields.
+  int delete_unused Return 1 if the value is to be kept, otherwise 0.
 
-  WayX *a The first extended way.
+  WayX *wayx The extended way.
 
-  WayX *b The second extended way.
+  index_t index The number of unsorted ways that have been read from the input file.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int sort_by_id(WayX *a,WayX *b)
+static int delete_unused(WayX *wayx,index_t index)
 {
- way_t a_id=a->id;
- way_t b_id=b->id;
+ if(sortsegmentsx && !IsBitSet(sortsegmentsx->usedway,index))
+   {
+    sortwaysx->cdata[index]=NO_WAY;
 
- if(a_id<b_id)
-    return(-1);
- else if(a_id>b_id)
-    return(1);
- else
     return(0);
-}
-
-
-/*++++++++++++++++++++++++++++++++++++++
-  Sort the ways into name order and then id order.
-
-  int sort_by_name_and_id Returns the comparison of the name and id fields.
-
-  WayX *a The first extended Way.
-
-  WayX *b The second extended Way.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-static int sort_by_name_and_id(WayX *a,WayX *b)
-{
- int compare;
- char *a_name=(char*)a+sizeof(WayX);
- char *b_name=(char*)b+sizeof(WayX);
-
- compare=strcmp(a_name,b_name);
-
- if(compare)
-    return(compare);
+   }
+ else
+   {
+    wayx->id=index;
 
- return(sort_by_id(a,b));
+    return(1);
+   }
 }
 
 
@@ -505,30 +660,32 @@ static int sort_by_name_and_prop_and_id(WayX *a,WayX *b)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Create the index of identifiers and discard duplicate ways.
+  Create the index of compacted Way identifiers and ignore Ways with duplicated properties.
 
-  int deduplicate_and_index_by_id Return 1 if the value is to be kept, otherwise 0.
+  int deduplicate_and_index_by_compact_id Return 1 if the value is to be kept, otherwise 0.
 
   WayX *wayx The extended way.
 
-  index_t index The index of this way in the total.
+  index_t index The number of sorted ways that have already been written to the output file.
   ++++++++++++++++++++++++++++++++++++++*/
 
-static int deduplicate_and_index_by_id(WayX *wayx,index_t index)
+static int deduplicate_and_index_by_compact_id(WayX *wayx,index_t index)
 {
- static way_t previd;
+ static Way lastway;
 
- if(index==0 || wayx->id!=previd)
+ if(index==0 || wayx->way.name!=lastway.name || WaysCompare(&lastway,&wayx->way))
    {
-    previd=wayx->id;
+    lastway=wayx->way;
+
+    sortwaysx->cdata[wayx->id]=index;
 
-    sortwaysx->idata[index]=wayx->id;
+    wayx->id=index;
 
     return(1);
    }
  else
    {
-    logerror("Way %"Pway_t" is duplicated.\n",wayx->id);
+    sortwaysx->cdata[wayx->id]=index-1;
 
     return(0);
    }
@@ -536,65 +693,6 @@ static int deduplicate_and_index_by_id(WayX *wayx,index_t index)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Find a particular way index.
-
-  index_t IndexWayX Returns the index of the extended way with the specified id.
-
-  WaysX *waysx The set of ways to process.
-
-  way_t id The way id to look for.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-index_t IndexWayX(WaysX *waysx,way_t id)
-{
- index_t start=0;
- index_t end=waysx->number-1;
- index_t mid;
-
- /* Binary search - search key exact match only is required.
-  *
-  *  # <- start  |  Check mid and move start or end if it doesn't match
-  *  #           |
-  *  #           |  Since an exact match is wanted we can set end=mid-1
-  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
-  *  #           |
-  *  #           |  Eventually either end=start or end=start+1 and one of
-  *  # <- end    |  start or end is the wanted one.
-  */
-
- if(end<start)                   /* There are no ways */
-    return(NO_WAY);
- else if(id<waysx->idata[start]) /* Check key is not before start */
-    return(NO_WAY);
- else if(id>waysx->idata[end])   /* Check key is not after end */
-    return(NO_WAY);
- else
-   {
-    do
-      {
-       mid=(start+end)/2;            /* Choose mid point */
-
-       if(waysx->idata[mid]<id)      /* Mid point is too low */
-          start=mid+1;
-       else if(waysx->idata[mid]>id) /* Mid point is too high */
-          end=mid?(mid-1):mid;
-       else                          /* Mid point is correct */
-          return(mid);
-      }
-    while((end-start)>1);
-
-    if(waysx->idata[start]==id)      /* Start is correct */
-       return(start);
-
-    if(waysx->idata[end]==id)        /* End is correct */
-       return(end);
-   }
-
- return(NO_WAY);
-}
-
-
-/*++++++++++++++++++++++++++++++++++++++
   Save the way list to a file.
 
   WaysX *waysx The set of ways to save.
@@ -607,6 +705,7 @@ void SaveWayList(WaysX *waysx,const char *filename)
  index_t i;
  int fd;
  int position=0;
+ WayX wayx;
  WaysFile waysfile={0};
  highways_t   highways=0;
  transports_t allow=0;
@@ -616,13 +715,10 @@ void SaveWayList(WaysX *waysx,const char *filename)
 
  printf_first("Writing Ways: Ways=0");
 
- /* Map into memory /  open the file */
+ /* Re-open the files */
 
-#if !SLIM
- waysx->data=MapFile(waysx->filename);
-#else
- waysx->fd=ReOpenFile(waysx->filename);
-#endif
+ waysx->fd=ReOpenFile(waysx->filename_tmp);
+ waysx->nfd=ReOpenFile(waysx->nfilename_tmp);
 
  /* Write out the ways data */
 
@@ -632,31 +728,21 @@ void SaveWayList(WaysX *waysx,const char *filename)
 
  for(i=0;i<waysx->number;i++)
    {
-    WayX *wayx=LookupWayX(waysx,i,1);
+    ReadFile(waysx->fd,&wayx,sizeof(WayX));
 
-    highways|=HIGHWAYS(wayx->way.type);
-    allow   |=wayx->way.allow;
-    props   |=wayx->way.props;
+    highways|=HIGHWAYS(wayx.way.type);
+    allow   |=wayx.way.allow;
+    props   |=wayx.way.props;
 
-    SeekWriteFile(fd,&wayx->way,sizeof(Way),sizeof(WaysFile)+(off_t)wayx->prop*sizeof(Way));
+    WriteFile(fd,&wayx.way,sizeof(Way));
 
     if(!((i+1)%1000))
        printf_middle("Writing Ways: Ways=%"Pindex_t,i+1);
    }
 
- /* Unmap from memory / close the file */
-
-#if !SLIM
- waysx->data=UnmapFile(waysx->filename);
-#else
- waysx->fd=CloseFile(waysx->fd);
-#endif
-
  /* Write out the ways names */
 
- SeekFile(fd,sizeof(WaysFile)+(off_t)waysx->cnumber*sizeof(Way));
-
- waysx->nfd=ReOpenFile(waysx->nfilename);
+ SeekFile(fd,sizeof(WaysFile)+(off_t)waysx->number*sizeof(Way));
 
  while(position<waysx->nlength)
    {
@@ -667,19 +753,20 @@ void SaveWayList(WaysX *waysx,const char *filename)
        len=waysx->nlength-position;
 
     ReadFile(waysx->nfd,temp,len);
+
     WriteFile(fd,temp,len);
 
     position+=len;
    }
 
- /* Close the file */
+ /* Close the files */
 
+ waysx->fd=CloseFile(waysx->fd);
  waysx->nfd=CloseFile(waysx->nfd);
 
  /* Write out the header structure */
 
- waysfile.number =waysx->cnumber;
- waysfile.onumber=waysx->number;
+ waysfile.number =waysx->number;
 
  waysfile.highways=highways;
  waysfile.allow   =allow;
diff --git a/src/waysx.h b/src/waysx.h
index 934c8c4..f4ed51a 100644
--- a/src/waysx.h
+++ b/src/waysx.h
@@ -39,19 +39,19 @@
 /*+ An extended structure containing a single way. +*/
 struct _WayX
 {
- way_t    id;                   /*+ The way identifier; the OSM value. +*/
+ way_t    id;                   /*+ The way identifier; initially the OSM value, later the Way index. +*/
 
- index_t  prop;                 /*+ The index of the properties of the way in the compacted list. +*/
-
- Way      way;                  /*+ The real Way data. +*/
+ Way      way;                  /*+ The real way data. +*/
 };
 
 
 /*+ A structure containing a set of ways (memory format). +*/
 struct _WaysX
 {
- char    *filename;             /*+ The name of the temporary file (for the WaysX). +*/
- int      fd;                   /*+ The file descriptor of the temporary file (for the WaysX). +*/
+ char    *filename;             /*+ The name of the intermediate file (for the WaysX). +*/
+ char    *filename_tmp;         /*+ The name of the temporary file (for the WaysX). +*/
+
+ int      fd;                   /*+ The file descriptor of the open file (for the WaysX). +*/
 
  index_t  number;               /*+ The number of extended ways still being considered. +*/
 
@@ -66,12 +66,13 @@ struct _WaysX
 
 #endif
 
- index_t  cnumber;              /*+ The number of entries after compacting. +*/
-
  way_t   *idata;                /*+ The extended way IDs (sorted by ID). +*/
 
- char    *nfilename;            /*+ The name of the temporary file (for the names). +*/
- int      nfd;                  /*+ The file descriptor of the temporary file (for the names). +*/
+ index_t *cdata;                /*+ The compacted way IDs (same order as sorted ways). +*/
+
+ char    *nfilename_tmp;        /*+ The name of the temporary file (for the WaysX names). +*/
+
+ int      nfd;                  /*+ The file descriptor of the temporary file (for the WaysX names). +*/
 
  uint32_t nlength;              /*+ The length of the string of name entries. +*/
 };
@@ -80,18 +81,21 @@ struct _WaysX
 /* Functions in waysx.c */
 
 
-WaysX *NewWayList(int append);
+WaysX *NewWayList(int append,int readonly);
 void FreeWayList(WaysX *waysx,int keep);
 
-void SaveWayList(WaysX *waysx,const char *filename);
+void AppendWayList(WaysX *waysx,way_t id,Way *way,const char *name);
+void FinishWayList(WaysX *waysx);
 
 index_t IndexWayX(WaysX *waysx,way_t id);
 
-void AppendWay(WaysX *waysx,way_t id,Way *way,const char *name);
-
 void SortWayList(WaysX *waysx);
 
-void CompactWayList(WaysX *waysx);
+void ExtractWayNames(WaysX *waysx,int keep);
+
+void CompactWayList(WaysX *waysx,SegmentsX *segmentsx);
+
+void SaveWayList(WaysX *waysx,const char *filename);
 
 
 /* Macros / inline functions */
diff --git a/src/xml/test/bad-cdata-start.xml b/src/xml/test/bad-text-outside.xml
similarity index 75%
rename from src/xml/test/bad-cdata-start.xml
rename to src/xml/test/bad-text-outside.xml
index cd9c4ed..8af1f35 100644
--- a/src/xml/test/bad-cdata-start.xml
+++ b/src/xml/test/bad-text-outside.xml
@@ -4,9 +4,9 @@
 
 <test>
 
-  <level1>
+  <level1 attr1="value1">
     <level2>
-      <![[CDATA <level1> ]]>
+      text
     </level2>
   </level1>
 
diff --git a/src/xml/test/good.xml b/src/xml/test/good.xml
index f7e207c..8c5bb2d 100644
--- a/src/xml/test/good.xml
+++ b/src/xml/test/good.xml
@@ -6,7 +6,6 @@
 
   <level1 attr1="value1 & value2 <  ">
     <level2>
-      <![CDATA[ <angle brackets> ]]>
     </level2>
   </level1>
 
diff --git a/src/xmlparse.l b/src/xmlparse.l
index e732b4d..4bed772 100644
--- a/src/xmlparse.l
+++ b/src/xmlparse.l
@@ -58,6 +58,7 @@
 #define LEX_ERROR_ATTR_VAL       109
 #define LEX_ERROR_ENTITY_REF     110
 #define LEX_ERROR_CHAR_REF       111
+#define LEX_ERROR_TEXT_OUTSIDE   112
 
 #define LEX_ERROR_UNEXP_TAG      201
 #define LEX_ERROR_UNBALANCED     202
@@ -133,6 +134,8 @@ static unsigned long long lineno;
 %option noyymore
 %option noyylineno
 
+%option ansi-definitions
+%option ansi-prototypes
 
  /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII tags not Unicode. */
 
@@ -151,8 +154,28 @@ U4c             \xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]
 U4              {U4a}|{U4b}|{U4c}
 
 U               ({U1}|{U2}|{U3}|{U4})
-UquotedS        ([\x09\x0A\x0D\x20-\x25\x28-\x3B\x3D\x3F-\x7F]|{U2}|{U3}|{U4})
-UquotedD        ([\x09\x0A\x0D\x20-\x21\x23-\x25\x27-\x3B\x3D\x3F-\x7F]|{U2}|{U3}|{U4})
+
+U2_bup          [\xC2-\xDF].
+U3a_bup         \xE0.{1,2}
+U3b_bup         [\xE1-\xEC].{1,2}
+U3c_bup         \xED.{1,2}
+U3d_bup         [\xEE-\xEF].{1,2}
+U3_bup          {U3a_bup}|{U3b_bup}|{U3c_bup}|{U3d_bup}
+U4a_bup         \xF0.{1,3}
+U4b_bup         [\xF1-\xF3].{1,3}
+U4c_bup         \xF4.{1,3}
+U4_bup          {U4a_bup}|{U4b_bup}|{U4c_bup}
+
+U1_xml          ([\x09\x0A\x0D\x20-\x25\x27-\x3B\x3D\x3F-\x7F])
+
+U1quotedS_xml   ([\x09\x0A\x0D\x20-\x25\x28-\x3B\x3D\x3F-\x7F])
+U1quotedD_xml   ([\x09\x0A\x0D\x20-\x21\x23-\x25\x27-\x3B\x3D\x3F-\x7F])
+
+UquotedS        ({U1quotedS_xml}|{U2}|{U3}|{U4})
+UquotedD        ({U1quotedD_xml}|{U2}|{U3}|{U4})
+
+UquotedS_bup    ({U2_bup}|{U3_bup}|{U4_bup})
+UquotedD_bup    ({U2_bup}|{U3_bup}|{U4_bup})
 
 N               (\n|\r\n)
 
@@ -161,16 +184,18 @@ digit           [0-9]
 xdigit          [a-fA-F0-9]
 
 namechar        ({letter}|{digit}|[-._:])
-name            (({letter}|[_:]){namechar}*)
+namestart       ({letter}|[_:])
+name            ({namestart}{namechar}*)
 
 entityref       (&{name};)
 charref         (&#({digit}+|x{xdigit}+);)
 
+entityref_bup   (&{namestart}{namechar}*[^-.0-9:;A-Z_a-z]*)
+charref_bup     (&#({digit}*[^0-9;]*|x{xdigit}*[^a-fA-F0-9;]*))
+
 
 %x BANGTAG
 %x COMMENT
-%x CDATA
-%x DOCTYPE
 %x XML_DECL_START XML_DECL
 %x TAG_START TAG
 %x ATTR_KEY ATTR_VAL
@@ -184,7 +209,6 @@ charref         (&#({digit}+|x{xdigit}+);)
  static unsigned long *stringlen=NULL,*stringused=NULL;
  static int after_attr=0;
  int newlen;
- int doctype_depth=0;
 
  /* Handle top level entities */
 
@@ -196,13 +220,12 @@ charref         (&#({digit}+|x{xdigit}+);)
 ">"                         { return(LEX_ERROR_CLOSE); }
 
 {N}                         { lineno++; }
-[^<>]                       { }
+{S}+                        { }
+.                           { yylval=yytext; return(LEX_ERROR_TEXT_OUTSIDE); }
 
  /* Tags beginning with '!' */
 
 <BANGTAG>"--"               { BEGIN(COMMENT); }
-<BANGTAG>"[CDATA["          { BEGIN(CDATA); }
-<BANGTAG>"DOCTYPE"          { BEGIN(DOCTYPE); doctype_depth=0; }
 <BANGTAG>{N}                { /* lineno++; */ return(LEX_ERROR_TAG_START); }
 <BANGTAG>.                  { return(LEX_ERROR_TAG_START); }
 
@@ -210,27 +233,15 @@ charref         (&#({digit}+|x{xdigit}+);)
 
 <COMMENT>"-->"              { BEGIN(INITIAL); }
 <COMMENT>"--"[^>]           { return(LEX_ERROR_COMMENT); }
-<COMMENT>{N}                { lineno++; }
-<COMMENT>[^-]               { }
+<COMMENT>"-".               { /* avoid backing up */ }
 <COMMENT>"-"                { }
-
- /* CDATA */
-
-<CDATA>"]]>"                { BEGIN(INITIAL); }
-<CDATA>"]"                  { }
-<CDATA>{N}                  { lineno++; }
-<CDATA>[^]]                 { }
-
- /* DOCTYPE */
-
-<DOCTYPE>"<"                { doctype_depth++; }
-<DOCTYPE>">"                { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; }
-<DOCTYPE>{N}                { lineno++; }
-<DOCTYPE>[^<>]              { }
+<COMMENT>{N}                { lineno++; }
+<COMMENT>[^-\n]+            { }
 
  /* XML declaration start */
 
 <XML_DECL_START>xml         { BEGIN(XML_DECL); reset_string; yylval=yytext; return(LEX_XML_DECL_BEGIN); }
+<XML_DECL_START>x.{1,2}     { return(LEX_ERROR_XML_DECL_START); /* avoid backing up */ }
 <XML_DECL_START>{N}         { /* lineno++; */ return(LEX_ERROR_XML_DECL_START); }
 <XML_DECL_START>.           { return(LEX_ERROR_XML_DECL_START); }
 
@@ -283,19 +294,27 @@ charref         (&#({digit}+|x{xdigit}+);)
 <DQUOTED>\"                 { BEGIN(after_attr); yylval=string[stringnum]; return(LEX_ATTR_VAL); }
 <DQUOTED>{entityref}        { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
                               else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
+<DQUOTED>{entityref_bup}    { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
 <DQUOTED>{charref}          { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
                               else { const char *str=ParseXML_Decode_Char_Ref(yytext);   if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
+<DQUOTED>{charref_bup}      { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
+<DQUOTED>{U1quotedD_xml}+   { append_string(yytext); /* optimise after avoiding backing up */ }
+<DQUOTED>{UquotedD}         { append_string(yytext); }
+<DQUOTED>{UquotedD_bup}     { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
 <DQUOTED>[<>&]              { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
-<DQUOTED>{UquotedD}+        { append_string(yytext); }
 <DQUOTED>.                  { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
 
 <SQUOTED>\'                 { BEGIN(after_attr); yylval=string[stringnum]; return(LEX_ATTR_VAL); }
 <SQUOTED>{entityref}        { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
                               else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
+<SQUOTED>{entityref_bup}    { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
 <SQUOTED>{charref}          { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
                               else { const char *str=ParseXML_Decode_Char_Ref(yytext);   if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
+<SQUOTED>{charref_bup}      { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
+<SQUOTED>{U1quotedS_xml}+   { append_string(yytext); /* optimise after avoiding backing up */ }
+<SQUOTED>{UquotedS}         { append_string(yytext); }
+<SQUOTED>{UquotedS_bup}     { yylval=yytext; return(LEX_ERROR_ATTR_VAL); /* avoid backing up */ }
 <SQUOTED>[<>&]              { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
-<SQUOTED>{UquotedS}+        { append_string(yytext); }
 <SQUOTED>.                  { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
 
  /* End of file */
@@ -601,6 +620,10 @@ int ParseXML(FILE *file,xmltag **tags,int options)
       case LEX_ERROR_CHAR_REF:
        fprintf(stderr,"XML Parser: Error on line %llu: invalid character reference '%s' seen in attribute value.\n",lineno,yylval);
        break;
+
+      case LEX_ERROR_TEXT_OUTSIDE:
+       fprintf(stderr,"XML Parser: Error on line %llu: non-whitespace '%s' seen outside tag.\n",lineno,yylval);
+       break;
       }
    }
  while(yychar>LEX_EOF && yychar<LEX_ERROR);
diff --git a/web/bin/summarise-log.pl b/web/bin/summarise-log.pl
index b526cf5..9fe0c1b 100755
--- a/web/bin/summarise-log.pl
+++ b/web/bin/summarise-log.pl
@@ -1,14 +1,19 @@
 #!/usr/bin/perl
 
-die "Usage: $0 [-v] < <error-log-file>\n" if($#ARGV>0);
-
 $verbose=0;
 $verbose=1 if($#ARGV==0 && $ARGV[0] eq "-v");
 
+$html=0;
+$html=1 if($#ARGV==0 && $ARGV[0] eq "-html");
+
+die "Usage: $0 [-v | -html] < <error-log-file>\n" if($#ARGV>0 || ($#ARGV==0 && !$verbose && !$html));
+
+
 # Read in each line from the error log and store them
 
 %errors=();
 %errorids=();
+%errortypes=();
 
 while(<STDIN>)
   {
@@ -16,38 +21,74 @@ while(<STDIN>)
 
    undef $errorid;
 
-   if(m%Node ([0-9]+)%)           # Generic node
+   if(m%nodes ([0-9]+) and ([0-9]+) in way ([0-9]+)%i) # Special case pair of nodes and a way
      {
-      $errorid=$1;
-      s%Node [0-9]+%Node <node-id>%g;
+      $errorid="($1 $2 $3)";
+      $errortype="N2W";
+      s%nodes [0-9]+ and [0-9]+ in way [0-9]+%nodes <node-id1> and <node-id2> in way <way-id>%;
+     }
+
+   elsif(m%nodes ([0-9]+) and ([0-9]+)%i) # Special case pair of nodes
+     {
+      $errorid="($1 $2)";
+      $errortype="N2";
+      s%nodes [0-9]+ and [0-9]+%nodes <node-id1> and <node-id2>%;
      }
 
-   if(m%Way ([0-9]+)%)            # Generic way
+   elsif(m%Segment connects node ([0-9]+)%) # Special case segment
      {
       $errorid=$1;
-      s%Way [0-9]+%Way <way-id>%g;
+      $errortype="N";
+      s%node [0-9]+%node <node-id>%;
+     }
+
+   elsif(m%Relation ([0-9]+).* contains Node ([0-9]+)%) # Special case relation/node
+     {
+      $errorid="($1 $2)";
+      $errortype="RN";
+      s%Relation [0-9]+%Relation <relation-id>%;
+      s%Node [0-9]+%node <node-id>%;
      }
 
-   if(m%Relation ([0-9]+)%)       # Generic relation
+   elsif(m%Relation ([0-9]+).* contains Way ([0-9]+)%) # Generic case relation/way
+     {
+      $errorid="($1 $2)";
+      $errortype="RW";
+      s%Relation [0-9]+%Relation <relation-id>%;
+      s%Way [0-9]+%way <way-id>%;
+     }
+
+   elsif(!m%Way ([0-9]+)% && !m%Relation ([0-9]+)% && m%Node ([0-9]+)%) # Generic node
      {
       $errorid=$1;
-      s%Relation [0-9]+%Relation <relation-id>%g;
+      $errortype="N";
+      s%Node [0-9]+%Node <node-id>%;
      }
 
-   if(m%Nodes [0-9]+ and [0-9]+%i) # Special case nodes
+   elsif(!m%Node ([0-9]+)% && !m%Relation ([0-9]+)% && m%Way ([0-9]+)%) # Generic way
      {
-      s%Nodes [0-9]+ and [0-9]+%Nodes <node-id1> and <node-id2>%gi;
+      $errorid=$1;
+      $errortype="W";
+      s%Way [0-9]+%Way <way-id>%;
      }
 
-   if(m%Segment connects node ([0-9]+)%) # Special case segment
+   elsif(!m%Node ([0-9]+)% && !m%Way ([0-9]+)% && m%Relation ([0-9]+)%) # Generic relation
      {
       $errorid=$1;
-      s%node [0-9]+%node <node-id>%g;
+      $errortype="R";
+      s%Relation [0-9]+%Relation <relation-id>%;
+     }
+
+   else
+     {
+      $errorid="ERROR";
+      $errortype="E";
+      warn "Unrecognised error message '$_'\n";
      }
 
    $errors{$_}++;
 
-   if($verbose && defined $errorid)
+   if($verbose || $html)
      {
       if(defined $errorids{$_})
         {
@@ -58,16 +99,153 @@ while(<STDIN>)
          $errorids{$_}="$errorid";
         }
      }
+
+   if($html)
+     {
+      $errortypes{$_}=$errortype;
+     }
   }
 
-# Print out the results
 
-foreach $error (sort { $errors{$b} <=> $errors{$a} } (keys %errors))
+# Print out the results as text
+
+if( ! $html )
   {
-   printf "%9d : $error\n",$errors{$error};
 
-   if($verbose && defined $errorids{$error})
+   foreach $error (sort { if ( $errors{$b} == $errors{$a} ) { return $errorids{$a} cmp $errorids{$b} }
+                          else                              { return $errors{$b}   <=> $errors{$a}   } } (keys %errors))
      {
-      print "            $errorids{$error}\n";
+      printf "%9d : $error\n",$errors{$error};
+
+      if($verbose && defined $errorids{$error})
+        {
+         print "            $errorids{$error}\n";
+        }
      }
+
   }
+
+# Print out the results as HTML
+
+else
+  {
+
+   print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n".
+         "<HTML>\n".
+         "\n".
+         "<HEAD>\n".
+         "<TITLE>Routino Error Log File Summary</TITLE>\n".
+         "<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n".
+         "<STYLE type=\"text/css\">\n".
+         "<!--\n".
+         "   body {font-family: sans-serif; font-size: 12px;}\n".
+         "   h1   {font-family: sans-serif; font-size: 14px; font-style: bold;}\n".
+         "   h2   {font-family: sans-serif; font-size: 13px; font-style: bold;}\n".
+         "   h3   {font-family: sans-serif; font-size: 12px; font-style: bold;}\n".
+         "-->\n".
+         "</STYLE>\n".
+         "</HEAD>\n".
+         "\n".
+         "<BODY>\n".
+         "\n".
+         "<h1>Routino Error Log File Summary</h1>\n".
+         "\n".
+         "This HTML file contains a summary of the Routino OSM parser error log file with\n".
+         "links to the OSM website that allow browsing each of the nodes, ways or relations\n".
+         "that are responsible for the error messages.\n".
+         "\n";
+
+   %errortypeorder=(
+                    "N"   , 1,
+                    "N2W" , 2,
+                    "N2"  , 3,
+                    "W"   , 4,
+                    "R"   , 5,
+                    "RN"  , 6,
+                    "RW"  , 7,
+                    "E"   , 8
+                   );
+
+   %errortypelabel=(
+                    "N"   , "Nodes",
+                    "N2W" , "Node Pairs in a Way",
+                    "N2"  , "Node Pairs",
+                    "W"   , "Ways",
+                    "R"   , "Relations",
+                    "RN"  , "Relations/Nodes",
+                    "RW"  , "Relations/Ways",
+                    "E"   , "ERROR"
+                   );
+
+   $lasterrortype="";
+
+   foreach $error (sort { if    ( $errortypes{$b} ne $errortypes{$a} ) { return $errortypeorder{$errortypes{$a}} <=> $errortypeorder{$errortypes{$b}} }
+                          elsif ( $errors{$b}     == $errors{$a} )     { return $errorids{$a} cmp $errorids{$b} }
+                          else                                         { return $errors{$b}   <=> $errors{$a}   } } (keys %errors))
+     {
+      $errorhtml=$error;
+
+      $errorhtml =~ s/&/&/g;
+      $errorhtml =~ s/</</g;
+      $errorhtml =~ s/>/>/g;
+
+      if($errortypes{$error} ne $lasterrortype)
+        {
+         print "<h2>$errortypelabel{$errortypes{$error}}</h2>\n";
+         $lasterrortype=$errortypes{$error};
+        }
+
+      print "<h3>$errorhtml</h3>\n";
+
+      if($errors{$error}>100)
+        {
+         print "$errors{$error} occurences (not listed).\n";
+        }
+      else
+        {
+         @ids=split(",",$errorids{$error});
+
+         $first=1;
+
+         foreach $id (@ids)
+           {
+            if($first)
+              {
+               print "$errortypelabel{$errortypes{$error}}:\n";
+              }
+            else
+              {
+               print ",";
+              }
+
+            $first=0;
+
+            print "<a href=\"http://www.openstreetmap.org/browse/node/$id\">$id</a>" if($errortypes{$error} eq "N");
+            print "<a href=\"http://www.openstreetmap.org/browse/way/$id\">$id</a>" if($errortypes{$error} eq "W");
+            print "<a href=\"http://www.openstreetmap.org/browse/relation/$id\">$id</a>" if($errortypes{$error} eq "R");
+
+            if($errortypes{$error} eq "N2" || $errortypes{$error} eq "RN" || $errortypes{$error} eq "RW")
+              {
+               $id =~ m%\(([0-9]+) ([0-9]+)\)%;
+               print "(<a href=\"http://www.openstreetmap.org/browse/node/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a>)" if($errortypes{$error} eq "N2");
+               print "(<a href=\"http://www.openstreetmap.org/browse/relation/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a>)" if($errortypes{$error} eq "RN");
+               print "(<a href=\"http://www.openstreetmap.org/browse/relation/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/way/$2\">$2</a>)" if($errortypes{$error} eq "RW");
+              }
+
+            if($errortypes{$error} eq "N2W")
+              {
+               $id =~ m%\(([0-9]+) ([0-9]+) ([0-9]+)\)%;
+               print "(<a href=\"http://www.openstreetmap.org/browse/node/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a> <a href=\"http://www.openstreetmap.org/browse/way/$3\">$3</a>)" if($errortypes{$error} eq "N2W");
+              }
+
+            print "\n";
+           }
+        }
+     }
+
+   print "\n".
+         "</BODY>\n".
+         "\n".
+         "</HTML>\n";
+
+}
diff --git a/web/www/routino/customrouter.cgi b/web/www/routino/customrouter.cgi
deleted file mode 100755
index 1748b37..0000000
--- a/web/www/routino/customrouter.cgi
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/perl
-#
-# Routino router custom link CGI
-#
-# Part of the Routino routing software.
-#
-# This file Copyright 2008-2012 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
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-# Use the perl CGI module
-use CGI ':cgi';
-
-# Create the query and get the parameters
-
-$query=new CGI;
-
-# Redirect to the HTML page.
-
-$params="";
-
-foreach $key ($query->param)
-  {
-   if($params eq "")
-     {
-      $params="?";
-     }
-   else
-     {
-      $params.="&";
-     }
-
-   $params.="$key=".$query->param($key);
-  }
-
-print $query->redirect("router.html".$params);
diff --git a/web/www/routino/customvisualiser.cgi b/web/www/routino/customvisualiser.cgi
deleted file mode 100755
index 581f40b..0000000
--- a/web/www/routino/customvisualiser.cgi
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/perl
-#
-# Routino data visualiser custom link CGI
-#
-# Part of the Routino routing software.
-#
-# This file Copyright 2008-2012 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
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-# Use the perl CGI module
-use CGI ':cgi';
-
-# Create the query and get the parameters
-
-$query=new CGI;
-
-# Redirect to the HTML page.
-
-$params="";
-
-foreach $key ($query->param)
-  {
-   if($params eq "")
-     {
-      $params="?";
-     }
-   else
-     {
-      $params.="&";
-     }
-
-   $params.="$key=".$query->param($key);
-  }
-
-print $query->redirect("visualiser.html".$params);
diff --git a/web/www/routino/noscript.cgi b/web/www/routino/noscript.cgi
deleted file mode 100755
index d838bad..0000000
--- a/web/www/routino/noscript.cgi
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/perl
-#
-# Routino non-Javascript router CGI
-#
-# Part of the Routino routing software.
-#
-# This file Copyright 2008-2011 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
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-# Use the generic router script
-require "router.pl";
-
-# Use the perl CGI module
-use CGI ':cgi';
-
-# Create the query and get the parameters
-
-$query=new CGI;
-
- at rawparams=$query->param;
-
-# Legal CGI parameters with regexp validity check
-
-%legalparams=(
-              "lon[1-9]"        => "[-0-9.]+",
-              "lat[1-9]"        => "[-0-9.]+",
-              "transport"       => "[a-z]+",
-              "highway-[a-z]+"  => "[0-9.]+",
-              "speed-[a-z]+"    => "[0-9.]+",
-              "property-[a-z]+" => "[0-9.]+",
-              "oneway"          => "(1|0|true|false|on|off)",
-              "turns"           => "(1|0|true|false|on|off)",
-              "weight"          => "[0-9.]+",
-              "height"          => "[0-9.]+",
-              "width"           => "[0-9.]+",
-              "length"          => "[0-9.]+",
-              "length"          => "[0-9.]+",
-
-              "language"        => "[-a-zA-Z]+",
-              "submit"          => "(shortest|quickest|link)",
-              "format"          => "(html|gpx-route|gpx-track|text|text-all|form)"
-             );
-
-# Validate the CGI parameters, ignore invalid ones
-
-foreach $key (@rawparams)
-  {
-   foreach $test (keys (%legalparams))
-     {
-      if($key =~ m%^$test$%)
-        {
-         $value=$query->param($key);
-
-         if($value =~ m%^$legalparams{$test}$%)
-           {
-            $cgiparams{$key}=$value;
-            last;
-           }
-        }
-     }
-  }
-
-# Get the important parameters
-
-$submit=$cgiparams{submit};
-delete $cgiparams{submit};
-
-$format=$cgiparams{format};
-delete $cgiparams{format};
-
-$format="form" if(!$format || ($submit ne "shortest" && $submit ne "quickest"));
-
-# Generate a custom URL
-
-$customurl="";
-
-if($submit)
-  {
-   $customurl="noscript.cgi?";
-
-   foreach $key (sort (keys %cgiparams))
-     {
-      $customurl.="$key=$cgiparams{$key};";
-     }
-
-   $customurl.="submit=custom";
-  }
-
-# Fill in the default parameters
-
-%fullparams=FillInDefaults(%cgiparams);
-
-# Open template file before running the router (including changing directory)
-
-open(TEMPLATE,"<noscript.template.html");
-
-# Run the router
-
-if($submit eq "shortest" || $submit eq "quickest")
-  {
-   ($router_uuid,$router_time,$router_result,$router_message)=RunRouter($submit,%fullparams);
-
-   $router_type=$submit;
-   $router_Type="Shortest" if($submit eq "shortest");
-   $router_Type="Quickest" if($submit eq "quickest");
-
-   if($format ne "form")
-     {
-      ReturnOutput($router_uuid,$submit,$format);
-      exit;
-     }
-  }
-
-# Generate the form output
-
-print header('text/html');
-
-# Parse the template and fill in the parameters
-
-while(<TEMPLATE>)
-  {
-   if (m%<input% && m%<!-- ([^ ]+) *-->%)
-     {
-      $key=$1;
-
-      m%type="([a-z]+)"%;
-      $type=$1;
-
-      m%value="([a-z]+)"%;
-      $value=$1;
-
-      if ($type eq "radio")
-        {
-         $checked="";
-         $checked="checked" if($fullparams{$key} eq $value);
-
-         s%><!-- .+? *-->% $checked>%;
-        }
-      elsif ($type eq "checkbox")
-        {
-         $checked="";
-         $checked="checked" if($fullparams{$key});
-
-         s%><!-- .+? *-->% $checked>%;
-        }
-      elsif ($type eq "text")
-        {
-         s%><!-- .+? *-->% value="$fullparams{$key}">%;
-        }
-
-      print;
-     }
-   elsif (m%<!-- custom-url -->%)
-     {
-      s%<!-- custom-url -->%$customurl%;
-
-      print if($submit);
-     }
-   elsif (m%<!-- result-start -->%)
-     {
-      $results_section=1;
-     }
-   elsif (m%<!-- result-finish -->%)
-     {
-      $results_section=0;
-     }
-   elsif ($results_section)
-     {
-      s%<!-- result-Type -->%$router_Type%;
-      s%<!-- result-type -->%$router_type%;
-      s%<!-- result-uuid -->%$router_uuid%;
-      s%<!-- result-time -->%$router_time%;
-      s%<!-- result-result -->%$router_result%;
-      s%<!-- result-message -->%$router_message%;
-
-      print if($router_uuid);
-     }
-   else
-     {
-      print;
-     }
-  }
-
-close(TEMPLATE);
diff --git a/web/www/routino/noscript.html b/web/www/routino/noscript.html
deleted file mode 100644
index 79344e2..0000000
--- a/web/www/routino/noscript.html
+++ /dev/null
@@ -1,70 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML>
-
-<!--
- Routino non-Javascript redirect web page.
-
- Part of the Routino routing software.
-
- This file Copyright 2008-2010 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
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program.  If not, see http://www.gnu.org/licenses/.
--->
-
-<HEAD>
-<TITLE>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</TITLE>
-<META http-equiv="refresh" content="1; URL=noscript.cgi">
-<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<LINK href="../documentation/style.css" type="text/css" rel="stylesheet">
-</HEAD>
-
-<BODY>
-
-<!-- Header Start -->
-
-<div class="header" align="center">
-
-<h1>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</h1>
-
-<hr>
-</div>
-
-<!-- Header End -->
-
-<!-- Content Start -->
-
-<div class="content">
-
-<h2><a href="noscript.cgi" title="Page Moved">Page Moved</a></h2>
-
-</div>
-
-<!-- Content End -->
-
-<!-- Footer Start -->
-
-<div class="footer" align="center">
-<hr>
-
-<address>
-© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
-</address>
-
-</div>
-
-<!-- Footer End -->
-
-</BODY>
-
-</HTML>
diff --git a/web/www/routino/noscript.template.html b/web/www/routino/noscript.template.html
deleted file mode 100644
index f5230bf..0000000
--- a/web/www/routino/noscript.template.html
+++ /dev/null
@@ -1,438 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML>
-
-<!--
- Routino non-Javascript web page.
-
- Part of the Routino routing software.
-
- This file Copyright 2008-2011 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
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program.  If not, see http://www.gnu.org/licenses/.
--->
-
-<HEAD>
-<TITLE>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</TITLE>
-<META name="keywords" content="openstreetmap routing route planner">
-<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<LINK href="../documentation/style.css" type="text/css" rel="stylesheet">
-</HEAD>
-
-<BODY>
-
-<!-- Header Start -->
-
-<div class="header" align="center">
-
-<h1>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</h1>
-
-<hr>
-</div>
-
-<!-- Header End -->
-
-<!-- Content Start -->
-
-<div class="content">
-
-<h2>Non Javascript Route Finder</h2>
-
-<form name="form" action="noscript.cgi" method="get">
-
-  <h3>Locations</h3>
-
-  When a route is calculated it will visit (as close as possible
-  for the selected transport type) each of the locations that have
-  been specified in the order given.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <td><b>Waypoint 1:</b>
-      <td><input name="lon1" type="text" size=8 title="Waypoint 1 Longitude" class="right"><!-- lon1 --> E
-      <td><input name="lat1" type="text" size=8 title="Waypoint 1 Latitude"  class="right"><!-- lat1 --> N
-    <tr>
-      <td><b>Waypoint 2:</b>
-      <td><input name="lon2" type="text" size=8 title="Waypoint 2 Longitude" class="right"><!-- lon2 --> E
-      <td><input name="lat2" type="text" size=8 title="Waypoint 2 Latitude"  class="right"><!-- lat2 --> N
-    <tr>
-      <td><b>Waypoint 3:</b>
-      <td><input name="lon3" type="text" size=8 title="Waypoint 3 Longitude" class="right"><!-- lon3 --> E
-      <td><input name="lat3" type="text" size=8 title="Waypoint 3 Latitude"  class="right"><!-- lat3 --> N
-    <tr>
-      <td><b>Waypoint 4:</b>
-      <td><input name="lon4" type="text" size=8 title="Waypoint 4 Longitude" class="right"><!-- lon4 --> E
-      <td><input name="lat4" type="text" size=8 title="Waypoint 4 Latitude"  class="right"><!-- lat4 --> N
-    <tr>
-      <td><b>Waypoint 5:</b>
-      <td><input name="lon5" type="text" size=8 title="Waypoint 5 Longitude" class="right"><!-- lon5 --> E
-      <td><input name="lat5" type="text" size=8 title="Waypoint 5 Latitude"  class="right"><!-- lat5 --> N
-    <tr>
-      <td><b>Waypoint 6:</b>
-      <td><input name="lon6" type="text" size=8 title="Waypoint 6 Longitude" class="right"><!-- lon6 --> E
-      <td><input name="lat6" type="text" size=8 title="Waypoint 6 Latitude"  class="right"><!-- lat6 --> N
-    <tr>
-      <td><b>Waypoint 7:</b>
-      <td><input name="lon7" type="text" size=8 title="Waypoint 7 Longitude" class="right"><!-- lon7 --> E
-      <td><input name="lat7" type="text" size=8 title="Waypoint 7 Latitude"  class="right"><!-- lat7 --> N
-    <tr>
-      <td><b>Waypoint 8:</b>
-      <td><input name="lon8" type="text" size=8 title="Waypoint 8 Longitude" class="right"><!-- lon8 --> E
-      <td><input name="lat8" type="text" size=8 title="Waypoint 8 Latitude"  class="right"><!-- lat8 --> N
-    <tr>
-      <td><b>Waypoint 9:</b>
-      <td><input name="lon9" type="text" size=8 title="Waypoint 9 Longitude" class="right"><!-- lon9 --> E
-      <td><input name="lat9" type="text" size=8 title="Waypoint 9 Latitude"  class="right"><!-- lat9 --> N
-  </table>
-
-  <p>
-
-  <h3>Transport Type</h3>
-
-  Selecting a transport type will restrict the chosen route to
-  those on which it is allowed.  Selecting one of the links here
-  will set default values for the other parameters.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <td><a href="noscript.cgi?transport=foot"       title="Foot profile"      >Foot      </a>
-      <td><input name="transport" type="radio" value="foot"      ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=horse"      title="Horse profile"     >Horse     </a>
-      <td><input name="transport" type="radio" value="horse"     ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=wheelchair" title="Wheelchair profile">Wheelchair</a>
-      <td><input name="transport" type="radio" value="wheelchair"><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=bicycle"    title="Bicycle profile"   >Bicycle   </a>
-      <td><input name="transport" type="radio" value="bicycle"   ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=moped"      title="Moped profile"     >Moped     </a>
-      <td><input name="transport" type="radio" value="moped"     ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=motorbike"  title="Motorbike profile" >Motorbike </a>
-      <td><input name="transport" type="radio" value="motorbike" ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=motorcar"   title="Motorcar profile"  >Motorcar  </a>
-      <td><input name="transport" type="radio" value="motorcar"  ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=goods"      title="Goods profile"     >Goods     </a>
-      <td><input name="transport" type="radio" value="goods"     ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=hgv"        title="HGV profile"       >HGV       </a>
-      <td><input name="transport" type="radio" value="hgv"       ><!-- transport -->
-    <tr>
-      <td><a href="noscript.cgi?transport=psv"        title="PSV profile"       >PSV       </a>
-      <td><input name="transport" type="radio" value="psv"       ><!-- transport -->
-  </table>
-
-  <p>
-
-  <h3>Highway Preferences</h3>
-
-  The highway preference is selected as a percentage and routes are chosen that
-  try to follow the preferred highways.
-  For example if a "Primary" road is given a "110%" preference and a "Secondary"
-  road is given a "100%" preference then it means that a route on a Primary road
-  can be up to 10% longer than on a secondary road and still be selected.
-
-  <h3>Speed Limits</h3>
-
-  The speed limits chosen here for the different types of highway apply if the
-  highway has no other speed limit marked or it is higher than the chosen one.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <th class="left">
-      <th class="left" colspan=2><b>Preference</b>
-      <th class="left" colspan=2><b>Speed Limit</b>
-    <tr>
-      <td class="left"  >Motorway:
-      <td class="right" ><input name="highway-motorway"     type="text" size=3 class="right"><!-- highway-motorway     -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-motorway"       type="text" size=3 class="right"><!-- speed-motorway       -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Trunk:
-      <td class="right" ><input name="highway-trunk"        type="text" size=3 class="right"><!-- highway-trunk        -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-trunk"          type="text" size=3 class="right"><!-- speed-trunk          -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Primary:
-      <td class="right" ><input name="highway-primary"      type="text" size=3 class="right"><!-- highway-primary      -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-primary"        type="text" size=3 class="right"><!-- speed-primary        -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Secondary:
-      <td class="right" ><input name="highway-secondary"    type="text" size=3 class="right"><!-- highway-secondary    -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-secondary"      type="text" size=3 class="right"><!-- speed-secondary      -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Tertiary:
-      <td class="right" ><input name="highway-tertiary"     type="text" size=3 class="right"><!-- highway-tertiary     -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-tertiary"       type="text" size=3 class="right"><!-- speed-tertiary       -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Unclassified:
-      <td class="right" ><input name="highway-unclassified" type="text" size=3 class="right"><!-- highway-unclassified -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-unclassified"   type="text" size=3 class="right"><!-- speed-unclassified   -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Residential:
-      <td class="right" ><input name="highway-residential"  type="text" size=3 class="right"><!-- highway-residential  -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-residential"    type="text" size=3 class="right"><!-- speed-residential    -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Service:
-      <td class="right" ><input name="highway-service"      type="text" size=3 class="right"><!-- highway-service      -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-service"        type="text" size=3 class="right"><!-- speed-service        -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Track:
-      <td class="right" ><input name="highway-track"        type="text" size=3 class="right"><!-- highway-track        -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-track"          type="text" size=3 class="right"><!-- speed-track          -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Cycleway:
-      <td class="right" ><input name="highway-cycleway"     type="text" size=3 class="right"><!-- highway-cycleway     -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-cycleway"       type="text" size=3 class="right"><!-- speed-cycleway       -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Path:
-      <td class="right" ><input name="highway-path"         type="text" size=3 class="right"><!-- highway-path         -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-path"           type="text" size=3 class="right"><!-- speed-path           -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Steps:
-      <td class="right" ><input name="highway-steps"        type="text" size=3 class="right"><!-- highway-steps        -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-steps"          type="text" size=3 class="right"><!-- speed-steps          -->
-      <td class="left"  >km/hr
-    <tr>
-      <td class="left"  >Ferry:
-      <td class="right" ><input name="highway-ferry"        type="text" size=3 class="right"><!-- highway-ferry        -->
-      <td class="left"  >%
-      <td class="right" ><input name="speed-ferry"          type="text" size=3 class="right"><!-- speed-ferry          -->
-      <td class="left"  >km/hr
-  </table>
-
-  <p>
-
-  <h3>Property Preferences</h3>
-
-  The property preference is selected as a percentage and routes are chosen that
-  try to follow highways with the preferred property.
-  For example if a "Paved" highway is given a "75%" preference then it means that
-  an unpaved highway is automatically given a "25%" preference so that a route on
-  a paved highway can be 3 times the length of an unpaved one and still be
-  selected.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <th class="left">
-      <th class="left" colspan=2><b>Preference</b><br>
-    <tr>
-      <td class="left"  >Paved:
-      <td class="right" ><input name="paved"        type="text" size=3 class="right"><!-- property-paved        -->
-      <td class="left"  >%
-    <tr>
-      <td class="left"  >Multiple Lanes:
-      <td class="right" ><input name="multilane"    type="text" size=3 class="right"><!-- property-multilane    -->
-      <td class="left"  >%
-    <tr>
-      <td class="left"  >Bridge:
-      <td class="right" ><input name="bridge"       type="text" size=3 class="right"><!-- property-bridge       -->
-      <td class="left"  >%
-    <tr>
-      <td class="left"  >Tunnel:
-      <td class="right" ><input name="tunnel"       type="text" size=3 class="right"><!-- property-tunnel       -->
-      <td class="left"  >%
-    <tr>
-      <td class="left"  >Walking Route:
-      <td class="right" ><input name="footroute"    type="text" size=3 class="right"><!-- property-footroute    -->
-      <td class="left"  >%
-    <tr>
-      <td class="left"  >Bicycle Route:
-      <td class="right" ><input name="bicycleroute" type="text" size=3 class="right"><!-- property-bicycleroute -->
-      <td class="left"  >%
-  </table>
-
-  <p>
-
-  <h3>Other Restrictions</h3>
-
-  These allow a route to be found that avoids marked limits on
-  weight, height, width or length.  It is also possible to ignore
-  one-way restrictions (e.g. if walking).
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <td class="left"  >Obey oneway:
-      <td class="right" ><input name="oneway" type="checkbox"><!-- oneway -->
-      <td class="left"  >
-    <tr>
-      <td class="left"  >Obey turn restrictions:
-      <td class="right" ><input name="turns" type="checkbox"><!-- turns -->
-      <td class="left"  >
-    <tr>
-      <td class="left"  >Weight:
-      <td class="right" ><input name="weight" type="text" size=3 class="right"><!-- weight -->
-      <td class="left"  >tonnes
-    <tr>
-      <td class="left"  >Height:
-      <td class="right" ><input name="height" type="text" size=3 class="right"><!-- height -->
-      <td class="left"  >metres
-    <tr>
-      <td class="left"  >Width:
-      <td class="right" ><input name="width"  type="text" size=3 class="right"><!-- width  -->
-      <td class="left"  >metres
-    <tr>
-      <td class="left"  >Length:
-      <td class="right" ><input name="length" type="text" size=3 class="right"><!-- length -->
-      <td class="left"  >metres
-  </table>
-
-  <p>
-
-<h3>Output Format</h3>
-
-  This allows for selection of the language of the generated output.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <td class="left">English (en)
-      <td class="left"><input name="language" type="radio" value="en" checked><!-- language -->
-    <tr>
-      <td class="left">German (de) 
-      <td class="left"><input name="language" type="radio" value="de"><!-- language -->
-  </table>
-
-  <p>
-
-  This allows for selection of the format of the generated output.
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <td class="left"><input name="format" type="radio" value="form" checked>This HTML format
-    <tr>
-      <td class="left"><input name="format" type="radio" value="html">HTML route instructions
-    <tr>
-      <td class="left"><input name="format" type="radio" value="gpx-track">GPX track file
-    <tr>
-      <td class="left"><input name="format" type="radio" value="gpx-route">GPX route file
-    <tr>
-      <td class="left"><input name="format" type="radio" value="text">Text file
-    <tr>
-      <td class="left"><input name="format" type="radio" value="text-all">Full text file
-  </table>
-
-  <p>
-
-  <h3>Calculate Route</h3>
-
-  <button type="submit" name="submit" value="shortest">Shortest</button>
-  <button type="submit" name="submit" value="quickest">Quickest</button>
-
-  <p>
-
-  <!-- result-start -->
-
-  <hr>
-
-  <p>
-
-  <table class="noborder-left">
-    <tr>
-      <th class="left" colspan=2><u><b><!-- result-Type --> Result</b></u>
-    <tr>
-      <td class="left" colspan=2><b><!-- result-message --></b>
-    <tr>
-      <td class="left" colspan=2><b><!-- result-result --></b>
-    <tr>
-      <td class="left">HTML file:
-      <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=html">Open</a>
-    <tr>
-      <td class="left">GPX track file:
-      <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=gpx-track">Open</a>
-    <tr>
-      <td class="left">GPX route file:
-      <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=gpx-route">Open</a>
-    <tr>
-      <td class="left">Text file:
-      <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=text">Open</a>
-    <tr>
-      <td class="left">Full text file:
-      <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=text-all">Open</a>
-    <tr>
-      <td class="left" colspan=2><i><!-- result-time --></i>
-  </table>
-
-  <p>
-
-  <!-- result-finish -->
-
-  <hr>
-
-  <p>
-
-  <h3>Create Link</h3>
-
-  <button type="submit" name="submit" value="link">Create Link</button>
-  <a title="" href="<!-- custom-url -->">Bookmarkable link with customised parameters</a>
-
-</form>
-
-</div>
-
-<!-- Content End -->
-
-<!-- Footer Start -->
-
-<div class="footer" align="center">
-<hr>
-
-<address>
-© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
-</address>
-
-</div>
-
-<!-- Footer End -->
-
-</BODY>
-
-</HTML>
diff --git a/xml/routino-osm.xsd b/xml/osc.xsd
similarity index 66%
copy from xml/routino-osm.xsd
copy to xml/osc.xsd
index 640b59b..de032b3 100644
--- a/xml/routino-osm.xsd
+++ b/xml/osc.xsd
@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="utf-8" ?>
 
 <!-- ============================================================
-     An XML Schema Definition for the part of the OSM XML format read by Routino.
+     An XML Schema Definition for the OSC (OsmChange) XML format
 
-     Part of the Routino routing software.
+     Created by reverse engineering an OSC file from the planet replication diffs;
+     not used in Routino but in a proof-of-concept parser created by xsd-to-xmlparser.
      ============================================================
      This file Copyright 2010-2012 Andrew M. Bishop
 
@@ -15,62 +16,57 @@
 
 <xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
-  <!-- The top level osm element -->
+  <!-- The top level osmChange element -->
 
-  <xsd:element name="osm" type="osmType"/>
+  <xsd:element name="osmChange" type="osmChangeType"/>
 
-  <xsd:complexType name="osmType">
+  <xsd:complexType name="osmChangeType">
     <xsd:sequence>
-      <xsd:element name="bounds"    type="boundsType"    minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="bound"     type="boundType"     minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="changeset" type="changesetType" minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="node"      type="nodeType"      minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="way"       type="wayType"       minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="relation"  type="relationType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="bounds"    type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="modify"    type="modifyType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="create"    type="createType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="delete"    type="deleteType" minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
     <xsd:attribute name="version"   type="xsd:string"/>
-    <!--
     <xsd:attribute name="generator" type="xsd:string"/>
-    -->
   </xsd:complexType>
 
-  <!-- The second level bounds, bound, changeset, node, way and relation elements -->
+  <!-- The second level bounds, modify, create and delete elements -->
 
   <xsd:complexType name="boundsType">
-    <!--
     <xsd:attribute name="minlat"    type="xsd:string"/>
     <xsd:attribute name="minlon"    type="xsd:string"/>
     <xsd:attribute name="maxlat"    type="xsd:string"/>
     <xsd:attribute name="maxlon"    type="xsd:string"/>
     <xsd:attribute name="origin"    type="xsd:string"/>
-    -->
   </xsd:complexType>
 
-  <xsd:complexType name="boundType">
-    <!--
-    <xsd:attribute name="box"       type="xsd:string"/>
-    <xsd:attribute name="origin"    type="xsd:string"/>
-    -->
+  <xsd:complexType name="modifyType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="createType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
   </xsd:complexType>
 
-  <xsd:complexType name="changesetType">
+  <xsd:complexType name="deleteType">
     <xsd:sequence>
-      <xsd:element name="tag"        type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
-    <!--
-    <xsd:attribute name="id"         type="xsd:string"/>
-    <xsd:attribute name="min_lat"    type="xsd:string"/>
-    <xsd:attribute name="min_lon"    type="xsd:string"/>
-    <xsd:attribute name="max_lat"    type="xsd:string"/>
-    <xsd:attribute name="max_lon"    type="xsd:string"/>
-    <xsd:attribute name="created_at" type="xsd:string"/>
-    <xsd:attribute name="closed_at"  type="xsd:string"/>
-    <xsd:attribute name="open"       type="xsd:string"/>
-    <xsd:attribute name="uid"        type="xsd:string"/>
-    <xsd:attribute name="user"       type="xsd:string"/>
-    -->
   </xsd:complexType>
 
+  <!-- The third level node, way and relation elements -->
+
   <xsd:complexType name="nodeType">
     <xsd:sequence>
       <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
@@ -78,7 +74,6 @@
     <xsd:attribute name="id"        type="xsd:string"/>
     <xsd:attribute name="lat"       type="xsd:string"/>
     <xsd:attribute name="lon"       type="xsd:string"/>
-    <!--
     <xsd:attribute name="timestamp" type="xsd:string"/>
     <xsd:attribute name="uid"       type="xsd:string"/>
     <xsd:attribute name="user"      type="xsd:string"/>
@@ -86,7 +81,6 @@
     <xsd:attribute name="version"   type="xsd:string"/>
     <xsd:attribute name="changeset" type="xsd:string"/>
     <xsd:attribute name="action"    type="xsd:string"/>
-    -->
   </xsd:complexType>
 
   <xsd:complexType name="wayType">
@@ -95,7 +89,6 @@
       <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
     <xsd:attribute name="id"        type="xsd:string"/>
-    <!--
     <xsd:attribute name="timestamp" type="xsd:string"/>
     <xsd:attribute name="uid"       type="xsd:string"/>
     <xsd:attribute name="user"      type="xsd:string"/>
@@ -103,7 +96,6 @@
     <xsd:attribute name="version"   type="xsd:string"/>
     <xsd:attribute name="changeset" type="xsd:string"/>
     <xsd:attribute name="action"    type="xsd:string"/>
-    -->
   </xsd:complexType>
 
   <xsd:complexType name="relationType">
@@ -112,7 +104,6 @@
       <xsd:element name="tag"       type="tagType"    minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
     <xsd:attribute name="id"        type="xsd:string"/>
-    <!--
     <xsd:attribute name="timestamp" type="xsd:string"/>
     <xsd:attribute name="uid"       type="xsd:string"/>
     <xsd:attribute name="user"      type="xsd:string"/>
@@ -120,10 +111,9 @@
     <xsd:attribute name="version"   type="xsd:string"/>
     <xsd:attribute name="changeset" type="xsd:string"/>
     <xsd:attribute name="action"    type="xsd:string"/>
-    -->
   </xsd:complexType>
 
-  <!-- The third level elements and their contents -->
+  <!-- The fourth level elements and their contents -->
 
   <xsd:complexType name="tagType">
     <xsd:attribute name="k"         type="xsd:string"/>
diff --git a/xml/osm.xsd b/xml/osm.xsd
index fe3f9b1..a92f5ba 100644
--- a/xml/osm.xsd
+++ b/xml/osm.xsd
@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="utf-8" ?>
 
 <!-- ============================================================
-     An XML Schema Definition for the OSM (JOSM?) XML format
+     An XML Schema Definition for the OSM XML format (including JOSM
+     specific additions such as 'bounds' tag and 'action' attribute).
 
-     Created by reverse engineering a JOSM saved file, not used in Routino
-     but a proof-of-concept parser created by xsd-to-xmlparser.
+     Created by reverse engineering a JOSM saved file; not used in Routino
+     but in a proof-of-concept parser created by xsd-to-xmlparser.
      ============================================================
      This file Copyright 2010-2012 Andrew M. Bishop
 
diff --git a/xml/routino-osm.xsd b/xml/routino-osc.xsd
similarity index 68%
copy from xml/routino-osm.xsd
copy to xml/routino-osc.xsd
index 640b59b..9c5f285 100644
--- a/xml/routino-osm.xsd
+++ b/xml/routino-osc.xsd
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8" ?>
 
 <!-- ============================================================
-     An XML Schema Definition for the part of the OSM XML format read by Routino.
+     An XML Schema Definition for the part of the OSC XML format read by Routino.
 
-     Part of the Routino routing software.
+     Part of the Routino routing software (semi-automatically converted to create osmparse.c).
      ============================================================
      This file Copyright 2010-2012 Andrew M. Bishop
 
@@ -15,18 +15,16 @@
 
 <xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
-  <!-- The top level osm element -->
+  <!-- The top level osmChange element -->
 
-  <xsd:element name="osm" type="osmType"/>
+  <xsd:element name="osmChange" type="osmChangeType"/>
 
-  <xsd:complexType name="osmType">
+  <xsd:complexType name="osmChangeType">
     <xsd:sequence>
-      <xsd:element name="bounds"    type="boundsType"    minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="bound"     type="boundType"     minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="changeset" type="changesetType" minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="node"      type="nodeType"      minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="way"       type="wayType"       minOccurs="0" maxOccurs="unbounded"/>
-      <xsd:element name="relation"  type="relationType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="bounds"    type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="modify"    type="modifyType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="create"    type="createType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="delete"    type="deleteType" minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
     <xsd:attribute name="version"   type="xsd:string"/>
     <!--
@@ -34,7 +32,7 @@
     -->
   </xsd:complexType>
 
-  <!-- The second level bounds, bound, changeset, node, way and relation elements -->
+  <!-- The second level bounds, modify, create and delete elements -->
 
   <xsd:complexType name="boundsType">
     <!--
@@ -46,31 +44,32 @@
     -->
   </xsd:complexType>
 
-  <xsd:complexType name="boundType">
-    <!--
-    <xsd:attribute name="box"       type="xsd:string"/>
-    <xsd:attribute name="origin"    type="xsd:string"/>
-    -->
+  <xsd:complexType name="modifyType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
   </xsd:complexType>
 
-  <xsd:complexType name="changesetType">
+  <xsd:complexType name="createType">
     <xsd:sequence>
-      <xsd:element name="tag"        type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="deleteType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
     </xsd:sequence>
-    <!--
-    <xsd:attribute name="id"         type="xsd:string"/>
-    <xsd:attribute name="min_lat"    type="xsd:string"/>
-    <xsd:attribute name="min_lon"    type="xsd:string"/>
-    <xsd:attribute name="max_lat"    type="xsd:string"/>
-    <xsd:attribute name="max_lon"    type="xsd:string"/>
-    <xsd:attribute name="created_at" type="xsd:string"/>
-    <xsd:attribute name="closed_at"  type="xsd:string"/>
-    <xsd:attribute name="open"       type="xsd:string"/>
-    <xsd:attribute name="uid"        type="xsd:string"/>
-    <xsd:attribute name="user"       type="xsd:string"/>
-    -->
   </xsd:complexType>
 
+  <!-- The third level node, way and relation elements -->
+
   <xsd:complexType name="nodeType">
     <xsd:sequence>
       <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
@@ -123,7 +122,7 @@
     -->
   </xsd:complexType>
 
-  <!-- The third level elements and their contents -->
+  <!-- The fourth level elements and their contents -->
 
   <xsd:complexType name="tagType">
     <xsd:attribute name="k"         type="xsd:string"/>
diff --git a/xml/routino-osm.xsd b/xml/routino-osm.xsd
index 640b59b..ca43c4a 100644
--- a/xml/routino-osm.xsd
+++ b/xml/routino-osm.xsd
@@ -3,7 +3,7 @@
 <!-- ============================================================
      An XML Schema Definition for the part of the OSM XML format read by Routino.
 
-     Part of the Routino routing software.
+     Part of the Routino routing software (semi-automatically converted to create osmparse.c).
      ============================================================
      This file Copyright 2010-2012 Andrew M. Bishop
 
diff --git a/xml/routino-tagging.xml b/xml/routino-tagging.xml
index fdbf2d9..042c7fc 100644
--- a/xml/routino-tagging.xml
+++ b/xml/routino-tagging.xml
@@ -23,21 +23,22 @@
     <!-- Note: The default is that all transport types are allowed past a barrier;
                access must be specified to disallow each transport type. -->
 
-    <!-- Barrier types -->
+    <!-- Not useful barrier types (too generic) -->
 
-    <if k="barrier" v="bollard">
-      <output k="motorcar"   v="no"/>
-      <output k="goods"      v="no"/>
-      <output k="hgv"        v="no"/>
-      <output k="psv"        v="no"/>
+    <if k="barrier" v="gate">     <unset/></if>
+    <if k="barrier" v="entrance"> <unset/></if>
+    <if k="barrier" v="lift_gate"><unset/></if>
 
-      <unset k="barrier"/>
-    </if>
+    <!-- Barrier types -->
 
     <if k="barrier" v="kissing_gate">
       <set v="foot_only"/>
     </if>
 
+    <if k="barrier" v="footgate">
+      <set v="foot_only"/>
+    </if>
+
     <if k="barrier" v="stile">
       <set v="foot_only"/>
     </if>
@@ -50,11 +51,11 @@
       <set v="foot_only"/>
     </if>
 
-    <if k="barrier" v="footgate">
+    <if k="barrier" v="squeeze">
       <set v="foot_only"/>
     </if>
 
-    <if k="barrier" v="squeeze">
+    <if k="barrier" v="squeeze_stile">
       <set v="foot_only"/>
     </if>
 
@@ -62,6 +63,10 @@
       <set v="foot_only"/>
     </if>
 
+    <if k="barrier" v="bicycle_barrier">
+      <set v="foot_only"/>
+    </if>
+
     <if k="barrier" v="foot_only">
       <output k="horse"      v="no"/>
       <output k="wheelchair" v="no"/>
@@ -76,19 +81,50 @@
       <unset k="barrier"/>
     </if>
 
-    <if k="barrier" v="horse_barrier">
-      <output k="horse"      v="no"/>
+    <if k="barrier" v="horse_stile">
+      <set v="not_wheeled"/>
+    </if>
+
+    <if k="barrier" v="horse_jump">
+      <set v="not_wheeled"/>
+    </if>
+
+    <if k="barrier" v="step_over">
+      <set v="not_wheeled"/>
+    </if>
+
+    <if k="barrier" v="not_wheeled">
+      <output k="wheelchair" v="no"/>
+      <output k="bicycle"    v="no"/>
+      <output k="moped"      v="no"/>
+      <output k="motorbike"  v="no"/>
+      <output k="motorcar"   v="no"/>
+      <output k="goods"      v="no"/>
+      <output k="hgv"        v="no"/>
+      <output k="psv"        v="no"/>
 
       <unset k="barrier"/>
     </if>
 
+    <if k="barrier" v="horse_barrier">
+      <set v="no_horse"/>
+    </if>
+
     <if k="barrier" v="cattle_grid">
+      <set v="no_horse"/>
+    </if>
+
+    <if k="barrier" v="no_horse">
       <output k="horse"      v="no"/>
 
       <unset k="barrier"/>
     </if>
 
-    <if k="barrier" v="car_trap">
+    <if k="barrier" v="motorcyle_barrier">
+      <set v="no_motorised"/>
+    </if>
+
+    <if k="barrier" v="no_motorised">
       <output k="moped"      v="no"/>
       <output k="motorbike"  v="no"/>
       <output k="motorcar"   v="no"/>
@@ -99,12 +135,26 @@
       <unset k="barrier"/>
     </if>
 
-    <!-- Barriers that are too generic but listed to stop errors -->
+    <if k="barrier" v="bollard">
+      <set v="not_2plus_wheels"/>
+    </if>
 
-    <if k="barrier" v="gate">     <unset k="barrier"/></if>
-    <if k="barrier" v="entrance"> <unset k="barrier"/></if>
-    <if k="barrier" v="lift_gate"><unset k="barrier"/></if>
-    <if k="barrier" v="block">    <unset k="barrier"/></if>
+    <if k="barrier" v="car_barrier">
+      <set v="not_2plus_wheels"/>
+    </if>
+
+    <if k="barrier" v="car_trap">
+      <set v="not_2plus_wheels"/>
+    </if>
+
+    <if k="barrier" v="not_2plus_wheels">
+      <output k="motorcar"   v="no"/>
+      <output k="goods"      v="no"/>
+      <output k="hgv"        v="no"/>
+      <output k="psv"        v="no"/>
+
+      <unset k="barrier"/>
+    </if>
 
     <if k="barrier">
       <logerror/>
@@ -119,6 +169,7 @@
     <if v="public"     ><set v="yes"/></if>
     <if v="official"   ><set v="yes"/></if>
 
+    <if v="unsuitable" ><set v="no"/></if>
     <if v="private"    ><set v="no"/></if>
     <if v="limited"    ><set v="no"/></if>
 
@@ -194,10 +245,26 @@
     <!-- Note: The default is that no transport type is allowed on any highway;
                access must be specified to allow each transport type. -->
 
-    <if k="highway">
-      <output/>
+    <!-- Not useful highway types -->
+
+    <if k="highway" v="proposed">
+      <unset/>
+    </if>
+
+    <if k="highway" v="construction">
+      <unset/>
+    </if>
+
+    <if k="highway" v="abandoned">
+      <unset/>
     </if>
 
+    <if k="highway" v="raceway">
+      <unset/>
+    </if>
+
+    <!-- Mark ways that are not highways to suppress error logging on non-highways -->
+
     <if>
       <set k="not_highway" v="yes"/>
     </if>
@@ -224,6 +291,8 @@
       <output k="paved"      v="yes"/>
       <output k="multilane"  v="yes"/>
       <output k="oneway"     v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="trunk_link">
@@ -242,6 +311,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="primary_link">
@@ -263,6 +334,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="secondary_link">
@@ -284,6 +357,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="tertiary_link">
@@ -305,6 +380,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="minor">
@@ -330,6 +407,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="living_street">
@@ -351,6 +430,12 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
+    </if>
+
+    <if k="highway" v="access">
+      <set k="highway" v="service"/>
     </if>
 
     <if k="highway" v="services">
@@ -376,6 +461,8 @@
       <output k="psv"        v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="byway">
@@ -396,6 +483,8 @@
       <output k="foot"       v="yes"/>
       <output k="horse"      v="yes"/>
       <output k="bicycle"    v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="tracktype" v="grade1">
@@ -410,6 +499,8 @@
       <output k="bicycle"    v="yes"/>
 
       <output k="paved"      v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="footway">
@@ -440,18 +531,28 @@
 
       <output k="foot"       v="yes"/>
       <output k="wheelchair" v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="highway" v="steps">
       <output k="highway"/>
 
       <output k="foot"       v="yes"/>
+
+      <unset k="highway"/>
     </if>
 
     <if k="route" v="ferry">
       <output k="highway" v="ferry"/>
     </if>
 
+    <if k="highway">
+      <logerror/>
+
+      <set k="not_highway" v="yes"/>
+    </if>
+
     <!-- Normalisation of access tags -->
 
     <if v="designated" ><set v="yes"/></if>
@@ -461,6 +562,7 @@
     <if v="public"     ><set v="yes"/></if>
     <if v="official"   ><set v="yes"/></if>
 
+    <if v="unsuitable" ><set v="no"/></if>
     <if v="private"    ><set v="no"/></if>
     <if v="limited"    ><set v="no"/></if>
 
@@ -610,37 +712,51 @@
 
     <!-- Normalisation of property tags -->
 
-    <if k="surface" v="paved">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <!-- Tags from http://wiki.openstreetmap.org/wiki/Key:surface on 2012-11-21 -->
+
+    <if k="surface" v="asphalt">               <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="cobblestone">           <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="cobblestone:flattened"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="compacted">             <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="concrete">              <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="concrete:lanes">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="concrete:plates">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="dirt">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="earth">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="fine_gravel">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="grass">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="grass_paver">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="gravel">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="ground">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="metal">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="mud">                   <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="paved">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="paving_stones">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="paving_stones:20">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="paving_stones:30">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="pebblestone">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="sand">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="unpaved">               <set k="paved" v="no"/>  <unset k="surface"/> </if>
+    <if k="surface" v="wood">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+
+    <!-- Other tags -->
+
     <if k="surface" v="sealed">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
-    <if k="surface" v="concrete">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="cement">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
-    <if k="surface" v="asphalt">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="tarmac">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="tar_and_chip">  <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="metalled">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
-    <if k="surface" v="paving_stones"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="bricks">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="brick">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="brick_weave">   <set k="paved" v="yes"/> <unset k="surface"/> </if>
     <if k="surface" v="setts">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
-    <if k="surface" v="metal">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+    <if k="surface" v="sett">          <set k="paved" v="yes"/> <unset k="surface"/> </if>
 
-    <if k="surface" v="unpaved">       <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="unsealed">      <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="grass">         <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="grass_paver">   <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="ground">        <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="earth">         <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="dirt">          <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="soil">          <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="mud">           <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="stones">        <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="stone">         <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="gravel">        <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="sand">          <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="cobblestone">   <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="pebbles">       <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="pebblestone">   <set k="paved" v="no"/> <unset k="surface"/> </if>
-    <if k="surface" v="compacted">     <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="hardcore">      <set k="paved" v="no"/> <unset k="surface"/> </if>
     <if k="surface" v="bark">          <set k="paved" v="no"/> <unset k="surface"/> </if>
 
@@ -755,6 +871,10 @@
       <output/>
     </if>
 
+    <if k="except" v="bus">
+      <set v="psv"/>
+    </if>
+
     <if k="except">
       <output/>
     </if>

-- 
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