[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Changes to m4/src/Attic/output.c,v [branch-1_4]
From: |
Eric Blake |
Subject: |
Changes to m4/src/Attic/output.c,v [branch-1_4] |
Date: |
Mon, 13 Nov 2006 19:10:58 +0000 |
CVSROOT: /sources/m4
Module name: m4
Branch: branch-1_4
Changes by: Eric Blake <ericb> 06/11/13 19:10:57
Index: src/output.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/output.c,v
retrieving revision 1.1.1.1.2.15
retrieving revision 1.1.1.1.2.16
diff -u -b -r1.1.1.1.2.15 -r1.1.1.1.2.16
--- src/output.c 8 Nov 2006 05:08:26 -0000 1.1.1.1.2.15
+++ src/output.c 13 Nov 2006 19:10:57 -0000 1.1.1.1.2.16
@@ -23,6 +23,8 @@
#include <sys/stat.h>
+#include "gl_avltree_oset.h"
+
/* Size of initial in-memory buffer size for diversions. Small diversions
would usually fit in. */
#define INITIAL_BUFFER_SIZE 512
@@ -40,24 +42,40 @@
This code is fairly entangled with the code in input.c, and maybe it
belongs there? */
-/* In a struct diversion, only one of file or buffer be may non-NULL,
- depending on the fact output is diverted to a file or in memory
- buffer. Further, if buffer is NULL, then pointer is NULL, size and
- unused are zero. */
+typedef struct temp_dir m4_temp_dir;
+
+/* 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. */
-struct diversion
+typedef struct m4_diversion m4_diversion;
+
+struct m4_diversion
+ {
+ union
{
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 */
int size; /* usable size before reallocation */
int used; /* used length in characters */
};
-/* Table of diversions. */
-static struct diversion *diversion_table;
+/* Table of diversions 1 through INT_MAX. */
+static gl_oset_t diversion_table;
+
+/* Diversion 0 (not part of diversion_table). */
+static m4_diversion div0;
-/* Number of entries in diversion table. */
-static int diversions;
+/* 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 int total_buffer_size;
@@ -67,7 +85,7 @@
int current_diversion;
/* Current output diversion, NULL if output is being currently discarded. */
-static struct diversion *output_diversion;
+static m4_diversion *output_diversion;
/* Values of some output_diversion fields, cached out for speed. */
static FILE *output_file; /* current value of (file) */
@@ -77,40 +95,56 @@
/* Number of input line we are generating output for. */
int output_current_line;
-typedef struct temp_dir m4_temp_dir;
-
/* Temporary directory holding all spilled diversion files. */
static m4_temp_dir *output_temp_dir;
/*------------------------.
-| Output initialisation. |
+| Output initialization. |
`------------------------*/
+/* 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;
+}
+
+/* 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;
+}
+
void
output_init (void)
{
- diversion_table = (struct diversion *) xmalloc (sizeof (struct diversion));
- diversions = 1;
- diversion_table[0].file = stdout;
- diversion_table[0].buffer = NULL;
- diversion_table[0].size = 0;
- diversion_table[0].used = 0;
-
- total_buffer_size = 0;
- current_diversion = 0;
- output_diversion = diversion_table;
+ diversion_table = gl_oset_create_empty (GL_AVLTREE_OSET, cmp_diversion_CB);
+ div0.u.file = stdout;
+ output_diversion = &div0;
output_file = stdout;
- output_cursor = NULL;
- output_unused = 0;
+ obstack_init (&diversion_storage);
}
void
output_exit (void)
{
- free (diversion_table);
+ /* Order is important, since we may have registered cleanup_tmpfile
+ as an atexit handler, and it must not traverse stale memory. */
+ gl_oset_t table = diversion_table;
diversion_table = NULL;
+ gl_oset_free (table);
+ obstack_free (&diversion_storage, NULL);
}
/* Clean up any temporary directory. Designed for use as an atexit
@@ -120,20 +154,24 @@
cleanup_tmpfile (void)
{
/* Close any open diversions. */
- int divnum;
- struct diversion *diversion;
bool fail = false;
if (diversion_table)
- for (divnum = 1; divnum < diversions; divnum++)
{
- diversion = diversion_table + divnum;
- if (diversion->file && close_stream_temp (diversion->file) != 0)
+ const void *elt;
+ gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
+ while (gl_oset_iterator_next (&iter, &elt))
+ {
+ m4_diversion *diversion = (m4_diversion *) elt;
+ if (!diversion->size && diversion->u.file
+ && close_stream_temp (diversion->u.file) != 0)
{
- M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+ M4ERROR ((0, errno,
+ "cannot clean temporary file for diversion"));
fail = true;
}
}
+ }
/* Clean up the temporary directory. */
if (cleanup_temp_dir (output_temp_dir) != 0)
@@ -187,6 +225,7 @@
make_room_for (int length)
{
int wanted_size;
+ m4_diversion *selected_diversion = NULL;
/* Compute needed size for in-memory buffer. Diversions in-memory
buffers start at 0 bytes, then 512, then keep doubling until it is
@@ -204,10 +243,12 @@
if (total_buffer_size - output_diversion->size + wanted_size
> MAXIMUM_TOTAL_SIZE)
{
- struct diversion *selected_diversion;
int selected_used;
- struct diversion *diversion;
+ char *selected_buffer;
+ m4_diversion *diversion;
int count;
+ gl_oset_iterator_t iter;
+ const void *elt;
/* Find out the buffer having most data, in view of flushing it to
disk. Fake the current buffer as having already received the
@@ -217,29 +258,38 @@
selected_diversion = output_diversion;
selected_used = output_diversion->used + length;
- for (diversion = diversion_table + 1;
- diversion < diversion_table + diversions;
- diversion++)
+ iter = gl_oset_iterator (diversion_table);
+ while (gl_oset_iterator_next (&iter, &elt))
+ {
+ diversion = (m4_diversion *) elt;
if (diversion->used > selected_used)
{
selected_diversion = diversion;
selected_used = diversion->used;
}
+ }
+ gl_oset_iterator_free (&iter);
/* Create a temporary file, write the in-memory buffer of the
- diversion to this file, then release the buffer. */
+ 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_diversion->file = m4_tmpfile ();
- if (set_cloexec_flag (fileno (selected_diversion->file), true) != 0)
+ selected_buffer = selected_diversion->u.buffer;
+ total_buffer_size -= selected_diversion->size;
+ selected_diversion->size = 0;
+ selected_diversion->u.file = NULL;
+ selected_diversion->u.file = m4_tmpfile ();
+
+ if (set_cloexec_flag (fileno (selected_diversion->u.file), true) != 0)
M4ERROR ((warning_status, errno,
"Warning: cannot protect diversion across forks"));
if (selected_diversion->used > 0)
{
- count = fwrite (selected_diversion->buffer,
- (size_t) selected_diversion->used,
- 1,
- selected_diversion->file);
+ count = fwrite (selected_buffer, (size_t) selected_diversion->used,
+ 1, selected_diversion->u.file);
if (count != 1)
M4ERROR ((EXIT_FAILURE, errno,
"ERROR: cannot flush diversion to temporary file"));
@@ -247,37 +297,31 @@
/* Reclaim the buffer space for other diversions. */
- free (selected_diversion->buffer);
- total_buffer_size -= selected_diversion->size;
-
- selected_diversion->buffer = NULL;
- selected_diversion->size = 0;
+ free (selected_buffer);
selected_diversion->used = 0;
}
/* Reload output_file, just in case the flushed diversion was current. */
- output_file = output_diversion->file;
- if (output_file)
+ if (output_diversion == selected_diversion)
{
-
/* The flushed diversion was current indeed. */
+ output_file = output_diversion->u.file;
output_cursor = NULL;
output_unused = 0;
}
else
{
-
/* The buffer may be safely reallocated. */
- output_diversion->buffer
- = xrealloc (output_diversion->buffer, (size_t) wanted_size);
+ output_diversion->u.buffer
+ = xrealloc (output_diversion->u.buffer, (size_t) wanted_size);
total_buffer_size += wanted_size - output_diversion->size;
output_diversion->size = wanted_size;
- output_cursor = output_diversion->buffer + output_diversion->used;
+ output_cursor = output_diversion->u.buffer + output_diversion->used;
output_unused = wanted_size - output_diversion->used;
}
}
@@ -445,11 +489,21 @@
void
make_diversion (int divnum)
{
- struct diversion *diversion;
+ m4_diversion *diversion = NULL;
+
+ if (current_diversion == divnum)
+ return;
if (output_diversion)
{
- output_diversion->file = output_file;
+ if (!output_diversion->size && !output_diversion->u.file)
+ {
+ if (!gl_oset_remove (diversion_table, output_diversion))
+ error (EXIT_FAILURE, 0, "INTERNAL ERROR: make_diversion failed");
+ output_diversion->u.next = free_list;
+ free_list = output_diversion;
+ }
+ else
output_diversion->used = output_diversion->size - output_unused;
output_diversion = NULL;
output_file = NULL;
@@ -462,26 +516,47 @@
if (divnum < 0)
return;
- if (divnum >= diversions)
+ if (divnum == 0)
+ diversion = &div0;
+ else
{
- diversion_table = (struct diversion *)
- xnrealloc (diversion_table, divnum + 1, sizeof (struct diversion));
- for (diversion = diversion_table + diversions;
- diversion <= diversion_table + divnum;
- diversion++)
+ const void *elt;
+ if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
+ &divnum, &elt))
{
- diversion->file = NULL;
- diversion->buffer = NULL;
+ m4_diversion *temp = (m4_diversion *) elt;
+ if (temp->divnum == divnum)
+ diversion = temp;
+ }
+ }
+ if (diversion == NULL)
+ {
+ /* First time visiting this diversion. */
+ if (free_list)
+ {
+ diversion = free_list;
+ free_list = diversion->u.next;
+ }
+ else
+ {
+ diversion = (m4_diversion *) obstack_alloc (&diversion_storage,
+ sizeof *diversion);
diversion->size = 0;
diversion->used = 0;
}
- diversions = divnum + 1;
+ diversion->u.file = NULL;
+ diversion->divnum = divnum;
+ gl_oset_add (diversion_table, diversion);
}
- output_diversion = diversion_table + divnum;
- output_file = output_diversion->file;
- output_cursor = output_diversion->buffer + output_diversion->used;
+ output_diversion = diversion;
+ if (output_diversion->size)
+ {
+ output_cursor = output_diversion->u.buffer + output_diversion->used;
output_unused = output_diversion->size - output_diversion->used;
+ }
+ else
+ output_file = output_diversion->u.file;
output_current_line = -1;
}
@@ -515,59 +590,66 @@
}
}
-/*-------------------------------------------------------------------------.
-| 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. |
-`-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Insert DIVERSION (but not div0) 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
-insert_diversion (int divnum)
+static void
+insert_diversion_helper (m4_diversion *diversion)
{
- struct diversion *diversion;
-
- /* Do not care about unexisting diversions. Also, diversion 0 is stdout,
- which is effectively always empty. */
-
- if (divnum <= 0 || divnum >= diversions)
- return;
-
- /* Also avoid undiverting into self. */
-
- diversion = diversion_table + divnum;
- if (diversion == output_diversion)
- return;
-
/* Effectively undivert only if an output stream is active. */
-
if (output_diversion)
{
- if (diversion->file)
+ if (diversion->size)
+ output_text (diversion->u.buffer, diversion->used);
+ else if (diversion->u.file)
{
- rewind (diversion->file);
- insert_file (diversion->file);
+ rewind (diversion->u.file);
+ insert_file (diversion->u.file);
}
- else if (diversion->buffer)
- output_text (diversion->buffer, diversion->used);
output_current_line = -1;
}
/* Return all space used by the diversion. */
-
- if (diversion->file)
+ if (diversion->size)
{
- if (close_stream_temp (diversion->file) != 0)
- M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
- diversion->file = NULL;
- }
- else if (diversion->buffer)
- {
- free (diversion->buffer);
- diversion->buffer = NULL;
+ free (diversion->u.buffer);
diversion->size = 0;
diversion->used = 0;
}
+ else if (diversion->u.file && close_stream_temp (diversion->u.file) != 0)
+ M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+ gl_oset_remove (diversion_table, diversion);
+ 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
+insert_diversion (int divnum)
+{
+ const void *elt;
+
+ /* Do not care about nonexistent diversions, and undiverting stdout
+ or self is a no-op. */
+ if (divnum <= 0 || current_diversion == divnum)
+ return;
+ 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 (diversion);
+ }
}
/*-------------------------------------------------------------------------.
@@ -578,10 +660,15 @@
void
undivert_all (void)
{
- int divnum;
-
- for (divnum = 1; divnum < diversions; divnum++)
- insert_diversion (divnum);
+ const void *elt;
+ gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
+ while (gl_oset_iterator_next (&iter, &elt))
+ {
+ m4_diversion *diversion = (m4_diversion *) elt;
+ if (diversion->divnum != current_diversion)
+ insert_diversion_helper (diversion);
+ }
+ gl_oset_iterator_free (&iter);
}
/*-------------------------------------------------------------.
@@ -593,38 +680,39 @@
{
int saved_number;
int last_inserted;
- int divnum;
- struct diversion *diversion;
- struct stat file_stat;
+ gl_oset_iterator_t iter;
+ const void *elt;
saved_number = current_diversion;
last_inserted = 0;
make_diversion (0);
output_file = file; /* kludge in the frozen file */
- for (divnum = 1; divnum < diversions; divnum++)
+ iter = gl_oset_iterator (diversion_table);
+ while (gl_oset_iterator_next (&iter, &elt))
{
- diversion = diversion_table + divnum;
- if (diversion->file || diversion->buffer)
+ m4_diversion *diversion = (m4_diversion *) elt;;
+ if (diversion->size || diversion->u.file)
{
- if (diversion->file)
+ if (diversion->size)
+ fprintf (file, "D%d,%d\n", diversion->divnum, diversion->used);
+ else
{
- fflush (diversion->file);
- if (fstat (fileno (diversion->file), &file_stat) < 0)
+ struct stat file_stat;
+ fflush (diversion->u.file);
+ if (fstat (fileno (diversion->u.file), &file_stat) < 0)
M4ERROR ((EXIT_FAILURE, errno, "cannot stat diversion"));
if (file_stat.st_size < 0
- || file_stat.st_size != (unsigned long) file_stat.st_size)
+ || file_stat.st_size != (unsigned long int) file_stat.st_size)
M4ERROR ((EXIT_FAILURE, 0, "diversion too large"));
- fprintf (file, "D%d,%lu", divnum,
+ fprintf (file, "D%d,%lu", diversion->divnum,
(unsigned long int) file_stat.st_size);
}
- else
- fprintf (file, "D%d,%d\n", divnum, diversion->used);
- insert_diversion (divnum);
+ insert_diversion_helper (diversion);
putc ('\n', file);
- last_inserted = divnum;
+ last_inserted = diversion->divnum;
}
}
- Changes to m4/src/Attic/output.c,v [branch-1_4], Eric Blake, 2006/11/01
- Changes to m4/src/Attic/output.c,v [branch-1_4], Eric Blake, 2006/11/08
- Changes to m4/src/Attic/output.c,v [branch-1_4],
Eric Blake <=
- Changes to m4/src/Attic/output.c,v [branch-1_4], Eric Blake, 2006/11/13
- Changes to m4/src/Attic/output.c,v [branch-1_4], Eric Blake, 2006/11/14