[Git][debian-gis-team/routino][bookworm-backports] 9 commits: Update branch in gbp.conf & Vcs-Git URL.

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Thu May 8 06:39:42 BST 2025



Bas Couwenberg pushed to branch bookworm-backports at Debian GIS Project / routino


Commits:
6ad6ef7a by Bas Couwenberg at 2025-04-27T06:29:21+02:00
Update branch in gbp.conf & Vcs-Git URL.

- - - - -
5160e6ff by Bas Couwenberg at 2025-04-27T06:31:29+02:00
New upstream version 3.4.3
- - - - -
b25118b7 by Bas Couwenberg at 2025-04-27T06:31:35+02:00
Update upstream source from tag 'upstream/3.4.3'

Update to upstream version '3.4.3'
with Debian dir 35fb5a9976be1d673b6d6d3d8b53d85cfe75a3d7
- - - - -
4629a189 by Bas Couwenberg at 2025-04-27T06:33:36+02:00
New upstream release.

- - - - -
5de05c60 by Bas Couwenberg at 2025-04-27T06:35:49+02:00
Set distribution to experimental.

- - - - -
e6122705 by Bas Couwenberg at 2025-04-28T05:36:46+02:00
Revert "Update branch in gbp.conf & Vcs-Git URL."

This reverts commit 6ad6ef7a105f9e74fcedae885c0f8f0af8172706.

- - - - -
e538f28c by Bas Couwenberg at 2025-04-28T05:43:34+02:00
Move from experimental to unstable.

- - - - -
c75f88e9 by Bas Couwenberg at 2025-05-08T07:35:27+02:00
Merge tag 'debian/3.4.3-1' into bookworm-backports

releasing package routino version 3.4.3-1

- - - - -
2d74866a by Bas Couwenberg at 2025-05-08T07:35:34+02:00
Rebuild for bookworm-backports.

- - - - -


21 changed files:

- ChangeLog
- debian/changelog
- doc/NEWS.txt
- doc/README.txt
- doc/html/readme.html
- extras/find-fixme/fixme-finder.c
- + src/#nodesx.c#
- src/files.c
- src/files.h
- src/logerror.c
- src/logging.c
- src/logging.h
- src/nodesx.c
- src/planetsplitter.c
- src/relationsx.c
- src/router.c
- src/sorting.c
- src/uncompress.c
- src/version.h
- src/waysx.c
- src/xml/xsd-to-xmlparser.c


Changes:

=====================================
ChangeLog
=====================================
@@ -1,3 +1,62 @@
+2025-04-26  Andrew M. Bishop <amb>
+
+	Version 3.4.3 released.
+
+2025-04-26 [r2207]  Andrew M. Bishop <amb>
+
+	* doc/html/readme.html: Fix typo in release notes.
+
+2025-04-26 [r2205]  Andrew M. Bishop <amb>
+
+	* FILES, doc/NEWS.txt, doc/README.txt, doc/html/readme.html,
+	  src/version.h: Update to version 3.4.3.
+
+2025-04-09 [r2203]  Andrew M. Bishop <amb>
+
+	* src/files.c, src/files.h, src/sorting.c: Merge the "filebuffer"
+	  and "openedfile" data structures. Add a new function for deleting
+	  an open buffered file. Improve the new logassert messages to
+	  print the filename.
+
+2025-04-08 [r2202]  Andrew M. Bishop <amb>
+
+	* src/files.c: Allocate the string for the filename of the mapped
+	  files. Don't allocate a filebuffer structure for mapped files.
+
+2025-04-06 [r2201]  Andrew M. Bishop <amb>
+
+	* src/files.c: Print an error message and exit if read/write fails.
+
+2025-04-06 [r2200]  Andrew M. Bishop <amb>
+
+	* extras/find-fixme/fixme-finder.c, src/files.c, src/logerror.c,
+	  src/planetsplitter.c, src/router.c, src/uncompress.c,
+	  src/xml/xsd-to-xmlparser.c: Check and update all exits from the
+	  program to make sure that there is consistency in the error
+	  messages. Use logassert if it's an internal bug, use
+	  fprintf();exit() if it's a user error or program failure to
+	  route.
+
+2025-04-06 [r2199]  Andrew M. Bishop <amb>
+
+	* src/nodesx.c, src/relationsx.c, src/waysx.c: Revert part of r2189
+	  and add extra checks on the sizes of node_t, way_t and relation_t
+	  with respect to index_t.
+
+2025-04-05 [r2198]  Andrew M. Bishop <amb>
+
+	* src/logging.c, src/logging.h: Create a logassert function that
+	  allows a format string (via a pre-processor hack).
+
+2025-04-05 [r2197]  Andrew M. Bishop <amb>
+
+	* src/version.h: Update the version number to make clear it is
+	  modified from the release version.
+
+2025-03-29  Andrew M. Bishop <amb>
+
+	Version 3.4.2 released.
+
 2025-03-29 [r2193]  Andrew M. Bishop <amb>
 
 	* FILES, doc/NEWS.txt, doc/README.txt, doc/html/readme.html,


=====================================
debian/changelog
=====================================
@@ -1,3 +1,21 @@
+routino (3.4.3-1~bpo12+1) bookworm-backports; urgency=medium
+
+  * Rebuild for bookworm-backports.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Thu, 08 May 2025 07:35:32 +0200
+
+routino (3.4.3-1) unstable; urgency=medium
+
+  * Move from experimental to unstable.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Mon, 28 Apr 2025 05:43:31 +0200
+
+routino (3.4.3-1~exp1) experimental; urgency=medium
+
+  * New upstream release.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Sun, 27 Apr 2025 06:35:37 +0200
+
 routino (3.4.2-1~bpo12+1) bookworm-backports; urgency=medium
 
   * Rebuild for bookworm-backports.


=====================================
doc/NEWS.txt
=====================================
@@ -1,3 +1,13 @@
+Version 3.4.3 of Routino released : Sat Apr 26 2025
+---------------------------------------------------
+
+Bug fixes:
+  Fix bug that would crash on some turn relations (partial undo of v3.4.2).
+
+
+Note: This version is compatible with databases from versions 2.7.1 - 3.4.2.
+
+
 Version 3.4.2 of Routino released : Sat Mar 29 2025
 ---------------------------------------------------
 


=====================================
doc/README.txt
=====================================
@@ -115,6 +115,7 @@ Status
    Version 3.4 of Routino was released on 11th June 2023.
    Version 3.4.1 of Routino was released on 1st July 2023.
    Version 3.4.2 of Routino was released on 29th March 2025.
+   Version 3.4.3 of Routino was released on 26th April 2025.
 
    The full version history is available in the NEWS.txt file.
 


=====================================
doc/html/readme.html
=====================================
@@ -182,6 +182,8 @@ Version 3.4 of Routino was released on 11th June 2023.
 Version 3.4.1 of Routino was released on 1st July 2023.
 <br>
 Version 3.4.2 of Routino was released on 29th March 2025.
+<br>
+Version 3.4.3 of Routino was released on 26th April 2025.
 
 <p>
 
@@ -247,7 +249,19 @@ The full version history is available in the NEWS.txt file.
 <b>Note:</b> This version is compatible with databases from versions 2.7.1 - 3.4.1.
 
 
-<h3 id="H_1_5_4" title="Other Versions">Other Versions</h3>
+<h3 id="H_1_5_4" title="Changes 3.4.3">Changes in Version 3.4.3</h3>
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Fix bug that would crash on some turn relations (partial undo of v3.4.2).
+</dl>
+
+<p>
+<b>Note:</b> This version is compatible with databases from versions 2.7.1 - 3.4.2.
+
+
+
+<h3 id="H_1_5_5" title="Other Versions">Other Versions</h3>
 
 There is a version of Routino (in subversion, on the branch called
 "destination-access") that allows the first and last waypoint of a


=====================================
extras/find-fixme/fixme-finder.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2023 Andrew M. Bishop
+ This file Copyright 2008-2015, 2023, 2025 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
@@ -211,17 +211,17 @@ int main(int argc,char** argv)
     if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
       {
        if(ParsePBFFile(fd,OSMNodes,OSMWays,OSMRelations))
-          exit(EXIT_FAILURE);
+          exit(EXIT_FAILURE); /* no message because one printed in parser function */
       }
     else if((p=strstr(filename,".o5m")) && !strcmp(p,".o5m"))
       {
        if(ParseO5MFile(fd,OSMNodes,OSMWays,OSMRelations))
-          exit(EXIT_FAILURE);
+          exit(EXIT_FAILURE); /* no message because one printed in parser function */
       }
     else
       {
        if(ParseOSMFile(fd,OSMNodes,OSMWays,OSMRelations))
-          exit(EXIT_FAILURE);
+          exit(EXIT_FAILURE); /* no message because one printed in parser function */
       }
 
     CloseFile(fd);


=====================================
src/#nodesx.c#
=====================================
@@ -0,0 +1,904 @@
+/***************************************
+ Extented Node data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015, 2019, 2020, 2022 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 <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "nodes.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ 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 (re-initialised for each sort). +*/
+static NodesX *sortnodesx;
+static latlong_t lat_min,lat_max,lon_min,lon_max;
+
+/* 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 update_id(NodeX *nodex,index_t index);
+static int sort_by_lat_long(NodeX *a,NodeX *b);
+static int index_by_lat_long(NodeX *nodex,index_t index);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new node list (create a new file or open an existing one).
+
+  NodesX *NewNodeList Returns a pointer to the node list.
+
+  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,int readonly)
+{
+ NodesX *nodesx;
+
+ nodesx=(NodesX*)calloc_logassert(1,sizeof(NodesX));
+
+ nodesx->filename    =(char*)malloc_logassert(strlen(option_tmpdirname)+32);
+ nodesx->filename_tmp=(char*)malloc_logassert(strlen(option_tmpdirname)+40); /* allow %p to be up to 20 bytes */
+
+ sprintf(nodesx->filename    ,"%s/nodesx.parsed.mem",option_tmpdirname);
+ sprintf(nodesx->filename_tmp,"%s/nodesx.%p.tmp"    ,option_tmpdirname,(void*)nodesx);
+
+ if(append || readonly)
+    if(ExistsFile(nodesx->filename))
+      {
+       offset_t size;
+
+       size=SizeFile(nodesx->filename);
+
+       nodesx->number=size/sizeof(NodeX);
+
+       RenameFile(nodesx->filename,nodesx->filename_tmp);
+      }
+
+ if(append)
+    nodesx->fd=OpenFileBufferedAppend(nodesx->filename_tmp);
+ else if(!readonly)
+    nodesx->fd=OpenFileBufferedNew(nodesx->filename_tmp);
+ else
+    nodesx->fd=-1;
+
+#if SLIM
+ nodesx->cache=NewNodeXCache();
+ log_malloc(nodesx->cache,sizeof(*nodesx->cache));
+#endif
+
+ nodesx->ifilename_tmp=(char*)malloc_logassert(strlen(option_tmpdirname)+40); /* allow %p to be up to 20 bytes */
+
+ sprintf(nodesx->ifilename_tmp,"%s/nodesx.%p.idx.tmp",option_tmpdirname,(void*)nodesx);
+
+ return(nodesx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a node list.
+
+  NodesX *nodesx The set of nodes to be freed.
+
+  int keep If set then the results file is to be kept.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeNodeList(NodesX *nodesx,int keep)
+{
+ if(keep)
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+ else
+    DeleteFile(nodesx->filename_tmp);
+
+ free(nodesx->filename);
+ free(nodesx->filename_tmp);
+
+ DeleteFile(nodesx->ifilename_tmp);
+
+ free(nodesx->ifilename_tmp);
+
+ if(nodesx->gdata)
+   {
+    log_free(nodesx->gdata);
+    free(nodesx->gdata);
+   }
+
+ if(nodesx->pdata)
+   {
+    log_free(nodesx->pdata);
+    free(nodesx->pdata);
+   }
+
+ if(nodesx->super)
+   {
+    log_free(nodesx->super);
+    free(nodesx->super);
+   }
+
+#if SLIM
+ log_free(nodesx->cache);
+ DeleteNodeXCache(nodesx->cache);
+#endif
+
+ free(nodesx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single node to an unsorted node list.
+
+  NodesX *nodesx The set of nodes to modify.
+
+  node_t id The node identifier from the original OSM data.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+
+  transports_t allow The allowed traffic types through the node.
+
+  nodeflags_t flags The flags to set for this node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendNodeList(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,nodeflags_t flags)
+{
+ NodeX nodex={0};
+
+ nodex.id=id;
+ nodex.latitude =radians_to_latlong(latitude);
+ nodex.longitude=radians_to_latlong(longitude);
+ nodex.allow=allow;
+ nodex.flags=flags;
+
+ WriteFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
+
+ nodesx->number++;
+
+ 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=CloseFileBuffered(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);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and exit if it matches else move start or end.
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 if we find that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one or neither is.
+  */
+
+ while((end-start)>1)
+   {
+    mid=start+(end-start)/2;       /* Choose mid point (avoid overflow) */
+
+    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-1;
+    else                           /* Mid point is correct */
+       return(mid);
+   }
+
+ if(nodesx->idata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(nodesx->idata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_NODE);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the node list.
+
+  NodesX *nodesx The set of nodes to modify.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortNodeList(NodesX *nodesx)
+{
+ int fd;
+ index_t xnumber;
+
+ /* Print the start message */
+
+ printf_first("Sorting Nodes");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Open a file for the index */
+
+ nodesx->ifd=OpenFileBufferedNew(nodesx->ifilename_tmp);
+
+ /* Sort the nodes by ID and index them */
+
+ xnumber=nodesx->number;
+
+ sortnodesx=nodesx;
+
+ 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);
+
+ nodesx->knumber=nodesx->number;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ nodesx->ifd=CloseFileBuffered(nodesx->ifd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Nodes: Nodes=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-nodesx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the nodes into id order.
+
+  int sort_by_id Returns the comparison of the id fields.
+
+  NodeX *a The first extended node.
+
+  NodeX *b The second extended node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_id(NodeX *a,NodeX *b)
+{
+ node_t a_id=a->id;
+ node_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 */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index of identifiers and discard duplicate nodes.
+
+  int deduplicate_and_index_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  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)
+{
+ static node_t previd; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || nodex->id!=previd)
+   {
+    previd=nodex->id;
+
+    if(nodex->flags&NODE_DELETED)
+       return(0);
+    else
+      {
+       WriteFileBuffered(sortnodesx->ifd,&nodex->id,sizeof(node_t));
+
+       return(1);
+      }
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove any nodes that are not part of a highway.
+
+  NodesX *nodesx The set of nodes to modify.
+
+  WaysX *waysx The set of ways to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
+{
+ BitMask *usednode;
+ NodeX nodex;
+ index_t i,total=0,highway=0,nothighway=0;
+ node_t bitmasklength;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Checking Ways for unused Nodes: Ways=0 Highway Nodes=0");
+
+ /* Re-open the file read-only */
+
+ waysx->fd=ReOpenFileBuffered(waysx->filename_tmp);
+
+ /* Map the index into memory */
+
+ nodesx->idata=MapFile(nodesx->ifilename_tmp);
+
+ /* Allocate the node usage bitmask */
+
+#if SLIM
+ bitmasklength=nodesx->number;                     /* The number of nodes in the database */
+#else
+ bitmasklength=nodesx->idata[nodesx->number-1]+1;  /* One more than the highest OSM node number in the database */
+#endif
+
+ usednode=AllocBitMask(bitmasklength);
+ log_malloc(usednode,SizeBitMask(bitmasklength));
+
+ /* Loop through the ways and mark the used nodes */
+
+ for(i=0;i<waysx->number;i++)
+   {
+    WayX wayx;
+    FILESORT_VARINT waysize;
+    node_t node;
+
+    ReadFileBuffered(waysx->fd,&waysize,FILESORT_VARSIZE);
+
+    ReadFileBuffered(waysx->fd,&wayx,sizeof(WayX));
+
+    while(!ReadFileBuffered(waysx->fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
+      {
+#if SLIM
+       index_t index=IndexNodeX(nodesx,node); /* Index bitmap by node number in the database */
+#else
+       node_t index=node;                     /* Index bitmap by OSM node number */
+#endif
+
+       waysize-=sizeof(node_t);
+
+#if SLIM
+       if(index==NO_NODE)
+          continue;
+#endif
+
+       if(!IsBitSet(usednode,index))
+          highway++;
+
+       SetBit(usednode,index);
+      }
+
+    waysize-=sizeof(node_t)+sizeof(WayX);
+
+    SkipFileBuffered(waysx->fd,waysize);
+
+    if(!((i+1)%1000))
+       printf_middle("Checking Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,i+1,highway);
+   }
+
+ /* Close the file */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+
+ /* Unmap the index from memory */
+
+ nodesx->idata=UnmapFile(nodesx->idata);
+
+ /* Print the final message */
+
+ printf_last("Checked Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,waysx->number,highway);
+
+
+ /* Print the start message */
+
+ printf_first("Removing unused Nodes: Nodes=0");
+
+ /* Open a file for the index */
+
+ nodesx->ifd=OpenFileBufferedNew(nodesx->ifilename_tmp);
+
+ highway=0;
+
+ /* Re-open the file read-only and a new file writeable */
+
+ if(keep)
+   {
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+
+    nodesx->fd=ReOpenFileBuffered(nodesx->filename);
+
+    fd=OpenFileBufferedNew(nodesx->filename_tmp);
+   }
+ else
+    fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+#if SLIM
+    index_t node=total;         /* Index by node number in the database */
+#else
+    node_t node=nodex.id;       /* Index by OSM node number */
+#endif
+
+    if(!IsBitSet(usednode,node))
+       nothighway++;
+    else
+      {
+       WriteFileBuffered(fd,&nodex,sizeof(NodeX));
+
+       WriteFileBuffered(nodesx->ifd,&nodex.id,sizeof(node_t));
+
+       highway++;
+      }
+
+    total++;
+
+    if(!(total%10000))
+       printf_middle("Removing unused Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+   }
+
+ nodesx->number=highway;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ nodesx->ifd=CloseFileBuffered(nodesx->ifd);
+
+ /* Free the now-unneeded index */
+
+ log_free(usednode);
+ free(usednode);
+
+ /* Print the final message */
+
+ printf_last("Removed unused Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove any nodes that have been pruned.
+
+  NodesX *nodesx The set of nodes to prune.
+
+  SegmentsX *segmentsx The set of segments to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx)
+{
+ NodeX nodex;
+ index_t total=0,pruned=0,notpruned=0;
+ int fd;
+
+ if(nodesx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Deleting Pruned Nodes: Nodes=0 Pruned=0");
+
+ /* Allocate the array of indexes */
+
+ nodesx->pdata=(index_t*)malloc_logassert(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->pdata,nodesx->number*sizeof(index_t));
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+    if(segmentsx->firstnode[total]==NO_SEGMENT)
+      {
+       pruned++;
+
+       nodesx->pdata[total]=NO_NODE;
+      }
+    else
+      {
+       nodesx->pdata[total]=notpruned;
+
+       WriteFileBuffered(fd,&nodex,sizeof(NodeX));
+
+       notpruned++;
+      }
+
+    total++;
+
+    if(!(total%10000))
+       printf_middle("Deleting Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+   }
+
+ nodesx->number=notpruned;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Free the no-longer required memory */
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+    segmentsx->firstnode=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Deleted Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the node list geographically.
+
+  NodesX *nodesx The set of nodes to modify.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortNodeListGeographically(NodesX *nodesx)
+{
+ int fd;
+ ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
+
+ if(nodesx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Nodes Geographically");
+
+ /* Work out the range of data */
+
+ lat_min=radians_to_latlong( 2);
+ lat_max=radians_to_latlong(-2);
+ lon_min=radians_to_latlong( 4);
+ lon_max=radians_to_latlong(-4);
+
+ /* Allocate the memory for the geographical index array */
+
+ nodesx->gdata=(index_t*)malloc_logassert(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->gdata,nodesx->number*sizeof(index_t));
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Sort nodes geographically and index them */
+
+ sortnodesx=nodesx;
+
+ filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(void*,index_t))update_id,
+                                            (int (*)(const void*,const void*))sort_by_lat_long,
+                                            (int (*)(void*,index_t))index_by_lat_long);
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Work out the number of bins */
+
+ if(nodesx->super)
+   {
+    lat_min_bin=latlong_to_bin(lat_min);
+    lon_min_bin=latlong_to_bin(lon_min);
+    lat_max_bin=latlong_to_bin(lat_max);
+    lon_max_bin=latlong_to_bin(lon_max);
+
+    nodesx->latzero=lat_min_bin;
+    nodesx->lonzero=lon_min_bin;
+
+    nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
+    nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
+   }
+
+ /* Free the memory */
+
+ if(nodesx->super)
+   {
+    log_free(nodesx->super);
+    free(nodesx->super);
+    nodesx->super=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Sorted Nodes Geographically: Nodes=%"Pindex_t,nodesx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the node ids.
+
+  int update_id Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  index_t index The number of unsorted nodes that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int update_id(NodeX *nodex,index_t index)
+{
+ nodex->id=index;
+
+ if(sortnodesx->super && IsBitSet(sortnodesx->super,index))
+    nodex->flags|=NODE_SUPER;
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  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).
+
+  int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
+
+  NodeX *a The first extended node.
+
+  NodeX *b The second extended node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_lat_long(NodeX *a,NodeX *b)
+{
+ ll_bin_t a_lon=latlong_to_bin(a->longitude);
+ ll_bin_t b_lon=latlong_to_bin(b->longitude);
+
+ 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);
+
+    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(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index between the sorted and unsorted nodes.
+
+  int index_by_lat_long Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  index_t index The number of sorted nodes that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int index_by_lat_long(NodeX *nodex,index_t index)
+{
+ sortnodesx->gdata[nodex->id]=index;
+
+ if(sortnodesx->super)
+   {
+    if(nodex->latitude<lat_min)
+       lat_min=nodex->latitude;
+    if(nodex->latitude>lat_max)
+       lat_max=nodex->latitude;
+    if(nodex->longitude<lon_min)
+       lon_min=nodex->longitude;
+    if(nodex->longitude>lon_max)
+       lon_max=nodex->longitude;
+   }
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the final node list database to a file.
+
+  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,SegmentsX *segmentsx)
+{
+ index_t i;
+ int fd;
+ NodesFile nodesfile={0};
+ index_t super_number=0;
+ ll_bin2_t latlonbin=0,maxlatlonbins;
+ index_t *offsets;
+
+ /* Print the start message */
+
+ printf_first("Writing Nodes: Nodes=0");
+
+ /* Allocate the memory for the geographical offsets array */
+
+ offsets=(index_t*)malloc_logassert((nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ latlonbin=0;
+
+ /* Re-open the file */
+
+ nodesx->fd=ReOpenFileBuffered(nodesx->filename_tmp);
+
+ /* Write out the nodes data */
+
+ fd=OpenFileBufferedNew(filename);
+
+ SeekFileBuffered(fd,sizeof(NodesFile)+(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ for(i=0;i<nodesx->number;i++)
+   {
+    NodeX nodex;
+    Node node={0};
+    ll_bin_t latbin,lonbin;
+    ll_bin2_t llbin;
+
+    ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
+
+    /* Create the Node */
+
+    node.latoffset=latlong_to_off(nodex.latitude);
+    node.lonoffset=latlong_to_off(nodex.longitude);
+    node.firstseg=segmentsx->firstnode[i];
+    node.allow=nodex.allow;
+    node.flags=nodex.flags;
+
+    if(node.flags&NODE_SUPER)
+       super_number++;
+
+    /* Work out the offsets */
+
+    latbin=latlong_to_bin(nodex.latitude )-nodesx->latzero;
+    lonbin=latlong_to_bin(nodex.longitude)-nodesx->lonzero;
+    llbin=lonbin*nodesx->latbins+latbin;
+
+    for(;latlonbin<=llbin;latlonbin++)
+       offsets[latlonbin]=i;
+
+    /* Write the data */
+
+    WriteFileBuffered(fd,&node,sizeof(Node));
+
+    if(!((i+1)%10000))
+       printf_middle("Writing Nodes: Nodes=%"Pindex_t,i+1);
+   }
+
+ /* Close the file */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+
+ /* Finish off the offset indexing and write them out */
+
+ maxlatlonbins=nodesx->latbins*nodesx->lonbins;
+
+ for(;latlonbin<=maxlatlonbins;latlonbin++)
+    offsets[latlonbin]=nodesx->number;
+
+ SeekFileBuffered(fd,sizeof(NodesFile));
+ WriteFileBuffered(fd,offsets,(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ free(offsets);
+
+ /* Write out the header structure */
+
+ nodesfile.number=nodesx->number;
+ nodesfile.snumber=super_number;
+
+ nodesfile.latbins=nodesx->latbins;
+ nodesfile.lonbins=nodesx->lonbins;
+
+ nodesfile.latzero=nodesx->latzero;
+ nodesfile.lonzero=nodesx->lonzero;
+
+ SeekFileBuffered(fd,0);
+ WriteFileBuffered(fd,&nodesfile,sizeof(NodesFile));
+
+ CloseFileBuffered(fd);
+
+ /* Free the memory in the segments */
+
+ log_free(segmentsx->firstnode);
+ free(segmentsx->firstnode);
+ segmentsx->firstnode=NULL;
+
+ /* Print the final message */
+
+ printf_last("Wrote Nodes: Nodes=%"Pindex_t,nodesx->number);
+}


=====================================
src/files.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2024 Andrew M. Bishop
+ This file Copyright 2008-2015, 2024, 2025 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
@@ -63,10 +63,10 @@
 /*+ A structure to contain the list of memory mapped files. +*/
 struct mmapinfo
 {
- const char  *filename;         /*+ The name of the file (the index of the list). +*/
-       int    fd;               /*+ The file descriptor used when it was opened. +*/
-       char  *address;          /*+ The address the file was mapped to. +*/
-       size_t length;           /*+ The length of the file. +*/
+ char  *filename;         /*+ The name of the file (the index of the list). +*/
+ int    fd;               /*+ The file descriptor used when it was opened. +*/
+ char  *address;          /*+ The address the file was mapped to. +*/
+ size_t length;           /*+ The length of the file. +*/
 };
 
 /*+ The list of memory mapped files. +*/
@@ -81,10 +81,14 @@ static int nmappedfiles=0;
 /*+ A structure to contain the list of file buffers. +*/
 struct filebuffer
 {
- char   buffer[BUFFLEN];        /*+ The data buffer. +*/
- size_t pointer;                /*+ The read/write pointer for the file buffer. +*/
- size_t length;                 /*+ The read pointer for the file buffer. +*/
- int    reading;                /*+ A flag to indicate if the file is for reading. +*/
+ char   buffer[BUFFLEN];   /*+ The data buffer. +*/
+ size_t pointer;           /*+ The read/write pointer for the file buffer. +*/
+ size_t length;            /*+ The read pointer for the file buffer. +*/
+ int    reading;           /*+ A flag to indicate if the file is for reading. +*/
+ char  *filename;          /*+ The name of the file. +*/
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ int    delete;            /*+ Set to non-zero value if the file is to be deleted when closed. +*/
+#endif
 };
 
 /*+ The list of file buffers. +*/
@@ -94,33 +98,9 @@ static struct filebuffer **filebuffers=NULL;
 static int nfilebuffers=0;
 
 
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
-/*+ A structure to contain the list of opened files to record which are to be deleted when closed. +*/
-struct openedfile
-{
- const char *filename;          /*+ The name of the file. +*/
-       int   delete;            /*+ Set to non-zero value if the file is to be deleted when closed. +*/
-};
-
-/*+ The list of opened files. +*/
-static struct openedfile **openedfiles=NULL;
-
-/*+ The number of allocated opened file buffer pointers. +*/
-static int nopenedfiles=0;
-
-#endif
-
-
 /* Local functions */
 
-static void CreateFileBuffer(int fd,int read_write);
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
-static void CreateOpenedFile(int fd,const char *filename);
-
-#endif
+static void CreateFileBuffer(int fd,int read_write,const char *filename);
 
 
 /*++++++++++++++++++++++++++++++++++++++
@@ -173,8 +153,7 @@ void *MapFile(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -185,8 +164,7 @@ void *MapFile(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot stat file '%s' [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -203,8 +181,7 @@ void *MapFile(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot mmap file '%s' for reading [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot mmap file '%s' for reading [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -216,7 +193,7 @@ void *MapFile(const char *filename)
 
  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
 
- mappedfiles[nmappedfiles].filename=filename;
+ mappedfiles[nmappedfiles].filename=strcpy(malloc(strlen(filename)+1),filename);
  mappedfiles[nmappedfiles].fd=fd;
  mappedfiles[nmappedfiles].address=address;
  mappedfiles[nmappedfiles].length=size;
@@ -255,8 +232,7 @@ void *MapFileWriteable(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading and writing [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -267,8 +243,7 @@ void *MapFileWriteable(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot stat file '%s' [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -285,8 +260,7 @@ void *MapFileWriteable(const char *filename)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"Cannot mmap file '%s' for reading and writing [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot mmap file '%s' for reading and writing [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -298,7 +272,7 @@ void *MapFileWriteable(const char *filename)
 
  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
 
- mappedfiles[nmappedfiles].filename=filename;
+ mappedfiles[nmappedfiles].filename=strcpy(malloc(strlen(filename)+1),filename);
  mappedfiles[nmappedfiles].fd=fd;
  mappedfiles[nmappedfiles].address=address;
  mappedfiles[nmappedfiles].length=size;
@@ -330,8 +304,7 @@ void *UnmapFile(const void *address)
 #ifdef LIBROUTINO
     return(NULL);
 #else
-    fprintf(stderr,"The data at address %p was not mapped using MapFile().\n",address);
-    exit(EXIT_FAILURE);
+    logassert_format(0,("The data at address %p was not mapped using MapFile() - report a bug.",address));
 #endif
    }
 
@@ -339,6 +312,8 @@ void *UnmapFile(const void *address)
 
  close(mappedfiles[i].fd);
 
+ free(mappedfiles[i].filename);
+
  /* Unmap the file */
 
  munmap(mappedfiles[i].address,mappedfiles[i].length);
@@ -383,13 +358,10 @@ int SlimMapFile(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading [%s].",filename,strerror(errno)));
 #endif
    }
 
- CreateFileBuffer(fd,0);
-
  return(fd);
 }
 
@@ -419,13 +391,10 @@ int SlimMapFileWriteable(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading and writing [%s].",filename,strerror(errno)));
 #endif
    }
 
- CreateFileBuffer(fd,0);
-
  return(fd);
 }
 
@@ -471,16 +440,11 @@ int OpenFileBufferedNew(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for writing [%s].",filename,strerror(errno)));
 #endif
    }
 
- CreateFileBuffer(fd,-1);
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
- CreateOpenedFile(fd,filename);
-#endif
+ CreateFileBuffer(fd,-1,filename);
 
  return(fd);
 }
@@ -511,16 +475,11 @@ int OpenFileBufferedAppend(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for appending [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for appending [%s].",filename,strerror(errno)));
 #endif
    }
 
- CreateFileBuffer(fd,-1);
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
- CreateOpenedFile(fd,filename);
-#endif
+ CreateFileBuffer(fd,-1,filename);
 
  return(fd);
 }
@@ -551,16 +510,11 @@ int ReOpenFileBuffered(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading [%s].",filename,strerror(errno)));
 #endif
    }
 
- CreateFileBuffer(fd,1);
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
- CreateOpenedFile(fd,filename);
-#endif
+ CreateFileBuffer(fd,1,filename);
 
  return(fd);
 }
@@ -592,13 +546,13 @@ int ReplaceFileBuffered(const char *filename,int *oldfd)
 
  *oldfd=ReOpenFileBuffered(filename2);
  
- DeleteFile(filename2);
+ DeleteFileBuffered(filename2);
 
 #else
 
  *oldfd=ReOpenFileBuffered(filename);
  
- DeleteFile(filename);
+ DeleteFileBuffered(filename);
 
 #endif
 
@@ -635,7 +589,13 @@ int WriteFileBuffered(int fd,const void *address,size_t length)
  if((filebuffers[fd]->pointer+length)>BUFFLEN)
    {
     if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+      {
+#ifdef LIBROUTINO
        return(-1);
+#else
+       logassert_format(0,("Cannot write to file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
 
     filebuffers[fd]->pointer=0;
    }
@@ -643,7 +603,13 @@ int WriteFileBuffered(int fd,const void *address,size_t length)
  if(length>=BUFFLEN)
    {
     if(write(fd,address,length)!=(ssize_t)length)
+      {
+#ifdef LIBROUTINO
        return(-1);
+#else
+       logassert_format(0,("Cannot write to file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
 
     return(0);
    }
@@ -695,7 +661,13 @@ int ReadFileBuffered(int fd,void *address,size_t length)
  if(length>=BUFFLEN)
    {
     if(read(fd,address,length)!=(ssize_t)length)
+      {
+#ifdef LIBROUTINO
        return(-1);
+#else
+       logassert_format(0,("Cannot read from file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
 
     return(0);
    }
@@ -704,7 +676,15 @@ int ReadFileBuffered(int fd,void *address,size_t length)
    {
     ssize_t len=read(fd,filebuffers[fd]->buffer,BUFFLEN);
 
-    if(len<=0)
+    if(len<0)
+      {
+#ifdef LIBROUTINO
+       return(-1);
+#else
+       logassert_format(0,("Cannot read from file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
+    else if(len==0)
        return(-1);
 
     filebuffers[fd]->length=len;
@@ -744,13 +724,25 @@ int SeekFileBuffered(int fd,offset_t position)
 
  if(!filebuffers[fd]->reading)
     if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+      {
+#ifdef LIBROUTINO
        return(-1);
+#else
+       logassert_format(0,("Cannot write to file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
 
  filebuffers[fd]->pointer=0;
  filebuffers[fd]->length=0;
 
  if(lseek(fd,position,SEEK_SET)!=position)
+   {
+#ifdef LIBROUTINO
     return(-1);
+#else
+    logassert_format(0,("Cannot seek in file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+   }
 
  return(0);
 }
@@ -786,7 +778,13 @@ int SkipFileBuffered(int fd,offset_t skip)
     filebuffers[fd]->length=0;
 
     if(lseek(fd,skip,SEEK_CUR)==-1)
+      {
+#ifdef LIBROUTINO
        return(-1);
+#else
+       logassert_format(0,("Cannot seek in file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
    }
  else
     filebuffers[fd]->pointer+=skip;
@@ -795,6 +793,115 @@ int SkipFileBuffered(int fd,offset_t skip)
 }
 
 
+/*++++++++++++++++++++++++++++++++++++++
+  Close a file on disk (and flush the buffer).
+
+  int CloseFileBuffered returns -1 (for similarity to the *OpenFileBuffered* functions).
+
+  int fd The file descriptor to close.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int CloseFileBuffered(int fd)
+{
+#ifndef LIBROUTINO
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+#endif
+
+ if(!filebuffers[fd]->reading)
+    if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+      {
+#ifdef LIBROUTINO
+       return(-1);
+#else
+       logassert_format(0,("Cannot write to file '%s' [%s].",filebuffers[fd]->filename,strerror(errno)));
+#endif
+      }
+
+ close(fd);
+
+ /* Delete the file if Windows */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ if(filebuffers[fd]->delete)
+    unlink(filebuffers[fd]->filename);
+#endif
+
+ /* Free the file buffer */
+
+ free(filebuffers[fd]->filename);
+ free(filebuffers[fd]);
+ filebuffers[fd]=NULL;
+
+ return(-1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a file buffer.
+
+  int fd The file descriptor.
+
+  int read_write A flag set to 1 for reading, -1 for writing and 0 for unbuffered.
+
+  const char *filename The name of the file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void CreateFileBuffer(int fd,int read_write,const char *filename)
+{
+ if(nfilebuffers<=fd)
+   {
+    int i;
+
+    filebuffers=(struct filebuffer**)realloc((void*)filebuffers,(fd+1)*sizeof(struct filebuffer*));
+
+    for(i=nfilebuffers;i<=fd;i++)
+       filebuffers[i]=NULL;
+
+    nfilebuffers=fd+1;
+   }
+
+ filebuffers[fd]=(struct filebuffer*)calloc(1,sizeof(struct filebuffer));
+
+ filebuffers[fd]->reading=(read_write==1);
+
+ filebuffers[fd]->filename=strcpy(malloc(strlen(filename)+1),filename);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ filebuffers[fd]->delete=0;
+#endif
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete a file from disk.
+
+  int DeleteFileBuffered Returns 0 if OK.
+
+  const char *filename The name of the file to delete.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int DeleteFileBuffered(const char *filename)
+{
+ int fd;
+
+ for(fd=0;fd<nfilebuffers;fd++)
+    if(filebuffers[fd] && !strcmp(filebuffers[fd]->filename,filename))
+       break;
+
+#ifndef LIBROUTINO
+ logassert_format(fd<nfilebuffers && filebuffers[fd],("File '%s' is not buffered - report a bug.",filebuffers[fd]->filename));
+#endif
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ filebuffers[fd]->delete=1;
+#else
+ unlink(filename);
+#endif
+
+ return(0);
+}
+
+
 /*++++++++++++++++++++++++++++++++++++++
   Get the size of a file.
 
@@ -812,8 +919,7 @@ offset_t SizeFile(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot stat file '%s' [%s].",filename,strerror(errno)));
 #endif
    }
 
@@ -838,8 +944,7 @@ offset_t SizeFileFD(int fd)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot stat file descriptor '%d' [%s].\n",fd,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot stat file descriptor '%d' [%s].",fd,strerror(errno)));
 #endif
    }
 
@@ -866,47 +971,6 @@ int ExistsFile(const char *filename)
 }
 
 
-/*++++++++++++++++++++++++++++++++++++++
-  Close a file on disk (and flush the buffer).
-
-  int CloseFileBuffered returns -1 (for similarity to the *OpenFileBuffered* functions).
-
-  int fd The file descriptor to close.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-int CloseFileBuffered(int fd)
-{
-#ifndef LIBROUTINO
- logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
-#endif
-
- if(!filebuffers[fd]->reading)
-    if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
-       return(-1);
-
- close(fd);
-
- free(filebuffers[fd]);
- filebuffers[fd]=NULL;
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
-#ifndef LIBROUTINO
- logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
-#endif
-
- if(openedfiles[fd]->delete)
-    unlink(openedfiles[fd]->filename);
-
- free(openedfiles[fd]);
- openedfiles[fd]=NULL;
-
-#endif
-
- return(-1);
-}
-
-
 /*++++++++++++++++++++++++++++++++++++++
   Open an existing file on disk for reading (in a simple mode).
 
@@ -932,15 +996,10 @@ int OpenFile(const char *filename)
 #ifdef LIBROUTINO
     return(-1);
 #else
-    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
-    exit(EXIT_FAILURE);
+    logassert_format(0,("Cannot open file '%s' for reading [%s].",filename,strerror(errno)));
 #endif
    }
 
-#if defined(_MSC_VER) || defined(__MINGW32__)
- CreateOpenedFile(fd,filename);
-#endif
-
  return(fd);
 }
 
@@ -953,26 +1012,16 @@ int OpenFile(const char *filename)
 
 void CloseFile(int fd)
 {
- close(fd);
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
 #ifndef LIBROUTINO
- logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
+ logassert_format(fd>=nfilebuffers || !filebuffers[fd],("File '%s' is buffered - report a bug.",filebuffers[fd]->filename));
 #endif
 
- if(openedfiles[fd]->delete)
-    unlink(openedfiles[fd]->filename);
-
- free(openedfiles[fd]);
- openedfiles[fd]=NULL;
-
-#endif
+ close(fd);
 }
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Delete a file from disk.
+  Delete a file from disk (that was opened in simple mode).
 
   int DeleteFile Returns 0 if OK.
 
@@ -981,17 +1030,14 @@ void CloseFile(int fd)
 
 int DeleteFile(const char *filename)
 {
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
  int fd;
 
- for(fd=0;fd<nopenedfiles;fd++)
-    if(openedfiles[fd] && !strcmp(openedfiles[fd]->filename,filename))
-      {
-       openedfiles[fd]->delete=1;
-       return(0);
-      }
+ for(fd=0;fd<nfilebuffers;fd++)
+    if(filebuffers[fd] && !strcmp(filebuffers[fd]->filename,filename))
+       break;
 
+#ifndef LIBROUTINO
+ logassert_format(fd==nfilebuffers || !filebuffers[fd],("File '%s' is buffered - report a bug.",filebuffers[fd]->filename));
 #endif
 
  unlink(filename);
@@ -1016,67 +1062,3 @@ int RenameFile(const char *oldfilename,const char *newfilename)
 
  return(0);
 }
-
-
-/*++++++++++++++++++++++++++++++++++++++
-  Create a file buffer.
-
-  int fd The file descriptor.
-
-  int read_write A flag set to 1 for reading, -1 for writing and 0 for unbuffered.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-static void CreateFileBuffer(int fd,int read_write)
-{
- if(nfilebuffers<=fd)
-   {
-    int i;
-
-    filebuffers=(struct filebuffer**)realloc((void*)filebuffers,(fd+1)*sizeof(struct filebuffer*));
-
-    for(i=nfilebuffers;i<=fd;i++)
-       filebuffers[i]=NULL;
-
-    nfilebuffers=fd+1;
-   }
-
- if(read_write)
-   {
-    filebuffers[fd]=(struct filebuffer*)calloc(1,sizeof(struct filebuffer));
-
-    filebuffers[fd]->reading=(read_write==1);
-   }
-}
-
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
-/*++++++++++++++++++++++++++++++++++++++
-  Create an opened file record.
-
-  int fd The file descriptor.
-
-  const char *filename The name of the file.
-  ++++++++++++++++++++++++++++++++++++++*/
-
-static void CreateOpenedFile(int fd,const char *filename)
-{
- if(nopenedfiles<=fd)
-   {
-    int i;
-
-    openedfiles=(struct openedfile**)realloc((void*)openedfiles,(fd+1)*sizeof(struct openedfile*));
-
-    for(i=nopenedfiles;i<=fd;i++)
-       openedfiles[i]=NULL;
-
-    nopenedfiles=fd+1;
-   }
-
- openedfiles[fd]=(struct openedfile*)calloc(sizeof(struct openedfile),1);
-
- openedfiles[fd]->filename=strcpy(malloc(strlen(filename)+1),filename);
- openedfiles[fd]->delete=0;
-}
-
-#endif


=====================================
src/files.h
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2019 Andrew M. Bishop
+ This file Copyright 2008-2015, 2019, 2025 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
@@ -65,6 +65,8 @@ typedef int64_t offset_t;
 
 char *FileName(const char *dirname,const char *prefix, const char *name);
 
+/* Functions in files.c for mapped files */
+
 void *MapFile(const char *filename);
 void *MapFileWriteable(const char *filename);
 
@@ -75,6 +77,8 @@ int SlimMapFileWriteable(const char *filename);
 
 int SlimUnmapFile(int fd);
 
+/* Functions in files.c for buffered files */
+
 int OpenFileBufferedNew(const char *filename);
 int OpenFileBufferedAppend(const char *filename);
 
@@ -90,16 +94,20 @@ int SkipFileBuffered(int fd,offset_t skip);
 
 int CloseFileBuffered(int fd);
 
+int DeleteFileBuffered(const char *filename);
+
+/* Functions in files.c for simple files */
+
 int OpenFile(const char *filename);
 
 void CloseFile(int fd);
 
+int DeleteFile(const char *filename);
+
 offset_t SizeFile(const char *filename);
 offset_t SizeFileFD(int fd);
 int ExistsFile(const char *filename);
 
-int DeleteFile(const char *filename);
-
 int RenameFile(const char *oldfilename,const char *newfilename);
 
 /* Functions in files.h */


=====================================
src/logerror.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2013, 2015 Andrew M. Bishop
+ This file Copyright 2013, 2015, 2025 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
@@ -75,11 +75,7 @@ void open_errorlog(const char *filename,int append,int bin)
  errorlogfile=fopen(errorlogfilename,append?"a" :"w" );
 #endif
 
- if(!errorlogfile)
-   {
-    fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",errorlogfilename,strerror(errno));
-    exit(EXIT_FAILURE);
-   }
+ logassert_format(errorlogfile,("Cannot open file '%s' for writing [%s].",errorlogfilename,strerror(errno)));
 
  /* Binary log file */
 


=====================================
src/logging.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2019 Andrew M. Bishop
+ This file Copyright 2008-2015, 2019, 2025 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
@@ -590,7 +590,7 @@ static void fprintf_max_memory(FILE *file,size_t max_alloc,size_t max_mmap)
 
 
 /*++++++++++++++++++++++++++++++++++++++
-  Log a fatal error and exit
+  Log a fatal error and exit.
 
   const char *message The error message.
 
@@ -607,6 +607,32 @@ void _logassert(const char *message,const char *file,int line)
 }
 
 
+/*++++++++++++++++++++++++++++++++++++++
+  Create an error message before logging a fatal error and exiting.
+
+  const char *_logassert_format Returns a constant string.
+
+  const char *format The error message format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *_logassert_format(const char *format, ...)
+{
+ static char string[256];
+
+ va_list ap;
+
+ va_start(ap,format);
+
+ vsnprintf(string,sizeof(string),format,ap);
+
+ va_end(ap);
+
+ return(string);
+}
+
+
 /*++++++++++++++++++++++++++++++++++++++
   Allocate some memory by calling calloc() and checking for failures.
 


=====================================
src/logging.h
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2017, 2019 Andrew M. Bishop
+ This file Copyright 2008-2015, 2017, 2019, 2025 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
@@ -106,16 +106,21 @@ relation_t logerror_relation(relation_t id);
 
 /* Runtime fatal error assertion in logging.c */
 
-#define logassert(xx,yy) do { if(!(xx)) _logassert(yy,__FILE__,__LINE__); } while(0)
+#define logassert(xx,yy)        do { if(!(xx)) _logassert(                  yy,__FILE__,__LINE__); } while(0)
+#define logassert_format(xx,yy) do { if(!(xx)) _logassert(_logassert_format yy,__FILE__,__LINE__); } while(0)
 
 #ifdef __GNUC__
 
 void _logassert(const char *message,const char *file,int line) __attribute__ ((noreturn));
 
+const char *_logassert_format(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
 #else
 
 void _logassert(const char *message,const char *file,int line);
 
+const char *_logassert_format(const char *format, ...);
+
 #endif
 
 


=====================================
src/nodesx.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2019, 2020, 2022 Andrew M. Bishop
+ This file Copyright 2008-2015, 2019, 2020, 2022, 2025 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
@@ -71,6 +71,8 @@ NodesX *NewNodeList(int append,int readonly)
 {
  NodesX *nodesx;
 
+ logassert(sizeof(node_t)>=sizeof(index_t),"Size of node_t type must be at least as large as size of index_t type.");
+
  nodesx=(NodesX*)calloc_logassert(1,sizeof(NodesX));
 
  nodesx->filename    =(char*)malloc_logassert(strlen(option_tmpdirname)+32);


=====================================
src/planetsplitter.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2017, 2023 Andrew M. Bishop
+ This file Copyright 2008-2017, 2023, 2025 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
@@ -278,17 +278,18 @@ if(!option_process_only)
 
          if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
            {
-            logassert(0,"Unable to read a PBF file to apply changes (format does not permit this)");
+            fprintf(stderr,"Error: Unable to read a PBF file to apply changes (format does not permit this).\n");
+            exit(EXIT_FAILURE);
            }
          else if((p=strstr(filename,".o5c")) && !strcmp(p,".o5c"))
            {
             if(ParseO5CFile(fd,OSMNodes,OSMWays,OSMRelations))
-               exit(EXIT_FAILURE);
+               exit(EXIT_FAILURE); /* no message because one printed in parser function */
            }
          else
            {
             if(ParseOSCFile(fd,OSMNodes,OSMWays,OSMRelations))
-               exit(EXIT_FAILURE);
+               exit(EXIT_FAILURE); /* no message because one printed in parser function */
            }
         }
       else
@@ -299,17 +300,17 @@ if(!option_process_only)
          if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
            {
             if(ParsePBFFile(fd,OSMNodes,OSMWays,OSMRelations))
-               exit(EXIT_FAILURE);
+               exit(EXIT_FAILURE); /* no message because one printed in parser function */
            }
          else if((p=strstr(filename,".o5m")) && !strcmp(p,".o5m"))
            {
             if(ParseO5MFile(fd,OSMNodes,OSMWays,OSMRelations))
-               exit(EXIT_FAILURE);
+               exit(EXIT_FAILURE); /* no message because one printed in parser function */
            }
          else
            {
             if(ParseOSMFile(fd,OSMNodes,OSMWays,OSMRelations))
-               exit(EXIT_FAILURE);
+               exit(EXIT_FAILURE); /* no message because one printed in parser function */
            }
         }
 


=====================================
src/relationsx.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2015, 2018, 2019, 2020, 2022, 2024 Andrew M. Bishop
+ This file Copyright 2010-2015, 2018, 2019, 2020, 2022, 2024, 2025 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
@@ -75,6 +75,8 @@ RelationsX *NewRelationList(int append,int readonly)
 {
  RelationsX *relationsx;
 
+ logassert(sizeof(relation_t)>=sizeof(index_t),"Size of relation_t type must be at least as large as size of index_t type.");
+
  relationsx=(RelationsX*)calloc_logassert(1,sizeof(RelationsX));
 
 
@@ -1189,7 +1191,7 @@ void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
     relationx.via =nodesx->pdata[relationx.via];
     relationx.to  =nodesx->pdata[relationx.to];
 
-    if(relationx.from==NO_WAY_ID || relationx.via==NO_NODE_ID || relationx.to==NO_WAY_ID)
+    if(relationx.from==NO_WAY || relationx.via==NO_NODE || relationx.to==NO_WAY)
        pruned++;
     else
       {


=====================================
src/router.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2016, 2018 Andrew M. Bishop
+ This file Copyright 2008-2016, 2018, 2025 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
@@ -625,7 +625,7 @@ int main(int argc,char** argv)
     results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);
 
     if(!results[nresults])
-       exit(EXIT_FAILURE);
+       exit(EXIT_FAILURE); /* no message because one printed in route calculator */
 
     join_segment=results[nresults]->last_segment;
 
@@ -648,7 +648,7 @@ int main(int argc,char** argv)
     results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);
 
     if(!results[nresults])
-       exit(EXIT_FAILURE);
+       exit(EXIT_FAILURE); /* no message because one printed in route calculator */
 
     nresults++;
    }


=====================================
src/sorting.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2009-2015, 2017, 2019, 2023 Andrew M. Bishop
+ This file Copyright 2009-2015, 2017, 2019, 2023, 2025 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
@@ -921,7 +921,7 @@ static index_t filesort_merge(int fd_out,int nfiles,size_t itemsize,size_t large
 
     fds[i]=ReOpenFileBuffered(filename);
 
-    DeleteFile(filename);
+    DeleteFileBuffered(filename);
    }
 
  /* Fill the heap to start with */


=====================================
src/uncompress.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2012-2015 Andrew M. Bishop
+ This file Copyright 2012-2015, 2025 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
@@ -96,7 +96,7 @@ int Uncompress_Bzip2(int filefd)
 
 #else /* USE_BZIP2 */
 
- logassert(0,"No bzip2 compression support available (re-compile and try again)");
+ logassert(0,"No bzip2 compression support available (re-compile and try again).");
 
  return(0);
 
@@ -127,7 +127,7 @@ int Uncompress_Gzip(int filefd)
 
 #else /* USE_GZIP */
 
- logassert(0,"No gzip compression support available (re-compile and try again)");
+ logassert(0,"No gzip compression support available (re-compile and try again).");
 
  return(0);
 
@@ -158,7 +158,7 @@ int Uncompress_Xz(int filefd)
 
 #else /* USE_XZ */
 
- logassert(0,"No xz compression support available (re-compile and try again)");
+ logassert(0,"No xz compression support available (re-compile and try again).");
 
  return(0);
 
@@ -264,7 +264,7 @@ static void uncompress_bzip2_pipe(int filefd,int pipefd)
  int state;
 
  if(BZ2_bzDecompressInit(&bz,0,0)!=BZ_OK)
-    exit(EXIT_FAILURE);
+    exit(EXIT_FAILURE); /* no error message because in sub-process */
 
  do
    {
@@ -287,7 +287,7 @@ static void uncompress_bzip2_pipe(int filefd,int pipefd)
     state=BZ2_bzDecompress(&bz);
 
     if(state!=BZ_OK && state!=BZ_STREAM_END)
-       exit(EXIT_FAILURE);
+       exit(EXIT_FAILURE); /* no error message because in sub-process */
 
     if(bz.avail_out<sizeof(outbuffer))
       {
@@ -302,7 +302,7 @@ static void uncompress_bzip2_pipe(int filefd,int pipefd)
           m=write(pipefd,p,n);
 
           if(m<=0)
-             exit(EXIT_FAILURE);
+             exit(EXIT_FAILURE); /* no error message because in sub-process */
 
           p+=m;
           n-=m;
@@ -312,7 +312,7 @@ static void uncompress_bzip2_pipe(int filefd,int pipefd)
  while(state!=BZ_STREAM_END);
 
  if(BZ2_bzDecompressEnd(&bz)!=BZ_OK)
-    exit(EXIT_FAILURE);
+    exit(EXIT_FAILURE); /* no error message because in sub-process */
 
  exit(EXIT_SUCCESS);
 }
@@ -338,7 +338,7 @@ static void uncompress_gzip_pipe(int filefd,int pipefd)
  int state;
 
  if(inflateInit2(&z,15+32)!=Z_OK)
-    exit(EXIT_FAILURE);
+    exit(EXIT_FAILURE); /* no error message because in sub-process */
 
  do
    {
@@ -361,9 +361,7 @@ static void uncompress_gzip_pipe(int filefd,int pipefd)
     state=inflate(&z,Z_NO_FLUSH);
 
     if(state!=Z_OK && state!=Z_STREAM_END)
-      {
-       exit(EXIT_FAILURE);
-      }
+       exit(EXIT_FAILURE); /* no error message because in sub-process */
 
     if(z.avail_out<sizeof(outbuffer))
       {
@@ -378,7 +376,7 @@ static void uncompress_gzip_pipe(int filefd,int pipefd)
           m=write(pipefd,p,n);
 
           if(m<=0)
-             exit(EXIT_FAILURE);
+             exit(EXIT_FAILURE); /* no error message because in sub-process */
 
           p+=m;
           n-=m;
@@ -388,7 +386,7 @@ static void uncompress_gzip_pipe(int filefd,int pipefd)
  while(state!=Z_STREAM_END);
 
  if(inflateEnd(&z)!=Z_OK)
-    exit(EXIT_FAILURE);
+    exit(EXIT_FAILURE); /* no error message because in sub-process */
 
  exit(EXIT_SUCCESS);
 }
@@ -414,7 +412,7 @@ static void uncompress_xz_pipe(int filefd,int pipefd)
  lzma_ret retval;
 
  if(lzma_stream_decoder(&lzma,UINT64_MAX,0)!=LZMA_OK)
-    exit(EXIT_FAILURE);
+    exit(EXIT_FAILURE); /* no error message because in sub-process */
 
  do
    {
@@ -437,9 +435,7 @@ static void uncompress_xz_pipe(int filefd,int pipefd)
     retval=lzma_code(&lzma,LZMA_RUN);
 
     if(retval!=LZMA_OK && retval!=LZMA_STREAM_END)
-      {
-       exit(EXIT_FAILURE);
-      }
+       exit(EXIT_FAILURE); /* no error message because in sub-process */
 
     if(lzma.avail_out<sizeof(outbuffer))
       {
@@ -454,7 +450,7 @@ static void uncompress_xz_pipe(int filefd,int pipefd)
           m=write(pipefd,p,n);
 
           if(m<=0)
-             exit(EXIT_FAILURE);
+             exit(EXIT_FAILURE); /* no error message because in sub-process */
 
           p+=m;
           n-=m;
@@ -465,7 +461,7 @@ static void uncompress_xz_pipe(int filefd,int pipefd)
 
  lzma_end(&lzma);
 
- exit(EXIT_SUCCESS);
+ exit(EXIT_SUCCESS); /* no error message because in sub-process */
 }
 
 #endif /* USE_XZ */


=====================================
src/version.h
=====================================
@@ -23,7 +23,7 @@
 #ifndef VERSION_H
 #define VERSION_H    /*+ To stop multiple inclusions. +*/
 
-#define ROUTINO_VERSION "3.4.2"
+#define ROUTINO_VERSION "3.4.3"
 
 #define ROUTINO_URL     "<http://www.routino.org/>"
 


=====================================
src/waysx.c
=====================================
@@ -3,7 +3,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2008-2015, 2018, 2019, 2020, 2022, 2024 Andrew M. Bishop
+ This file Copyright 2008-2015, 2018, 2019, 2020, 2022, 2024, 2025 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
@@ -73,6 +73,8 @@ WaysX *NewWayList(int append,int readonly)
 {
  WaysX *waysx;
 
+ logassert(sizeof(way_t)>=sizeof(index_t),"Size of way_t type must be at least as large as size of index_t type.");
+
  waysx=(WaysX*)calloc_logassert(1,sizeof(WaysX));
 
  waysx->filename    =(char*)malloc_logassert(strlen(option_tmpdirname)+32);


=====================================
src/xml/xsd-to-xmlparser.c
=====================================
@@ -5,7 +5,7 @@
 
  Part of the Routino routing software.
  ******************/ /******************
- This file Copyright 2010-2015, 2019 Andrew M. Bishop
+ This file Copyright 2010-2015, 2019, 2025 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
@@ -236,7 +236,10 @@ static int elementType_function(const char *_tag_,int _type_,const char *name,co
        tagsx[i]->nsubtagsx++;
 
        if(tagsx[i]->nsubtagsx==XMLPARSE_MAX_SUBTAGS)
-         {fprintf(stderr,"Too many subtags seen for type '%s'.\n",currenttype); exit(1);}
+         {
+          fprintf(stderr,"Error: Too many subtags (%d) seen for type '%s'.\n",XMLPARSE_MAX_SUBTAGS,currenttype);
+          exit(EXIT_FAILURE);
+         }
       }
 
  return(0);
@@ -310,7 +313,10 @@ static int attributeType_function(const char *_tag_,int _type_,const char *name,
        tagsx[i]->nattributes++;
 
        if(tagsx[i]->nattributes==XMLPARSE_MAX_ATTRS)
-         {fprintf(stderr,"Too many attributes seen for type '%s'.\n",currenttype); exit(1);}
+         {
+          fprintf(stderr,"Error: Too many attributes (%d) seen for type '%s'.\n",XMLPARSE_MAX_ATTRS,currenttype);
+          exit(EXIT_FAILURE);
+         }
       }
 
  return(0);
@@ -329,8 +335,8 @@ int main(int argc,char **argv)
 
  if(ParseXML(STDIN_FILENO,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE))
    {
-    fprintf(stderr,"Cannot parse XML file - exiting.\n");
-    exit(1);
+    fprintf(stderr,"Error: Cannot parse XML file - exiting.\n");
+    exit(EXIT_FAILURE);
    }
 
  /* Print the header */



View it on GitLab: https://salsa.debian.org/debian-gis-team/routino/-/compare/db5e4e8ec8d4e81b3e898b73f0aa0fbdf51ba28b...2d74866a50e88c050338bd03e7c00520a91fb035

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/routino/-/compare/db5e4e8ec8d4e81b3e898b73f0aa0fbdf51ba28b...2d74866a50e88c050338bd03e7c00520a91fb035
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20250508/1c2c2dfe/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list