pool: Support NULL pool argument to pool_alloc_unaligned().
[pspp-builds.git] / src / libpspp / pool.c
index 0e6c9358fc828cd10f027c32d9f5750c7ffd5c23..7f3175d477bde1d758f5f358378fa448b30a60ab 100644 (file)
@@ -1,29 +1,32 @@
-/* PSPP - computes sample statistics.
-   Copyright (C) 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2000, 2010, 2011 Free Software Foundation, Inc.
 
 
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU 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
-   General Public License for more details.
+   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 General Public License for more details.
 
    You should have received a copy of the GNU General Public License
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
 
 #include <config.h>
-#include "pool.h"
+
+#include "libpspp/pool.h"
+
+#include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
-#include "alloc.h"
-#include "message.h"
-#include "size_max.h"
-#include "str.h"
+
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/temp-file.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 /* Fast, low-overhead memory block suballocator. */
 struct pool
 
 /* Fast, low-overhead memory block suballocator. */
 struct pool
@@ -34,7 +37,7 @@ struct pool
   };
 
 /* Pool block. */
   };
 
 /* Pool block. */
-struct pool_block 
+struct pool_block
   {
     struct pool_block *prev;
     struct pool_block *next;
   {
     struct pool_block *prev;
     struct pool_block *next;
@@ -46,12 +49,13 @@ enum
   {
     POOL_GIZMO_MALLOC,
     POOL_GIZMO_FILE,
   {
     POOL_GIZMO_MALLOC,
     POOL_GIZMO_FILE,
+    POOL_GIZMO_TEMP_FILE,
     POOL_GIZMO_SUBPOOL,
     POOL_GIZMO_REGISTERED,
   };
 
 /* Pool routines can maintain objects (`gizmos') as well as doing
     POOL_GIZMO_SUBPOOL,
     POOL_GIZMO_REGISTERED,
   };
 
 /* Pool routines can maintain objects (`gizmos') as well as doing
-   suballocation.  
+   suballocation.
    This structure is used to keep track of them. */
 struct pool_gizmo
   {
    This structure is used to keep track of them. */
 struct pool_gizmo
   {
@@ -65,7 +69,7 @@ struct pool_gizmo
     /* Type-dependent info. */
     union
       {
     /* Type-dependent info. */
     union
       {
-       FILE *file;             /* POOL_GIZMO_FILE. */
+       FILE *file;             /* POOL_GIZMO_FILE, POOL_GIZMO_TEMP_FILE. */
        struct pool *subpool;   /* POOL_GIZMO_SUBPOOL. */
 
        /* POOL_GIZMO_REGISTERED. */
        struct pool *subpool;   /* POOL_GIZMO_SUBPOOL. */
 
        /* POOL_GIZMO_REGISTERED. */
@@ -100,8 +104,8 @@ union align
 
 /* DISCRETE_BLOCKS may be declared as nonzero to prevent
    suballocation of blocks.  This is useful under memory
 
 /* DISCRETE_BLOCKS may be declared as nonzero to prevent
    suballocation of blocks.  This is useful under memory
-   debuggers like Checker or valgrind because it allows the
-   source location of bugs to be more accurately pinpointed.
+   debuggers like valgrind because it allows the source location
+   of bugs to be more accurately pinpointed.
 
    On the other hand, if we're testing the library, then we want to
    test the library's real functionality, not its crippled, slow,
 
    On the other hand, if we're testing the library, then we want to
    test the library's real functionality, not its crippled, slow,
@@ -147,7 +151,7 @@ pool_create (void)
   block = xmalloc (BLOCK_SIZE);
   block->prev = block->next = block;
   block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
   block = xmalloc (BLOCK_SIZE);
   block->prev = block->next = block;
   block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
-  
+
   pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
   pool->parent = NULL;
   pool->blocks = block;
   pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
   pool->parent = NULL;
   pool->blocks = block;
@@ -163,7 +167,7 @@ pool_create (void)
 
    Meant for use indirectly via pool_create_container(). */
 void *
 
    Meant for use indirectly via pool_create_container(). */
 void *
-pool_create_at_offset (size_t struct_size, size_t pool_member_offset) 
+pool_create_at_offset (size_t struct_size, size_t pool_member_offset)
 {
   struct pool *pool;
   char *struct_;
 {
   struct pool *pool;
   char *struct_;
@@ -185,9 +189,9 @@ pool_destroy (struct pool *pool)
     return;
 
   /* Remove this pool from its parent's list of gizmos. */
     return;
 
   /* Remove this pool from its parent's list of gizmos. */
-  if (pool->parent) 
+  if (pool->parent)
     delete_gizmo (pool->parent, (void *) (((char *) pool) + POOL_SIZE));
     delete_gizmo (pool->parent, (void *) (((char *) pool) + POOL_SIZE));
-  
+
   free_all_gizmos (pool);
 
   /* Free all the memory. */
   free_all_gizmos (pool);
 
   /* Free all the memory. */
@@ -205,25 +209,25 @@ pool_destroy (struct pool *pool)
 
 /* Release all the memory and gizmos in POOL.
    Blocks are not given back with free() but kept for later
 
 /* Release all the memory and gizmos in POOL.
    Blocks are not given back with free() but kept for later
-   allocations.  To give back memory, use a subpool instead. */ 
+   allocations.  To give back memory, use a subpool instead. */
 void
 void
-pool_clear (struct pool *pool) 
+pool_clear (struct pool *pool)
 {
   free_all_gizmos (pool);
 
   /* Zero out block sizes. */
   {
     struct pool_block *cur;
 {
   free_all_gizmos (pool);
 
   /* Zero out block sizes. */
   {
     struct pool_block *cur;
-    
+
     cur = pool->blocks;
     do
       {
         cur->ofs = POOL_BLOCK_SIZE;
     cur = pool->blocks;
     do
       {
         cur->ofs = POOL_BLOCK_SIZE;
-        if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool) 
+        if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
           {
             cur->ofs += POOL_SIZE;
             if (pool->parent != NULL)
           {
             cur->ofs += POOL_SIZE;
             if (pool->parent != NULL)
-              cur->ofs += POOL_GIZMO_SIZE; 
+              cur->ofs += POOL_GIZMO_SIZE;
           }
         cur = cur->next;
       }
           }
         cur = cur->next;
       }
@@ -243,7 +247,7 @@ pool_alloc (struct pool *pool, size_t amt)
 
   if (amt == 0)
     return NULL;
 
   if (amt == 0)
     return NULL;
-  
+
 #ifndef DISCRETE_BLOCKS
   if (amt <= MAX_SUBALLOC)
     {
 #ifndef DISCRETE_BLOCKS
   if (amt <= MAX_SUBALLOC)
     {
@@ -259,7 +263,7 @@ pool_alloc (struct pool *pool, size_t amt)
 
       /* No space in this block, so we must make other
          arrangements. */
 
       /* No space in this block, so we must make other
          arrangements. */
-      if (b->next->ofs == 0) 
+      if (b->next->ofs == 0)
         {
           /* The next block is empty.  Use it. */
           b = b->next;
         {
           /* The next block is empty.  Use it. */
           b = b->next;
@@ -267,7 +271,7 @@ pool_alloc (struct pool *pool, size_t amt)
           if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
             b->ofs += POOL_SIZE;
         }
           if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
             b->ofs += POOL_SIZE;
         }
-      else 
+      else
         {
           /* Create a new block at the start of the list. */
           b = xmalloc (BLOCK_SIZE);
         {
           /* Create a new block at the start of the list. */
           b = xmalloc (BLOCK_SIZE);
@@ -295,13 +299,14 @@ pool_alloc (struct pool *pool, size_t amt)
 void *
 pool_alloc_unaligned (struct pool *pool, size_t amt)
 {
 void *
 pool_alloc_unaligned (struct pool *pool, size_t amt)
 {
-  assert (pool != NULL);
+  if (pool == NULL)
+    return xmalloc (amt);
 
 #ifndef DISCRETE_BLOCKS
   /* Strings need not be aligned on any boundary, but some
      operations may be more efficient when they are.  However,
      that's only going to help with reasonably long strings. */
 
 #ifndef DISCRETE_BLOCKS
   /* Strings need not be aligned on any boundary, but some
      operations may be more efficient when they are.  However,
      that's only going to help with reasonably long strings. */
-  if (amt < ALIGN_SIZE) 
+  if (amt < ALIGN_SIZE)
     {
       if (amt == 0)
         return NULL;
     {
       if (amt == 0)
         return NULL;
@@ -328,7 +333,7 @@ pool_alloc_unaligned (struct pool *pool, size_t amt)
    Terminates the program if the memory cannot be obtained,
    including the case where N * S overflows the range of size_t. */
 void *
    Terminates the program if the memory cannot be obtained,
    including the case where N * S overflows the range of size_t. */
 void *
-pool_nalloc (struct pool *pool, size_t n, size_t s) 
+pool_nalloc (struct pool *pool, size_t n, size_t s)
 {
   if (xalloc_oversized (n, s))
     xalloc_die ();
 {
   if (xalloc_oversized (n, s))
     xalloc_die ();
@@ -360,11 +365,24 @@ pool_clone_unaligned (struct pool *pool, const void *buffer, size_t size)
    the returned pointere may not be aligned properly for other
    types. */
 char *
    the returned pointere may not be aligned properly for other
    types. */
 char *
-pool_strdup (struct pool *pool, const char *string) 
+pool_strdup (struct pool *pool, const char *string)
 {
   return pool_clone_unaligned (pool, string, strlen (string) + 1);
 }
 
 {
   return pool_clone_unaligned (pool, string, strlen (string) + 1);
 }
 
+/* Duplicates the SIZE bytes of STRING, plus a trailing 0 byte,
+   and returns a pointer to the duplicate.  For use only with
+   strings, because the returned pointere may not be aligned
+   properly for other types. */
+char *
+pool_strdup0 (struct pool *pool, const char *string, size_t size)
+{
+  char *new_string = pool_alloc_unaligned (pool, size + 1);
+  memcpy (new_string, string, size);
+  new_string[size] = '\0';
+  return new_string;
+}
+
 /* Formats FORMAT with the given ARGS in memory allocated from
    POOL and returns the formatted string. */
 char *
 /* Formats FORMAT with the given ARGS in memory allocated from
    POOL and returns the formatted string. */
 char *
@@ -382,9 +400,9 @@ pool_vasprintf (struct pool *pool, const char *format, va_list args_)
   needed = vsnprintf (s, avail, format, args);
   va_end (args);
 
   needed = vsnprintf (s, avail, format, args);
   va_end (args);
 
-  if (needed >= 0) 
+  if (needed >= 0)
     {
     {
-      if (needed < avail) 
+      if (needed < avail)
         {
           /* Success.  Reserve the space that was actually used. */
           b->ofs += needed + 1;
         {
           /* Success.  Reserve the space that was actually used. */
           b->ofs += needed + 1;
@@ -400,7 +418,7 @@ pool_vasprintf (struct pool *pool, const char *format, va_list args_)
           va_end (args);
         }
     }
           va_end (args);
         }
     }
-  else 
+  else
     {
       /* Some old libc's returned -1 when the destination string
          was too short.  This should be uncommon these days and
     {
       /* Some old libc's returned -1 when the destination string
          was too short.  This should be uncommon these days and
@@ -423,7 +441,7 @@ pool_asprintf (struct pool *pool, const char *format, ...)
 {
   va_list args;
   char *string;
 {
   va_list args;
   char *string;
-  
+
   va_start (args, format);
   string = pool_vasprintf (pool, format, args);
   va_end (args);
   va_start (args, format);
   string = pool_vasprintf (pool, format, args);
   va_end (args);
@@ -465,13 +483,41 @@ pool_malloc (struct pool *pool, size_t amt)
    Terminates the program if the memory cannot be obtained,
    including the case where N * S overflows the range of size_t. */
 void *
    Terminates the program if the memory cannot be obtained,
    including the case where N * S overflows the range of size_t. */
 void *
-pool_nmalloc (struct pool *pool, size_t n, size_t s) 
+pool_nmalloc (struct pool *pool, size_t n, size_t s)
 {
   if (xalloc_oversized (n, s))
     xalloc_die ();
   return pool_malloc (pool, n * s);
 }
 
 {
   if (xalloc_oversized (n, s))
     xalloc_die ();
   return pool_malloc (pool, n * s);
 }
 
+/* Allocates AMT bytes using malloc(), to be managed by POOL,
+   zeros the block, and returns a pointer to the beginning of the
+   block.
+   If POOL is a null pointer, then allocates a normal memory block
+   with xmalloc().  */
+void *
+pool_zalloc (struct pool *pool, size_t amt)
+{
+  void *p = pool_malloc (pool, amt);
+  memset (p, 0, amt);
+  return p;
+}
+
+/* Allocates and returns N elements of S bytes each, to be
+   managed by POOL, and zeros the block.
+   If POOL is a null pointer, then allocates a normal memory block
+   with malloc().
+   N must be nonnegative, S must be positive.
+   Terminates the program if the memory cannot be obtained,
+   including the case where N * S overflows the range of size_t. */
+void *
+pool_calloc (struct pool *pool, size_t n, size_t s)
+{
+  void *p = pool_nmalloc (pool, n, s);
+  memset (p, 0, n * s);
+  return p;
+}
+
 /* Changes the allocation size of the specified memory block P managed
    by POOL to AMT bytes and returns a pointer to the beginning of the
    block.
 /* Changes the allocation size of the specified memory block P managed
    by POOL to AMT bytes and returns a pointer to the beginning of the
    block.
@@ -657,7 +703,7 @@ pool_create_subpool (struct pool *pool)
 
   g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs);
   subpool->blocks->ofs += POOL_GIZMO_SIZE;
 
   g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs);
   subpool->blocks->ofs += POOL_GIZMO_SIZE;
-  
+
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
 
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
 
@@ -671,14 +717,14 @@ pool_create_subpool (struct pool *pool)
    The subpool will be destroyed automatically when POOL is destroyed.
    It may also be destroyed explicitly in advance. */
 void
    The subpool will be destroyed automatically when POOL is destroyed.
    It may also be destroyed explicitly in advance. */
 void
-pool_add_subpool (struct pool *pool, struct pool *subpool) 
+pool_add_subpool (struct pool *pool, struct pool *subpool)
 {
   struct pool_gizmo *g;
 
   assert (pool != NULL);
   assert (subpool != NULL);
   assert (subpool->parent == NULL);
 {
   struct pool_gizmo *g;
 
   assert (pool != NULL);
   assert (subpool != NULL);
   assert (subpool->parent == NULL);
-  
+
   g = pool_alloc (subpool, sizeof *g);
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
   g = pool_alloc (subpool, sizeof *g);
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
@@ -699,8 +745,8 @@ pool_fopen (struct pool *pool, const char *file_name, const char *mode)
 
   assert (pool && file_name && mode);
   f = fopen (file_name, mode);
 
   assert (pool && file_name && mode);
   f = fopen (file_name, mode);
-  if (f == NULL)
-    return NULL;
+  if (f != NULL)
+    pool_attach_file (pool, f);
 
   return f;
 }
 
   return f;
 }
@@ -715,41 +761,78 @@ pool_fclose (struct pool *pool, FILE *file)
   return fclose (file);
 }
 
   return fclose (file);
 }
 
-/* Creates a temporary file with tmpfile() and returns a handle to it
-   if successful or a null pointer if not.
+/* Attaches FILE to POOL.
    The file will be closed automatically when POOL is destroyed, or it
    may be closed explicitly in advance using pool_fclose(), or
    detached from the pool with pool_detach_file(). */
    The file will be closed automatically when POOL is destroyed, or it
    may be closed explicitly in advance using pool_fclose(), or
    detached from the pool with pool_detach_file(). */
+void
+pool_attach_file (struct pool *pool, FILE *file)
+{
+  struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
+  g->type = POOL_GIZMO_FILE;
+  g->p.file = file;
+  add_gizmo (pool, g);
+}
+
+/* Detaches FILE from POOL. */
+void
+pool_detach_file (struct pool *pool, FILE *file)
+{
+  struct pool_gizmo *g;
+
+  for (g = pool->gizmos; g; g = g->next)
+    if (g->type == POOL_GIZMO_FILE && g->p.file == file)
+      {
+        delete_gizmo (pool, g);
+        return;
+      }
+}
+
+/* Creates a temporary file with create_temp_file() and returns a handle to it
+   if successful or a null pointer if not.
+   The file will be closed automatically when POOL is destroyed, or it
+   may be closed explicitly in advance using pool_fclose_temp_file(), or
+   detached from the pool with pool_detach_temp_file(). */
 FILE *
 FILE *
-pool_tmpfile (struct pool *pool) 
+pool_create_temp_file (struct pool *pool)
 {
 {
-  FILE *file = tmpfile ();
+  FILE *file = create_temp_file ();
   if (file != NULL)
   if (file != NULL)
-    pool_attach_file (pool, file);
+    pool_attach_temp_file (pool, file);
   return file;
 }
 
   return file;
 }
 
-/* Attaches FILE to POOL.
+/* Closes file FILE managed by POOL.
+   FILE must have been opened with create_temp_file(). */
+void
+pool_fclose_temp_file (struct pool *pool, FILE *file)
+{
+  assert (pool && file);
+  pool_detach_temp_file (pool, file);
+  close_temp_file (file);
+}
+
+/* Attaches FILE, which must have been opened with create_temp_file(), to POOL.
    The file will be closed automatically when POOL is destroyed, or it
    The file will be closed automatically when POOL is destroyed, or it
-   may be closed explicitly in advance using pool_fclose(), or
-   detached from the pool with pool_detach_file(). */
+   may be closed explicitly in advance using pool_fclose_temp_file(), or
+   detached from the pool with pool_detach_temp_file(). */
 void
 void
-pool_attach_file (struct pool *pool, FILE *file)
+pool_attach_temp_file (struct pool *pool, FILE *file)
 {
   struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
 {
   struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
-  g->type = POOL_GIZMO_FILE;
+  g->type = POOL_GIZMO_TEMP_FILE;
   g->p.file = file;
   add_gizmo (pool, g);
 }
 
   g->p.file = file;
   add_gizmo (pool, g);
 }
 
-/* Detaches FILE from POOL. */
+/* Detaches FILE that was opened with create_temp_file() from POOL. */
 void
 void
-pool_detach_file (struct pool *pool, FILE *file)
+pool_detach_temp_file (struct pool *pool, FILE *file)
 {
   struct pool_gizmo *g;
 
   for (g = pool->gizmos; g; g = g->next)
 {
   struct pool_gizmo *g;
 
   for (g = pool->gizmos; g; g = g->next)
-    if (g->type == POOL_GIZMO_FILE && g->p.file == file)
+    if (g->type == POOL_GIZMO_TEMP_FILE && g->p.file == file)
       {
         delete_gizmo (pool, g);
         return;
       {
         delete_gizmo (pool, g);
         return;
@@ -776,12 +859,12 @@ pool_register (struct pool *pool, void (*free) (void *), void *p)
 }
 
 /* Unregisters previously registered P from POOL.
 }
 
 /* Unregisters previously registered P from POOL.
-   Returns nonzero only if P was found to be registered in POOL. */
-int
+   Returns true only if P was found to be registered in POOL. */
+bool
 pool_unregister (struct pool *pool, void *p)
 {
   assert (pool && p);
 pool_unregister (struct pool *pool, void *p)
 {
   assert (pool && p);
-  
+
   {
     struct pool_gizmo *g;
 
   {
     struct pool_gizmo *g;
 
@@ -789,11 +872,11 @@ pool_unregister (struct pool *pool, void *p)
       if (g->type == POOL_GIZMO_REGISTERED && g->p.registered.p == p)
        {
          delete_gizmo (pool, g);
       if (g->type == POOL_GIZMO_REGISTERED && g->p.registered.p == p)
        {
          delete_gizmo (pool, g);
-         return 1;
+         return true;
        }
   }
        }
   }
-  
-  return 0;
+
+  return false;
 }
 \f
 /* Partial freeing. */
 }
 \f
 /* Partial freeing. */
@@ -814,12 +897,12 @@ pool_mark (struct pool *pool, struct pool_mark *mark)
 /* Restores to POOL the state recorded in MARK.
    Emptied blocks are not given back with free() but kept for
    later allocations.  To get that behavior, use a subpool
 /* Restores to POOL the state recorded in MARK.
    Emptied blocks are not given back with free() but kept for
    later allocations.  To get that behavior, use a subpool
-   instead. */ 
+   instead. */
 void
 pool_release (struct pool *pool, const struct pool_mark *mark)
 {
   assert (pool && mark);
 void
 pool_release (struct pool *pool, const struct pool_mark *mark)
 {
   assert (pool && mark);
-  
+
   {
     struct pool_gizmo *cur, *next;
 
   {
     struct pool_gizmo *cur, *next;
 
@@ -837,18 +920,18 @@ pool_release (struct pool *pool, const struct pool_mark *mark)
     else
       pool->gizmos = NULL;
   }
     else
       pool->gizmos = NULL;
   }
-  
+
   {
     struct pool_block *cur;
 
   {
     struct pool_block *cur;
 
-    for (cur = pool->blocks; cur != mark->block; cur = cur->next) 
+    for (cur = pool->blocks; cur != mark->block; cur = cur->next)
       {
         cur->ofs = POOL_BLOCK_SIZE;
       {
         cur->ofs = POOL_BLOCK_SIZE;
-        if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool) 
+        if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
           {
             cur->ofs += POOL_SIZE;
             if (pool->parent != NULL)
           {
             cur->ofs += POOL_SIZE;
             if (pool->parent != NULL)
-              cur->ofs += POOL_GIZMO_SIZE; 
+              cur->ofs += POOL_GIZMO_SIZE;
           }
       }
     pool->blocks = mark->block;
           }
       }
     pool->blocks = mark->block;
@@ -875,7 +958,7 @@ add_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
 
   check_gizmo (pool, gizmo);
 }
 
   check_gizmo (pool, gizmo);
 }
+
 /* Removes GIZMO from POOL's gizmo list. */
 static void
 delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
 /* Removes GIZMO from POOL's gizmo list. */
 static void
 delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
@@ -907,6 +990,9 @@ free_gizmo (struct pool_gizmo *gizmo)
     case POOL_GIZMO_FILE:
       fclose (gizmo->p.file);  /* Ignore errors. */
       break;
     case POOL_GIZMO_FILE:
       fclose (gizmo->p.file);  /* Ignore errors. */
       break;
+    case POOL_GIZMO_TEMP_FILE:
+      close_temp_file (gizmo->p.file); /* Ignore errors. */
+      break;
     case POOL_GIZMO_SUBPOOL:
       gizmo->p.subpool->parent = NULL;
       pool_destroy (gizmo->p.subpool);
     case POOL_GIZMO_SUBPOOL:
       gizmo->p.subpool->parent = NULL;
       pool_destroy (gizmo->p.subpool);
@@ -915,13 +1001,13 @@ free_gizmo (struct pool_gizmo *gizmo)
       gizmo->p.registered.free (gizmo->p.registered.p);
       break;
     default:
       gizmo->p.registered.free (gizmo->p.registered.p);
       break;
     default:
-      assert (0);
+      NOT_REACHED ();
     }
 }
 
 /* Free all the gizmos in POOL. */
 static void
     }
 }
 
 /* Free all the gizmos in POOL. */
 static void
-free_all_gizmos (struct pool *pool) 
+free_all_gizmos (struct pool *pool)
 {
   struct pool_gizmo *cur, *next;
 
 {
   struct pool_gizmo *cur, *next;
 
@@ -934,7 +1020,7 @@ free_all_gizmos (struct pool *pool)
 }
 
 static void
 }
 
 static void
-check_gizmo (struct pool *p, struct pool_gizmo *g) 
+check_gizmo (struct pool *p, struct pool_gizmo *g)
 {
   assert (g->pool == p);
   assert (g->next == NULL || g->next->prev == g);
 {
   assert (g->pool == p);
   assert (g->next == NULL || g->next->prev == g);