m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Changes to m4/m4/output.c,v


From: Eric Blake
Subject: Changes to m4/m4/output.c,v
Date: Wed, 15 Nov 2006 00:45:08 +0000

CVSROOT:        /sources/m4
Module name:    m4
Changes by:     Eric Blake <ericb>      06/11/15 00:45:07

Index: m4/output.c
===================================================================
RCS file: /sources/m4/m4/m4/output.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- m4/output.c 14 Nov 2006 05:58:01 -0000      1.39
+++ m4/output.c 15 Nov 2006 00:45:07 -0000      1.40
@@ -21,6 +21,7 @@
 #include <config.h>
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -30,7 +31,7 @@
 
 #include "binary-io.h"
 #include "clean-temp.h"
-#include "gl_avltree_list.h"
+#include "gl_avltree_oset.h"
 #include "exitfail.h"
 #include "xvasprintf.h"
 
@@ -56,11 +57,12 @@
 
 typedef struct temp_dir m4_temp_dir;
 
-/* When part of diversion_table, each struct diversion either
+/* When part of diversion_table, each struct m4_diversion either
    represents an open file (zero size, non-NULL u.file), an in-memory
    buffer (non-zero size, non-NULL u.buffer), or an unused placeholder
-   diversion (zero size, u is NULL).  When not part of
-   diversion_table, u.next is a pointer to the free_list chain.  */
+   diversion (zero size, u is NULL, non-zero used indicates that a
+   temporary file exists).  When not part of diversion_table, u.next
+   is a pointer to the free_list chain.  */
 
 typedef struct m4_diversion m4_diversion;
 
@@ -77,15 +79,18 @@
     size_t used;               /* used length in characters */
   };
 
-/* Sorted list of current diversions.  */
-static gl_list_t diversion_table;
+/* Sorted set of diversions 1 through INT_MAX.  */
+static gl_oset_t diversion_table;
 
-/* Number of entries in diversion table.  */
-static int diversions;
+/* Diversion 0 (not part of diversion_table).  */
+static m4_diversion div0;
 
 /* Linked list of reclaimed diversion storage.  */
 static m4_diversion *free_list;
 
+/* Obstack from which diversion storage is allocated.  */
+static struct obstack diversion_storage;
+
 /* Total size of all in-memory buffer sizes.  */
 static size_t total_buffer_size;
 
@@ -104,16 +109,6 @@
 
 /* --- OUTPUT INITIALIZATION --- */
 
-/* Callback for comparing list elements ELT1 and ELT2 for equality in
-   diversion_table.  */
-static bool
-equal_diversion_CB (const void *elt1, const void *elt2)
-{
-  const m4_diversion *d1 = (const m4_diversion *) elt1;
-  const m4_diversion *d2 = (const m4_diversion *) elt2;
-  return d1->divnum == d2->divnum;
-}
-
 /* Callback for comparing list elements ELT1 and ELT2 for order in
    diversion_table.  */
 static int
@@ -126,42 +121,39 @@
   return d1->divnum - d2->divnum;
 }
 
+/* Callback for comparing list element ELT against THRESHOLD.  */
+static bool
+threshold_diversion_CB (const void *elt, const void *threshold)
+{
+  const m4_diversion *div = (const m4_diversion *) elt;
+  /* No need to worry about overflow, since we don't create diversions
+     with negative divnum.  */
+  return div->divnum >= *(const int *) threshold;
+}
+
+/* Initialize the output engine.  */
 void
 m4_output_init (m4 *context)
 {
-  m4_diversion *diversion = xmalloc (sizeof *diversion);
-  const void *tmp = diversion;
-  diversion->u.file = stdout;
-  diversion->divnum = 0;
-  diversion->size = 0;
-  diversion->used = 0;
-  diversion_table = gl_list_create (GL_AVLTREE_LIST, equal_diversion_CB, NULL,
-                                   false, 1, &tmp);
-
-  diversions = 1;
+  diversion_table = gl_oset_create_empty (GL_AVLTREE_OSET, cmp_diversion_CB);
+  div0.u.file = stdout;
   m4_set_current_diversion (context, 0);
-  output_diversion = diversion;
+  output_diversion = &div0;
   output_file = stdout;
+  obstack_init (&diversion_storage);
 }
 
+/* Clean up memory allocated during use.  */
 void
 m4_output_exit (void)
 {
-  m4_diversion *diversion = free_list;
-  gl_list_t table = diversion_table;
-
   /* Order is important, since we may have registered cleanup_tmpfile
      as an atexit handler, and it must not traverse stale memory.  */
-  assert (gl_list_size (diversion_table) == 1);
+  gl_oset_t table = diversion_table;
+  assert (gl_oset_size (diversion_table) == 0);
   diversion_table = NULL;
-  free ((void *) gl_list_get_at (table, 0));
-  gl_list_free (table);
-  while (diversion)
-    {
-      m4_diversion *stale = diversion;
-      diversion = diversion->u.next;
-      free (stale);
-    }
+  gl_oset_free (table);
+  obstack_free (&diversion_storage, NULL);
 }
 
 /* Clean up any temporary directory.  Designed for use as an atexit
@@ -171,18 +163,15 @@
 cleanup_tmpfile (void)
 {
   /* Close any open diversions.  */
-  m4_diversion *diversion;
-  gl_list_iterator_t iter;
-  const void *elt;
   bool fail = false;
 
   if (diversion_table)
     {
-      iter = gl_list_iterator_from_to (diversion_table, 1,
-                                      gl_list_size (diversion_table));
-      while (gl_list_iterator_next (&iter, &elt, NULL))
+      const void *elt;
+      gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
+      while (gl_oset_iterator_next (&iter, &elt))
        {
-         diversion = (m4_diversion *) elt;
+         m4_diversion *diversion = (m4_diversion *) elt;
          if (!diversion->size && diversion->u.file
              && close_stream_temp (diversion->u.file) != 0)
            {
@@ -191,7 +180,7 @@
              fail = true;
            }
        }
-      gl_list_iterator_free (&iter);
+      gl_oset_iterator_free (&iter);
     }
 
   /* Clean up the temporary directory.  */
@@ -201,16 +190,33 @@
     _exit (exit_failure);
 }
 
-/* Create a temporary file open for reading and writing in a secure
-   temp directory.  The file will be automatically closed and deleted
-   on a fatal signal.  When done with the file, close it with
-   close_stream_temp.  Exits on failure, so the return value is always
-   an open file.  */
+/* Convert DIVNUM into a temporary file name for use in m4_tmp*.  */
+static const char *
+m4_tmpname (int divnum)
+{
+  static char *buffer;
+  static char *tail;
+  if (buffer == NULL)
+    {
+      tail = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, INT_MAX);
+      buffer = obstack_copy0 (&diversion_storage, tail, strlen (tail));
+      free (tail);
+      tail = strrchr (buffer, '-') + 1;
+    }
+  sprintf (tail, "%d", divnum);
+  return buffer;
+}
+
+/* Create a temporary file for diversion DIVNUM open for reading and
+   writing in a secure temp directory.  The file will be automatically
+   closed and deleted on a fatal signal.  The file can be closed and
+   reopened with m4_tmpclose and m4_tmpopen; when finally done with
+   the file, close it and use m4_tmpremove.  Exits on failure, so the
+   return value is always an open file.  */
 static FILE *
-m4_tmpfile (m4 *context)
+m4_tmpfile (m4 *context, int divnum)
 {
-  static unsigned int count;
-  char *name;
+  const char *name;
   FILE *file;
 
   if (output_temp_dir == NULL)
@@ -222,17 +228,54 @@
                  _("cannot create temporary file for diversion"));
       atexit (cleanup_tmpfile);
     }
-  name = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, count++);
+  name = m4_tmpname (divnum);
   register_temp_file (output_temp_dir, name);
   errno = 0;
   file = fopen_temp (name, O_BINARY ? "wb+" : "w+");
   if (file == NULL)
+    {
+      unregister_temp_file (output_temp_dir, name);
+      m4_error (context, EXIT_FAILURE, errno,
+               _("cannot create temporary file for diversion"));
+    }
+  else if (set_cloexec_flag (fileno (file), true) != 0)
+    m4_warn (context, errno, _("cannot protect diversion across forks"));
+  return file;
+}
+
+/* Reopen a temporary file for diversion DIVNUM for reading and
+   writing in a secure temp directory.  Exits on failure, so the
+   return value is always an open file.  */
+static FILE *
+m4_tmpopen (m4 *context, int divnum)
+{
+  const char *name = m4_tmpname (divnum);
+  FILE *file;
+
+  errno = 0;
+  file = fopen_temp (name, O_BINARY ? "ab+" : "a+");
+  if (file == NULL)
     m4_error (context, EXIT_FAILURE, errno,
              _("cannot create temporary file for diversion"));
-  free (name);
+  else if (set_cloexec_flag (fileno (file), true) != 0)
+    m4_warn (context, errno, _("cannot protect diversion across forks"));
   return file;
 }
 
+/* Close, but don't delete, a temporary FILE.  */
+static int
+m4_tmpclose (FILE *file)
+{
+  return close_stream_temp (file);
+}
+
+/* Delete a closed temporary FILE for diversion DIVNUM.  */
+static int
+m4_tmpremove (int divnum)
+{
+  return cleanup_temp_file (output_temp_dir, m4_tmpname (divnum));
+}
+
 /* Reorganize in-memory diversion buffers so the current diversion can
    accomodate LENGTH more characters without further reorganization.  The
    current diversion buffer is made bigger if possible.  But to make room
@@ -270,7 +313,7 @@
       char *selected_buffer;
       m4_diversion *diversion;
       size_t count;
-      gl_list_iterator_t iter;
+      gl_oset_iterator_t iter;
       const void *elt;
 
       /* Find out the buffer having most data, in view of flushing it to
@@ -281,9 +324,8 @@
       selected_diversion = output_diversion;
       selected_used = output_diversion->used + length;
 
-      iter = gl_list_iterator_from_to (diversion_table, 1,
-                                      gl_list_size (diversion_table));
-      while (gl_list_iterator_next (&iter, &elt, NULL))
+      iter = gl_oset_iterator (diversion_table);
+      while (gl_oset_iterator_next (&iter, &elt))
        {
          diversion = (m4_diversion *) elt;
          if (diversion->used > selected_used)
@@ -292,21 +334,20 @@
              selected_used = diversion->used;
            }
        }
-      gl_list_iterator_free (&iter);
+      gl_oset_iterator_free (&iter);
 
       /* Create a temporary file, write the in-memory buffer of the
-        diversion to this file, then release the buffer.  Set the
-        size to zero before doing anything that can exit (), so that
-        the atexit handler recognizes a file that must be closed.  */
+        diversion to this file, then release the buffer.  Zero the
+        diversion before doing anything that can exit () (including
+        m4_tmpfile), so that the atexit handler doesn't try to close
+        a garbage pointer as a file.  */
 
       selected_buffer = selected_diversion->u.buffer;
       total_buffer_size -= selected_diversion->size;
       selected_diversion->size = 0;
-      selected_diversion->u.file = m4_tmpfile (context);
-
-      if (set_cloexec_flag (fileno (selected_diversion->u.file), true) != 0)
-       m4_error (context, 0, errno,
-                 _("cannot protect diversion across forks"));
+      selected_diversion->u.file = NULL;
+      selected_diversion->u.file = m4_tmpfile (context,
+                                              selected_diversion->divnum);
 
       if (selected_diversion->used > 0)
        {
@@ -320,14 +361,13 @@
       /* Reclaim the buffer space for other diversions.  */
 
       free (selected_buffer);
-      selected_diversion->used = 0;
+      selected_diversion->used = 1;
     }
 
   /* Reload output_file, just in case the flushed diversion was current.  */
 
   if (output_diversion == selected_diversion)
     {
-
       /* The flushed diversion was current indeed.  */
 
       output_file = output_diversion->u.file;
@@ -336,9 +376,19 @@
     }
   else
     {
+      /* Close any selected file since it is not the current diversion.  */
+      if (selected_diversion)
+       {
+         FILE *file = selected_diversion->u.file;
+         selected_diversion->u.file = 0;
+         if (m4_tmpclose (file) != 0)
+           m4_error (context, 0, errno,
+                     _("cannot close temporary file for diversion"));
+       }
+
       /* The buffer may be safely reallocated.  */
 
-      assert (wanted_size > length);
+      assert (wanted_size >= length);
       output_diversion->u.buffer = xrealloc (output_diversion->u.buffer,
                                             wanted_size);
 
@@ -543,8 +593,7 @@
 void
 m4_make_diversion (m4 *context, int divnum)
 {
-  m4_diversion *diversion;
-  gl_list_node_t node = NULL;
+  m4_diversion *diversion = NULL;
 
   if (m4_get_current_diversion (context) == divnum)
     return;
@@ -555,13 +604,23 @@
       assert (output_diversion->divnum != divnum);
       if (!output_diversion->size && !output_diversion->u.file)
        {
-         if (!gl_list_remove (diversion_table, output_diversion))
+         if (!gl_oset_remove (diversion_table, output_diversion))
            assert (false);
          output_diversion->u.next = free_list;
+         output_diversion->used = 0;
          free_list = output_diversion;
        }
-      else
+      else if (output_diversion->size)
        output_diversion->used = output_diversion->size - output_unused;
+      else if (output_diversion->used)
+       {
+         assert (output_diversion->divnum != 0);
+         FILE *file = output_diversion->u.file;
+         output_diversion->u.file = NULL;
+         if (m4_tmpclose (file) != 0)
+           m4_error (context, 0, errno,
+                     _("cannot close temporary file for diversion"));
+       }
       output_diversion = NULL;
       output_file = NULL;
       output_cursor = NULL;
@@ -573,17 +632,20 @@
   if (divnum < 0)
     return;
 
-  if (divnum >= diversions)
-    diversions = divnum + 1;
+  if (divnum == 0)
+    diversion = &div0;
   else
     {
-      m4_diversion temp;
-      temp.divnum = divnum;
-      node = gl_sortedlist_search (diversion_table, cmp_diversion_CB, &temp);
+      const void *elt;
+      if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
+                                 &divnum, &elt))
+       {
+         m4_diversion *temp = (m4_diversion *) elt;
+         if (temp->divnum == divnum)
+           diversion = temp;
     }
-  if (node != NULL)
-    diversion = (m4_diversion *) gl_list_node_value (diversion_table, node);
-  else
+    }
+  if (diversion == NULL)
     {
       /* First time visiting this diversion.  */
       if (free_list)
@@ -594,13 +656,15 @@
        }
       else
        {
-         diversion = (m4_diversion *) xmalloc (sizeof *diversion);
+         diversion = (m4_diversion *) obstack_alloc (&diversion_storage,
+                                                     sizeof *diversion);
          diversion->size = 0;
          diversion->used = 0;
        }
       diversion->u.file = NULL;
       diversion->divnum = divnum;
-      gl_sortedlist_add (diversion_table, cmp_diversion_CB, diversion);
+      if (!gl_oset_add (diversion_table, diversion))
+       assert (false);
     }
 
   output_diversion = diversion;
@@ -610,7 +674,12 @@
       output_unused = output_diversion->size - output_diversion->used;
     }
   else
+    {
+      if (!output_diversion->u.file && output_diversion->used)
+       output_diversion->u.file = m4_tmpopen (context,
+                                              output_diversion->divnum);
     output_file = output_diversion->u.file;
+    }
 
   m4_set_output_line (context, -1);
 }
@@ -646,8 +715,7 @@
    not be rescanned.  When the file is closed, it is deleted by the
    system.  */
 static void
-m4_insert_diversion_helper (m4 *context, m4_diversion *diversion,
-                           gl_list_node_t node)
+insert_diversion_helper (m4 *context, m4_diversion *diversion)
 {
   assert (diversion->divnum > 0
          && diversion->divnum != m4_get_current_diversion (context));
@@ -656,11 +724,16 @@
     {
       if (diversion->size)
        output_text (context, diversion->u.buffer, diversion->used);
-      else if (diversion->u.file)
+      else
+       {
+         if (!diversion->u.file && diversion->used)
+           diversion->u.file = m4_tmpopen (context, diversion->divnum);
+         if (diversion->u.file)
        {
          rewind (diversion->u.file);
          m4_insert_file (context, diversion->u.file);
        }
+       }
 
       m4_set_output_line (context, -1);
     }
@@ -672,10 +745,23 @@
       diversion->size = 0;
       diversion->used = 0;
     }
-  else if (diversion->u.file && close_stream_temp (diversion->u.file) != 0)
+  else
+    {
+      if (diversion->u.file)
+       {
+         FILE *file = diversion->u.file;
+         diversion->u.file = NULL;
+         diversion->used = 0;
+         if (m4_tmpclose (file) != 0)
     m4_error (context, 0, errno,
              _("cannot clean temporary file for diversion"));
-  gl_list_remove_node (diversion_table, node);
+       }
+      if (m4_tmpremove (diversion->divnum) != 0)
+       m4_error (context, 0, errno,
+                 _("cannot clean temporary file for diversion"));
+    }
+  if (!gl_oset_remove (diversion_table, diversion))
+    assert (false);
   diversion->u.next = free_list;
   free_list = diversion;
 }
@@ -686,21 +772,19 @@
 void
 m4_insert_diversion (m4 *context, int divnum)
 {
-  m4_diversion *diversion;
-  m4_diversion temp;
-  gl_list_node_t node;
+  const void *elt;
 
   /* Do not care about nonexistent diversions, and undiverting stdout
      or self is a no-op.  */
-  if (divnum <= 0 || divnum >= diversions
-      || m4_get_current_diversion (context) == divnum)
-    return;
-  temp.divnum = divnum;
-  node = gl_sortedlist_search (diversion_table, cmp_diversion_CB, &temp);
-  if (node == NULL)
+  if (divnum <= 0 || m4_get_current_diversion (context) == divnum)
     return;
-  diversion = (m4_diversion *) gl_list_node_value (diversion_table, node);
-  m4_insert_diversion_helper (context, diversion, node);
+  if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
+                             &divnum, &elt))
+    {
+      m4_diversion *diversion = (m4_diversion *) elt;
+      if (diversion->divnum == divnum)
+       insert_diversion_helper (context, diversion);
+    }
 }
 
 /* Get back all diversions.  This is done just before exiting from main (),
@@ -708,21 +792,16 @@
 void
 m4_undivert_all (m4 *context)
 {
-  m4_diversion *diversion;
-  gl_list_iterator_t iter;
-  gl_list_node_t node;
   int divnum = m4_get_current_diversion (context);
   const void *elt;
-
-  iter = gl_list_iterator_from_to (diversion_table, 1,
-                                  gl_list_size (diversion_table));
-  while (gl_list_iterator_next (&iter, &elt, &node))
+  gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
+  while (gl_oset_iterator_next (&iter, &elt))
     {
-      diversion = (m4_diversion *) elt;
+      m4_diversion *diversion = (m4_diversion *) elt;
       if (diversion->divnum != divnum)
-       m4_insert_diversion_helper (context, diversion, node);
+       insert_diversion_helper (context, diversion);
     }
-  gl_list_iterator_free (&iter);
+  gl_oset_iterator_free (&iter);
 }
 
 /* Produce all diversion information in frozen format on FILE.  */
@@ -731,10 +810,7 @@
 {
   int saved_number;
   int last_inserted;
-  m4_diversion *diversion;
-  struct stat file_stat;
-  gl_list_iterator_t iter;
-  gl_list_node_t node;
+  gl_oset_iterator_t iter;
   const void *elt;
 
   saved_number = m4_get_current_diversion (context);
@@ -742,11 +818,10 @@
   m4_make_diversion (context, 0);
   output_file = file;          /* kludge in the frozen file */
 
-  iter = gl_list_iterator_from_to (diversion_table, 1,
-                                  gl_list_size (diversion_table));
-  while (gl_list_iterator_next (&iter, &elt, &node))
+  iter = gl_oset_iterator (diversion_table);
+  while (gl_oset_iterator_next (&iter, &elt))
     {
-      diversion = (m4_diversion *) elt;
+      m4_diversion *diversion = (m4_diversion *) elt;
       if (diversion->size || diversion->u.file)
        {
          if (diversion->size)
@@ -757,6 +832,7 @@
            }
          else
            {
+             struct stat file_stat;
              fflush (diversion->u.file);
              if (fstat (fileno (diversion->u.file), &file_stat) < 0)
                m4_error (context, EXIT_FAILURE, errno,
@@ -772,13 +848,13 @@
                       (unsigned long int) file_stat.st_size);
            }
 
-         m4_insert_diversion_helper (context, diversion, node);
+         insert_diversion_helper (context, diversion);
          putc ('\n', file);
 
          last_inserted = diversion->divnum;
        }
     }
-  gl_list_iterator_free (&iter);
+  gl_oset_iterator_free (&iter);
 
   /* Save the active diversion number, if not already.  */
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]