[Top][All Lists]
[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: |
Thu, 26 Oct 2006 23:19:13 +0000 |
CVSROOT: /sources/m4
Module name: m4
Changes by: Eric Blake <ericb> 06/10/26 23:19:12
Index: m4/output.c
===================================================================
RCS file: /sources/m4/m4/m4/output.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -b -r1.33 -r1.34
--- m4/output.c 26 Oct 2006 23:11:41 -0000 1.33
+++ m4/output.c 26 Oct 2006 23:19:12 -0000 1.34
@@ -30,6 +30,7 @@
#include "binary-io.h"
#include "clean-temp.h"
+#include "gl_avltree_list.h"
#include "exitfail.h"
#include "xvasprintf.h"
@@ -58,7 +59,8 @@
/* When part of diversion_table, each struct 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). */
+ diversion (zero size, u is NULL). When not part of
+ diversion_table, u.next is a pointer to the free_list chain. */
typedef struct m4_diversion m4_diversion;
@@ -68,17 +70,22 @@
{
FILE *file; /* diversion file on disk */
char *buffer; /* in-memory diversion buffer */
+ m4_diversion *next; /* free-list pointer */
} u;
+ int divnum; /* which diversion this represents */
size_t size; /* usable size before reallocation */
size_t used; /* used length in characters */
};
-/* Table of diversions. */
-static m4_diversion *diversion_table;
+/* Sorted list of current diversions. */
+static gl_list_t diversion_table;
/* Number of entries in diversion table. */
static int diversions;
+/* Linked list of reclaimed diversion storage. */
+static m4_diversion *free_list;
+
/* Total size of all in-memory buffer sizes. */
static size_t total_buffer_size;
@@ -97,33 +104,58 @@
/* --- 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
+cmp_diversion_CB (const void *elt1, const void *elt2)
+{
+ const m4_diversion *d1 = (const m4_diversion *) elt1;
+ const m4_diversion *d2 = (const m4_diversion *) elt2;
+ /* No need to worry about overflow, since we don't create diversions
+ with negative divnum. */
+ return d1->divnum - d2->divnum;
+}
+
void
m4_output_init (m4 *context)
{
- diversion_table = xmalloc (sizeof *diversion_table);
- diversions = 1;
- diversion_table[0].u.file = stdout;
- diversion_table[0].size = 0;
- diversion_table[0].used = 0;
+ m4_diversion *diversion = xmalloc (sizeof *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, (const void **) &diversion);
- total_buffer_size = 0;
+ diversions = 1;
m4_set_current_diversion (context, 0);
- output_diversion = diversion_table;
+ output_diversion = diversion;
output_file = stdout;
- output_cursor = NULL;
- output_unused = 0;
}
void
m4_output_exit (void)
{
-#ifndef NDEBUG
- int divnum;
- for (divnum = 1; divnum < diversions; divnum++)
- assert (!diversion_table[divnum].size
- && !diversion_table[divnum].u.file);
-#endif
- DELETE (diversion_table);
+ m4_diversion *diversion = free_list;
+ assert (gl_list_size (diversion_table) == 1);
+ free ((void *) gl_list_get_at (diversion_table, 0));
+ gl_list_free (diversion_table);
+ while (diversion)
+ {
+ m4_diversion *stale = diversion;
+ diversion = diversion->u.next;
+ free (stale);
+ }
}
/* Clean up any temporary directory. Designed for use as an atexit
@@ -205,6 +237,7 @@
char *selected_buffer;
m4_diversion *diversion;
size_t count;
+ gl_list_iterator_t iter;
/* Find out the buffer having most data, in view of flushing it to
disk. Fake the current buffer as having already received the
@@ -214,14 +247,15 @@
selected_diversion = output_diversion;
selected_used = output_diversion->used + length;
- for (diversion = diversion_table + 1;
- diversion < diversion_table + diversions;
- diversion++)
+ iter = gl_list_iterator_from_to (diversion_table, 1,
+ gl_list_size (diversion_table));
+ while (gl_list_iterator_next (&iter, (const void **) &diversion, NULL))
if (diversion->used > selected_used)
{
selected_diversion = diversion;
selected_used = diversion->used;
}
+ gl_list_iterator_free (&iter);
/* Create a temporary file, write the in-memory buffer of the
diversion to this file, then release the buffer. */
@@ -265,9 +299,9 @@
{
/* The buffer may be safely reallocated. */
- output_diversion->u.buffer
- = xrealloc (output_diversion->u.buffer,
- wanted_size > length ? wanted_size : length);
+ assert (wanted_size > length);
+ output_diversion->u.buffer = xrealloc (output_diversion->u.buffer,
+ wanted_size);
total_buffer_size += wanted_size - output_diversion->size;
output_diversion->size = wanted_size;
@@ -471,10 +505,15 @@
m4_make_diversion (m4 *context, int divnum)
{
m4_diversion *diversion;
+ gl_list_node_t node = NULL;
+
+ if (m4_get_current_diversion (context) == divnum)
+ return;
if (output_diversion)
{
assert (!output_file || output_diversion->u.file == output_file);
+ assert (output_diversion->divnum != divnum);
output_diversion->used = output_diversion->size - output_unused;
output_diversion = NULL;
output_file = NULL;
@@ -488,22 +527,36 @@
return;
if (divnum >= diversions)
+ diversions = divnum + 1;
+ else
{
- diversion_table = (m4_diversion *) xnrealloc (diversion_table,
- divnum + 1,
- sizeof (*diversion_table));
- for (diversion = diversion_table + diversions;
- diversion <= diversion_table + divnum;
- diversion++)
+ m4_diversion temp;
+ temp.divnum = divnum;
+ node = gl_sortedlist_search (diversion_table, cmp_diversion_CB, &temp);
+ }
+ if (node != NULL)
+ diversion = (m4_diversion *) gl_list_node_value (diversion_table, node);
+ else
{
- diversion->u.file = NULL;
+ /* First time visiting this diversion. */
+ if (free_list)
+ {
+ diversion = free_list;
+ free_list = diversion->u.next;
+ assert (!diversion->size && !diversion->used);
+ }
+ else
+ {
+ diversion = (m4_diversion *) xmalloc (sizeof *diversion);
diversion->size = 0;
diversion->used = 0;
}
- diversions = divnum + 1;
+ diversion->u.file = NULL;
+ diversion->divnum = divnum;
+ gl_sortedlist_add (diversion_table, cmp_diversion_CB, diversion);
}
- output_diversion = diversion_table + divnum;
+ output_diversion = diversion;
if (output_diversion->size)
{
output_cursor = output_diversion->u.buffer + output_diversion->used;
@@ -541,27 +594,17 @@
}
}
-/* Insert diversion number DIVNUM into the current output file. The
- diversion is NOT placed on the expansion obstack, because it must not
- be rescanned. When the file is closed, it is deleted by the system. */
-void
-m4_insert_diversion (m4 *context, int divnum)
+/* Insert DIVERSION living at NODE into the current output file. The
+ diversion is NOT placed on the expansion obstack, because it must
+ 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)
{
- m4_diversion *diversion;
-
- /* Do not care about unexisting diversions. */
-
- if (divnum <= 0 || divnum >= diversions)
- return;
-
- /* Also avoid undiverting into self. */
-
- diversion = diversion_table + divnum;
- if (diversion == output_diversion)
- return;
-
+ assert (diversion->divnum > 0
+ && diversion->divnum != m4_get_current_diversion (context));
/* Effectively undivert only if an output stream is active. */
-
if (output_diversion)
{
if (diversion->size)
@@ -576,7 +619,6 @@
}
/* Return all space used by the diversion. */
-
if (diversion->size)
{
free (diversion->u.buffer);
@@ -585,7 +627,32 @@
}
else if (diversion->u.file)
close_stream_temp (diversion->u.file);
- diversion->u.file = NULL;
+ gl_list_remove_node (diversion_table, node);
+ diversion->u.next = free_list;
+ free_list = diversion;
+}
+
+/* Insert diversion number DIVNUM into the current output file. The
+ diversion is NOT placed on the expansion obstack, because it must not
+ be rescanned. When the file is closed, it is deleted by the system. */
+void
+m4_insert_diversion (m4 *context, int divnum)
+{
+ m4_diversion *diversion;
+ m4_diversion temp;
+ gl_list_node_t node;
+
+ /* 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)
+ return;
+ diversion = (m4_diversion *) gl_list_node_value (diversion_table, node);
+ m4_insert_diversion_helper (context, diversion, node);
}
/* Get back all diversions. This is done just before exiting from main (),
@@ -593,10 +660,17 @@
void
m4_undivert_all (m4 *context)
{
- int divnum;
-
- for (divnum = 1; divnum < diversions; divnum++)
- m4_insert_diversion (context, divnum);
+ m4_diversion *diversion;
+ gl_list_iterator_t iter;
+ gl_list_node_t node;
+ int divnum = m4_get_current_diversion (context);
+
+ iter = gl_list_iterator_from_to (diversion_table, 1,
+ gl_list_size (diversion_table));
+ while (gl_list_iterator_next (&iter, (const void **) &diversion, &node))
+ if (diversion->divnum != divnum)
+ m4_insert_diversion_helper (context, diversion, node);
+ gl_list_iterator_free (&iter);
}
/* Produce all diversion information in frozen format on FILE. */
@@ -608,15 +682,18 @@
int divnum;
m4_diversion *diversion;
struct stat file_stat;
+ gl_list_iterator_t iter;
+ gl_list_node_t node;
saved_number = m4_get_current_diversion (context);
last_inserted = 0;
m4_make_diversion (context, 0);
output_file = file; /* kludge in the frozen file */
- for (divnum = 1; divnum < diversions; divnum++)
+ iter = gl_list_iterator_from_to (diversion_table, 1,
+ gl_list_size (diversion_table));
+ while (gl_list_iterator_next (&iter, (const void **) &diversion, &node))
{
- diversion = diversion_table + divnum;
if (diversion->size || diversion->u.file)
{
if (diversion->size)
@@ -641,12 +718,13 @@
(unsigned long) file_stat.st_size);
}
- m4_insert_diversion (context, divnum);
+ m4_insert_diversion_helper (context, diversion, node);
putc ('\n', file);
last_inserted = divnum;
}
}
+ gl_list_iterator_free (&iter);
/* Save the active diversion number, if not already. */
- Changes to m4/m4/output.c,v, Eric Blake, 2006/10/03
- Changes to m4/m4/output.c,v, Eric Blake, 2006/10/06
- Changes to m4/m4/output.c,v, Eric Blake, 2006/10/07
- Changes to m4/m4/output.c,v, Eric Blake, 2006/10/26
- Changes to m4/m4/output.c,v,
Eric Blake <=
- Changes to m4/m4/output.c,v, Eric Blake, 2006/10/27