pool: New function pool_strdup0.
[pspp-builds.git] / src / libpspp / pool.c
index 0e6c9358fc828cd10f027c32d9f5750c7ffd5c23..dbdd71b6cbbf250fbb91248e6c8cc820da13e4f0 100644 (file)
@@ -1,30 +1,29 @@
-/* PSPP - computes sample statistics.
+/* PSPP - a program for statistical analysis.
    Copyright (C) 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
 
-   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
-   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 "pool.h"
+#include <stdint.h>
 #include <stdlib.h>
-#include "alloc.h"
+#include <libpspp/assertion.h>
 #include "message.h"
-#include "size_max.h"
 #include "str.h"
 
+#include "xalloc.h"
+
 /* Fast, low-overhead memory block suballocator. */
 struct pool
   {
@@ -34,7 +33,7 @@ struct pool
   };
 
 /* Pool block. */
-struct pool_block 
+struct pool_block
   {
     struct pool_block *prev;
     struct pool_block *next;
@@ -51,7 +50,7 @@ enum
   };
 
 /* Pool routines can maintain objects (`gizmos') as well as doing
-   suballocation.  
+   suballocation.
    This structure is used to keep track of them. */
 struct pool_gizmo
   {
@@ -100,8 +99,8 @@ union align
 
 /* 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,
@@ -147,7 +146,7 @@ pool_create (void)
   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;
@@ -163,7 +162,7 @@ pool_create (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_;
@@ -185,9 +184,9 @@ pool_destroy (struct pool *pool)
     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));
-  
+
   free_all_gizmos (pool);
 
   /* Free all the memory. */
@@ -205,25 +204,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
-   allocations.  To give back memory, use a subpool instead. */ 
+   allocations.  To give back memory, use a subpool instead. */
 void
-pool_clear (struct pool *pool) 
+pool_clear (struct pool *pool)
 {
   free_all_gizmos (pool);
 
   /* Zero out block sizes. */
   {
     struct pool_block *cur;
-    
+
     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_GIZMO_SIZE; 
+              cur->ofs += POOL_GIZMO_SIZE;
           }
         cur = cur->next;
       }
@@ -243,7 +242,7 @@ pool_alloc (struct pool *pool, size_t amt)
 
   if (amt == 0)
     return NULL;
-  
+
 #ifndef DISCRETE_BLOCKS
   if (amt <= MAX_SUBALLOC)
     {
@@ -259,7 +258,7 @@ pool_alloc (struct pool *pool, size_t amt)
 
       /* 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;
@@ -267,7 +266,7 @@ pool_alloc (struct pool *pool, size_t amt)
           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);
@@ -301,7 +300,7 @@ pool_alloc_unaligned (struct pool *pool, size_t amt)
   /* 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;
@@ -328,7 +327,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 *
-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 ();
@@ -360,11 +359,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 *
-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);
 }
 
+/* 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 *
@@ -382,9 +394,9 @@ pool_vasprintf (struct pool *pool, const char *format, va_list 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;
@@ -400,7 +412,7 @@ pool_vasprintf (struct pool *pool, const char *format, va_list 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
@@ -423,7 +435,7 @@ pool_asprintf (struct pool *pool, const char *format, ...)
 {
   va_list args;
   char *string;
-  
+
   va_start (args, format);
   string = pool_vasprintf (pool, format, args);
   va_end (args);
@@ -465,13 +477,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 *
-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);
 }
 
+/* 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.
@@ -657,7 +697,7 @@ pool_create_subpool (struct pool *pool)
 
   g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs);
   subpool->blocks->ofs += POOL_GIZMO_SIZE;
-  
+
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
 
@@ -671,14 +711,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
-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);
-  
+
   g = pool_alloc (subpool, sizeof *g);
   g->type = POOL_GIZMO_SUBPOOL;
   g->p.subpool = subpool;
@@ -699,8 +739,8 @@ pool_fopen (struct pool *pool, const char *file_name, const char *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;
 }
@@ -721,7 +761,7 @@ pool_fclose (struct pool *pool, FILE *file)
    may be closed explicitly in advance using pool_fclose(), or
    detached from the pool with pool_detach_file(). */
 FILE *
-pool_tmpfile (struct pool *pool) 
+pool_tmpfile (struct pool *pool)
 {
   FILE *file = tmpfile ();
   if (file != NULL)
@@ -776,12 +816,12 @@ pool_register (struct pool *pool, void (*free) (void *), void *p)
 }
 
 /* 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);
-  
+
   {
     struct pool_gizmo *g;
 
@@ -789,11 +829,11 @@ pool_unregister (struct pool *pool, void *p)
       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. */
@@ -814,12 +854,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
-   instead. */ 
+   instead. */
 void
 pool_release (struct pool *pool, const struct pool_mark *mark)
 {
   assert (pool && mark);
-  
+
   {
     struct pool_gizmo *cur, *next;
 
@@ -837,18 +877,18 @@ pool_release (struct pool *pool, const struct pool_mark *mark)
     else
       pool->gizmos = NULL;
   }
-  
+
   {
     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;
-        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_GIZMO_SIZE; 
+              cur->ofs += POOL_GIZMO_SIZE;
           }
       }
     pool->blocks = mark->block;
@@ -875,7 +915,7 @@ add_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
 
   check_gizmo (pool, gizmo);
 }
+
 /* Removes GIZMO from POOL's gizmo list. */
 static void
 delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
@@ -915,13 +955,13 @@ free_gizmo (struct pool_gizmo *gizmo)
       gizmo->p.registered.free (gizmo->p.registered.p);
       break;
     default:
-      assert (0);
+      NOT_REACHED ();
     }
 }
 
 /* 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;
 
@@ -934,7 +974,7 @@ free_all_gizmos (struct pool *pool)
 }
 
 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);