maint: run update-copyright for 2014.
[m4/ericb.git] / m4 / output.c
blobbf3c599a94d5aa73f87ff8daae979f349a6b6d6c
1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 1989-1994, 1998, 2002, 2004, 2006-2010, 2013-2014 Free
3 Software Foundation, Inc.
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 #include <sys/stat.h>
25 #include "m4private.h"
27 #include "binary-io.h"
28 #include "clean-temp.h"
29 #include "exitfail.h"
30 #include "gl_avltree_oset.h"
31 #include "gl_xoset.h"
32 #include "intprops.h"
33 #include "quotearg.h"
34 #include "xvasprintf.h"
36 /* Define this to see runtime debug output. Implied by DEBUG. */
37 /*#define DEBUG_OUTPUT */
39 /* Size of initial in-memory buffer size for diversions. Small diversions
40 would usually fit in. */
41 #define INITIAL_BUFFER_SIZE 512
43 /* Maximum value for the total of all in-memory buffer sizes for
44 diversions. */
45 #define MAXIMUM_TOTAL_SIZE (512 * 1024)
47 /* Size of buffer size to use while copying files. */
48 #define COPY_BUFFER_SIZE (32 * 512)
50 /* Output functions. Most of the complexity is for handling cpp like
51 sync lines.
53 This code is fairly entangled with the code in input.c, and maybe it
54 belongs there? */
56 typedef struct temp_dir m4_temp_dir;
58 /* When part of diversion_table, each struct m4_diversion either
59 represents an open file (zero size, non-NULL u.file), an in-memory
60 buffer (non-zero size, non-NULL u.buffer), or an unused placeholder
61 diversion (zero size, u is NULL, non-zero used indicates that a
62 temporary file exists). When not part of diversion_table, u.next
63 is a pointer to the free_list chain. */
65 typedef struct m4_diversion m4_diversion;
67 struct m4_diversion
69 union
71 FILE *file; /* Diversion file on disk. */
72 char *buffer; /* Malloc'd diversion buffer. */
73 m4_diversion *next; /* Free-list pointer */
74 } u;
75 int divnum; /* Which diversion this represents. */
76 size_t size; /* Usable size before reallocation. */
77 size_t used; /* Used buffer length, or tmp file exists. */
80 /* Sorted set of diversions 1 through INT_MAX. */
81 static gl_oset_t diversion_table;
83 /* Diversion 0 (not part of diversion_table). */
84 static m4_diversion div0;
86 /* Linked list of reclaimed diversion storage. */
87 static m4_diversion *free_list;
89 /* Obstack from which diversion storage is allocated. */
90 static m4_obstack diversion_storage;
92 /* Total size of all in-memory buffer sizes. */
93 static size_t total_buffer_size;
95 /* Current output diversion, NULL if output is being currently
96 discarded. output_diversion->u is guaranteed non-NULL except when
97 the diversion has never been used; use size to determine if it is a
98 malloc'd buffer or a FILE. output_diversion->used is 0 if u.file
99 is stdout, and non-zero if this is a malloc'd buffer or a temporary
100 diversion file. */
101 static m4_diversion *output_diversion;
103 /* Cache of output_diversion->u.file, only valid when
104 output_diversion->size is 0. */
105 static FILE *output_file;
107 /* Cache of output_diversion->u.buffer + output_diversion->used, only
108 valid when output_diversion->size is non-zero. */
109 static char *output_cursor;
111 /* Cache of output_diversion->size - output_diversion->used, only
112 valid when output_diversion->size is non-zero. */
113 static size_t output_unused;
115 /* Temporary directory holding all spilled diversion files. */
116 static m4_temp_dir *output_temp_dir;
118 /* Cache of most recently used spilled diversion files. */
119 static FILE *tmp_file1;
120 static FILE *tmp_file2;
122 /* Diversions that own tmp_file, or 0. */
123 static int tmp_file1_owner;
124 static int tmp_file2_owner;
126 /* True if tmp_file2 is more recently used. */
127 static bool tmp_file2_recent;
130 /* Internal routines. */
132 /* Callback for comparing list elements ELT1 and ELT2 for order in
133 diversion_table. */
134 static int
135 cmp_diversion_CB (const void *elt1, const void *elt2)
137 const m4_diversion *d1 = (const m4_diversion *) elt1;
138 const m4_diversion *d2 = (const m4_diversion *) elt2;
139 /* No need to worry about overflow, since we don't create diversions
140 with negative divnum. */
141 return d1->divnum - d2->divnum;
144 /* Callback for comparing list element ELT against THRESHOLD. */
145 static bool
146 threshold_diversion_CB (const void *elt, const void *threshold)
148 const m4_diversion *diversion = (const m4_diversion *) elt;
149 /* No need to worry about overflow, since we don't create diversions
150 with negative divnum. */
151 return diversion->divnum >= *(const int *) threshold;
154 /* Clean up any temporary directory. Designed for use as an atexit
155 handler, where it is not safe to call exit() recursively; so this
156 calls _exit if a problem is encountered. */
157 static void
158 cleanup_tmpfile (void)
160 /* Close any open diversions. */
161 bool fail = false;
163 if (diversion_table)
165 const void *elt;
166 gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
167 while (gl_oset_iterator_next (&iter, &elt))
169 m4_diversion *diversion = (m4_diversion *) elt;
170 if (!diversion->size && diversion->u.file
171 && close_stream_temp (diversion->u.file) != 0)
173 error (0, errno,
174 _("cannot clean temporary file for diversion"));
175 fail = true;
178 gl_oset_iterator_free (&iter);
181 /* Clean up the temporary directory. */
182 if (cleanup_temp_dir (output_temp_dir) != 0)
183 fail = true;
184 if (fail)
185 _exit (exit_failure);
188 /* Convert DIVNUM into a temporary file name for use in m4_tmp*. */
189 static const char *
190 m4_tmpname (int divnum)
192 static char *buffer;
193 static size_t offset;
194 if (buffer == NULL)
196 obstack_printf (&diversion_storage, "%s/m4-", output_temp_dir->dir_name);
197 offset = obstack_object_size (&diversion_storage);
198 buffer = (char *) obstack_alloc (&diversion_storage,
199 INT_BUFSIZE_BOUND (divnum));
201 assert (0 < divnum);
202 if (snprintf (&buffer[offset], INT_BUFSIZE_BOUND (divnum), "%d", divnum) < 0)
203 abort ();
204 return buffer;
207 /* Create a temporary file for diversion DIVNUM open for reading and
208 writing in a secure temp directory. The file will be automatically
209 closed and deleted on a fatal signal. The file can be closed and
210 reopened with m4_tmpclose and m4_tmpopen, or moved with
211 m4_tmprename; when finally done with the file, close it with
212 m4_tmpremove. Exits on failure, so the return value is always an
213 open file. */
214 static FILE *
215 m4_tmpfile (m4 *context, int divnum)
217 const char *name;
218 FILE *file;
220 if (output_temp_dir == NULL)
222 output_temp_dir = create_temp_dir ("m4-", NULL, true);
223 if (output_temp_dir == NULL)
224 m4_error (context, EXIT_FAILURE, errno, NULL,
225 _("cannot create temporary file for diversion"));
226 atexit (cleanup_tmpfile);
228 name = m4_tmpname (divnum);
229 register_temp_file (output_temp_dir, name);
230 file = fopen_temp (name, O_BINARY ? "wb+" : "w+");
231 if (file == NULL)
233 unregister_temp_file (output_temp_dir, name);
234 m4_error (context, EXIT_FAILURE, errno, NULL,
235 _("cannot create temporary file for diversion"));
237 else if (set_cloexec_flag (fileno (file), true) != 0)
238 m4_warn (context, errno, NULL, _("cannot protect diversion across forks"));
239 return file;
242 /* Reopen a temporary file for diversion DIVNUM for reading and
243 writing in a secure temp directory. If REREAD, the file is
244 positioned at offset 0, otherwise the file is positioned at the
245 end. Exits on failure, so the return value is always an open
246 file. */
247 static FILE *
248 m4_tmpopen (m4 *context, int divnum, bool reread)
250 const char *name;
251 FILE *file;
253 if (tmp_file1_owner == divnum)
255 if (reread && fseeko (tmp_file1, 0, SEEK_SET) != 0)
256 m4_error (context, EXIT_FAILURE, errno, NULL,
257 _("cannot seek within diversion"));
258 tmp_file2_recent = false;
259 return tmp_file1;
261 else if (tmp_file2_owner == divnum)
263 if (reread && fseeko (tmp_file2, 0, SEEK_SET) != 0)
264 m4_error (context, EXIT_FAILURE, errno, NULL,
265 _("cannot seek to beginning of diversion"));
266 tmp_file2_recent = true;
267 return tmp_file2;
269 name = m4_tmpname (divnum);
270 /* We need update mode, to avoid truncation. */
271 file = fopen_temp (name, O_BINARY ? "rb+" : "r+");
272 if (file == NULL)
273 m4_error (context, EXIT_FAILURE, errno, NULL,
274 _("cannot create temporary file for diversion"));
275 else if (set_cloexec_flag (fileno (file), true) != 0)
276 m4_warn (context, errno, NULL, _("cannot protect diversion across forks"));
277 /* Update mode starts at the beginning of the stream, but sometimes
278 we want the end. */
279 else if (!reread && fseeko (file, 0, SEEK_END) != 0)
280 m4_error (context, EXIT_FAILURE, errno, NULL,
281 _("cannot seek within diversion"));
282 return file;
285 /* Close, but don't delete, a temporary FILE for diversion DIVNUM. To
286 reduce the I/O overhead of repeatedly opening and closing the same
287 file, this implementation caches the most recent spilled diversion.
288 On the other hand, keeping every spilled diversion open would run
289 into EMFILE limits. */
290 static int
291 m4_tmpclose (FILE *file, int divnum)
293 int result = 0;
294 if (divnum != tmp_file1_owner && divnum != tmp_file2_owner)
296 if (tmp_file2_recent)
298 if (tmp_file1_owner)
299 result = close_stream_temp (tmp_file1);
300 tmp_file1 = file;
301 tmp_file1_owner = divnum;
303 else
305 if (tmp_file2_owner)
306 result = close_stream_temp (tmp_file2);
307 tmp_file2 = file;
308 tmp_file2_owner = divnum;
311 return result;
314 /* Delete a closed temporary FILE for diversion DIVNUM. */
315 static int
316 m4_tmpremove (int divnum)
318 if (divnum == tmp_file1_owner)
320 int result = close_stream_temp (tmp_file1);
321 if (result)
322 return result;
323 tmp_file1_owner = 0;
325 else if (divnum == tmp_file2_owner)
327 int result = close_stream_temp (tmp_file2);
328 if (result)
329 return result;
330 tmp_file2_owner = 0;
332 return cleanup_temp_file (output_temp_dir, m4_tmpname (divnum));
335 /* Transfer the temporary file for diversion OLDNUM to the previously
336 unused diversion NEWNUM. Return an open stream visiting the new
337 temporary file, positioned at the end, or exit on failure. */
338 static FILE*
339 m4_tmprename (m4 *context, int oldnum, int newnum)
341 /* m4_tmpname reuses its return buffer. */
342 char *oldname = xstrdup (m4_tmpname (oldnum));
343 const char *newname = m4_tmpname (newnum);
344 register_temp_file (output_temp_dir, newname);
345 if (oldnum == tmp_file1_owner)
347 /* Be careful of mingw, which can't rename an open file. */
348 if (RENAME_OPEN_FILE_WORKS)
349 tmp_file1_owner = newnum;
350 else
352 if (close_stream_temp (tmp_file1))
353 m4_error (context, EXIT_FAILURE, errno, NULL,
354 _("cannot close temporary file for diversion"));
355 tmp_file1_owner = 0;
358 else if (oldnum == tmp_file2_owner)
360 /* Be careful of mingw, which can't rename an open file. */
361 if (RENAME_OPEN_FILE_WORKS)
362 tmp_file2_owner = newnum;
363 else
365 if (close_stream_temp (tmp_file2))
366 m4_error (context, EXIT_FAILURE, errno, NULL,
367 _("cannot close temporary file for diversion"));
368 tmp_file2_owner = 0;
371 /* Either it is safe to rename an open file, or no one should have
372 oldname open at this point. */
373 if (rename (oldname, newname))
374 m4_error (context, EXIT_FAILURE, errno, NULL,
375 _("cannot create temporary file for diversion"));
376 unregister_temp_file (output_temp_dir, oldname);
377 free (oldname);
378 return m4_tmpopen (context, newnum, false);
382 /* --- OUTPUT INITIALIZATION --- */
384 /* Initialize the output engine. */
385 void
386 m4_output_init (m4 *context)
388 diversion_table = gl_oset_create_empty (GL_AVLTREE_OSET, cmp_diversion_CB,
389 NULL);
390 div0.u.file = stdout;
391 m4_set_current_diversion (context, 0);
392 output_diversion = &div0;
393 output_file = stdout;
394 obstack_init (&diversion_storage);
397 /* Clean up memory allocated during use. */
398 void
399 m4_output_exit (void)
401 /* Order is important, since we may have registered cleanup_tmpfile
402 as an atexit handler, and it must not traverse stale memory. */
403 gl_oset_t table = diversion_table;
404 assert (gl_oset_size (diversion_table) == 0);
405 if (tmp_file1_owner)
406 m4_tmpremove (tmp_file1_owner);
407 if (tmp_file2_owner)
408 m4_tmpremove (tmp_file2_owner);
409 diversion_table = NULL;
410 gl_oset_free (table);
411 obstack_free (&diversion_storage, NULL);
414 /* Reorganize in-memory diversion buffers so the current diversion can
415 accomodate LENGTH more characters without further reorganization. The
416 current diversion buffer is made bigger if possible. But to make room
417 for a bigger buffer, one of the in-memory diversion buffers might have
418 to be flushed to a newly created temporary file. This flushed buffer
419 might well be the current one. */
420 static void
421 make_room_for (m4 *context, size_t length)
423 size_t wanted_size;
424 m4_diversion *selected_diversion = NULL;
426 assert (!output_file);
427 assert (output_diversion);
428 assert (output_diversion->size || !output_diversion->u.file);
430 /* Compute needed size for in-memory buffer. Diversions in-memory
431 buffers start at 0 bytes, then 512, then keep doubling until it is
432 decided to flush them to disk. */
434 output_diversion->used = output_diversion->size - output_unused;
436 for (wanted_size = output_diversion->size;
437 wanted_size <= MAXIMUM_TOTAL_SIZE
438 && wanted_size - output_diversion->used < length;
439 wanted_size = wanted_size == 0 ? INITIAL_BUFFER_SIZE : wanted_size * 2)
442 /* Check if we are exceeding the maximum amount of buffer memory. */
444 if (total_buffer_size - output_diversion->size + wanted_size
445 > MAXIMUM_TOTAL_SIZE)
447 size_t selected_used;
448 char *selected_buffer;
449 m4_diversion *diversion;
450 size_t count;
451 gl_oset_iterator_t iter;
452 const void *elt;
454 /* Find out the buffer having most data, in view of flushing it to
455 disk. Fake the current buffer as having already received the
456 projected data, while making the selection. So, if it is
457 selected indeed, we will flush it smaller, before it grows. */
459 selected_diversion = output_diversion;
460 selected_used = output_diversion->used + length;
462 iter = gl_oset_iterator (diversion_table);
463 while (gl_oset_iterator_next (&iter, &elt))
465 diversion = (m4_diversion *) elt;
466 if (diversion->used > selected_used)
468 selected_diversion = diversion;
469 selected_used = diversion->used;
472 gl_oset_iterator_free (&iter);
474 /* Create a temporary file, write the in-memory buffer of the
475 diversion to this file, then release the buffer. Zero the
476 diversion before doing anything that can exit () (including
477 m4_tmpfile), so that the atexit handler doesn't try to close
478 a garbage pointer as a file. */
480 selected_buffer = selected_diversion->u.buffer;
481 total_buffer_size -= selected_diversion->size;
482 selected_diversion->size = 0;
483 selected_diversion->u.file = NULL;
484 selected_diversion->u.file = m4_tmpfile (context,
485 selected_diversion->divnum);
487 if (selected_diversion->used > 0)
489 count = fwrite (selected_buffer, selected_diversion->used, 1,
490 selected_diversion->u.file);
491 if (count != 1)
492 m4_error (context, EXIT_FAILURE, errno, NULL,
493 _("cannot flush diversion to temporary file"));
496 /* Reclaim the buffer space for other diversions. */
498 free (selected_buffer);
499 selected_diversion->used = 1;
502 /* Reload output_file, just in case the flushed diversion was current. */
504 if (output_diversion == selected_diversion)
506 /* The flushed diversion was current indeed. */
508 output_file = output_diversion->u.file;
509 output_cursor = NULL;
510 output_unused = 0;
512 else
514 /* Close any selected file since it is not the current diversion. */
515 if (selected_diversion)
517 FILE *file = selected_diversion->u.file;
518 selected_diversion->u.file = NULL;
519 if (m4_tmpclose (file, selected_diversion->divnum) != 0)
520 m4_error (context, 0, errno, NULL,
521 _("cannot close temporary file for diversion"));
524 /* The current buffer may be safely reallocated. */
525 assert (wanted_size >= length);
527 char *buffer = output_diversion->u.buffer;
528 output_diversion->u.buffer = xcharalloc ((size_t) wanted_size);
529 memcpy (output_diversion->u.buffer, buffer, output_diversion->used);
530 free (buffer);
533 total_buffer_size += wanted_size - output_diversion->size;
534 output_diversion->size = wanted_size;
536 output_cursor = output_diversion->u.buffer + output_diversion->used;
537 output_unused = wanted_size - output_diversion->used;
541 /* Output one character CHAR, when it is known that it goes to a
542 diversion file or an in-memory diversion buffer. A variable m4
543 *context must be in scope. */
544 #define OUTPUT_CHARACTER(Char) \
545 if (output_file) \
546 putc ((Char), output_file); \
547 else if (output_unused == 0) \
548 output_character_helper (context, (Char)); \
549 else \
550 (output_unused--, *output_cursor++ = (Char))
552 static void
553 output_character_helper (m4 *context, int character)
555 make_room_for (context, 1);
557 if (output_file)
558 putc (character, output_file);
559 else
561 *output_cursor++ = character;
562 output_unused--;
566 /* Output one TEXT having LENGTH characters, when it is known that it goes
567 to a diversion file or an in-memory diversion buffer. */
568 void
569 m4_output_text (m4 *context, const char *text, size_t length)
571 size_t count;
573 if (!output_diversion || !length)
574 return;
576 if (!output_file && length > output_unused)
577 make_room_for (context, length);
579 if (output_file)
581 count = fwrite (text, length, 1, output_file);
582 if (count != 1)
583 m4_error (context, EXIT_FAILURE, errno, NULL,
584 _("copying inserted file"));
586 else
588 memcpy (output_cursor, text, length);
589 output_cursor += length;
590 output_unused -= length;
594 /* Add some text into an obstack OBS, taken from TEXT, having LENGTH
595 characters. If OBS is NULL, output the text to an external file or
596 an in-memory diversion buffer instead. If OBS is NULL, and there
597 is no output file, the text is discarded. LINE is the line where
598 the token starts (not necessarily m4_get_output_line, in the case
599 of multiline tokens).
601 If we are generating sync lines, the output has to be examined,
602 because we need to know how much output each input line generates.
603 In general, sync lines are output whenever a single input line
604 generates several output lines, or when several input lines do not
605 generate any output. */
606 void
607 m4_divert_text (m4 *context, m4_obstack *obs, const char *text, size_t length,
608 int line)
610 static bool start_of_output_line = true;
612 /* If output goes to an obstack, merely add TEXT to it. */
614 if (obs != NULL)
616 obstack_grow (obs, text, length);
617 return;
620 /* Do nothing if TEXT should be discarded. */
622 if (!output_diversion || !length)
623 return;
625 /* Output TEXT to a file, or in-memory diversion buffer. */
627 if (!m4_get_syncoutput_opt (context))
628 switch (length)
631 /* In-line short texts. */
633 case 8: OUTPUT_CHARACTER (*text); text++;
634 case 7: OUTPUT_CHARACTER (*text); text++;
635 case 6: OUTPUT_CHARACTER (*text); text++;
636 case 5: OUTPUT_CHARACTER (*text); text++;
637 case 4: OUTPUT_CHARACTER (*text); text++;
638 case 3: OUTPUT_CHARACTER (*text); text++;
639 case 2: OUTPUT_CHARACTER (*text); text++;
640 case 1: OUTPUT_CHARACTER (*text);
641 case 0:
642 return;
644 /* Optimize longer texts. */
646 default:
647 m4_output_text (context, text, length);
649 else
651 /* Check for syncline only at the start of a token. Multiline
652 tokens, and tokens that are out of sync but in the middle of
653 the line, must wait until the next raw newline triggers a
654 syncline. */
655 if (start_of_output_line)
657 start_of_output_line = false;
658 m4_set_output_line (context, m4_get_output_line (context) + 1);
660 #ifdef DEBUG_OUTPUT
661 xfprintf (stderr, "DEBUG: line %d, cur %lu, cur out %lu\n", line,
662 (unsigned long int) m4_get_current_line (context),
663 (unsigned long int) m4_get_output_line (context));
664 #endif
666 /* Output a `#line NUM' synchronization directive if needed.
667 If output_line was previously given a negative
668 value (invalidated), then output `#line NUM "FILE"'. */
670 if (m4_get_output_line (context) != line)
672 char linebuf[sizeof "#line " + INT_BUFSIZE_BOUND (line)];
673 sprintf (linebuf, "#line %lu",
674 (unsigned long int) m4_get_current_line (context));
675 m4_output_text (context, linebuf, strlen (linebuf));
676 if (m4_get_output_line (context) < 1
677 && m4_get_current_file (context)[0] != '\0')
679 const char *file = m4_get_current_file (context);
680 OUTPUT_CHARACTER (' ');
681 OUTPUT_CHARACTER ('"');
682 m4_output_text (context, file, strlen (file));
683 OUTPUT_CHARACTER ('"');
685 OUTPUT_CHARACTER ('\n');
686 m4_set_output_line (context, line);
690 /* Output the token, and track embedded newlines. */
691 for (; length-- > 0; text++)
693 if (start_of_output_line)
695 start_of_output_line = false;
696 m4_set_output_line (context, m4_get_output_line (context) + 1);
698 #ifdef DEBUG_OUTPUT
699 xfprintf (stderr, "DEBUG: line %d, cur %lu, cur out %lu\n", line,
700 (unsigned long int) m4_get_current_line (context),
701 (unsigned long int) m4_get_output_line (context));
702 #endif
704 OUTPUT_CHARACTER (*text);
705 if (*text == '\n')
706 start_of_output_line = true;
711 /* Format an int VAL, and stuff it into an obstack OBS. Used for
712 macros expanding to numbers. FIXME - support wider types, and
713 unsigned types. */
714 void
715 m4_shipout_int (m4_obstack *obs, int val)
717 /* Using obstack_printf (obs, "%d", val) has too much overhead. */
718 unsigned int uval;
719 char buf[INT_BUFSIZE_BOUND (unsigned int)];
720 char *p = buf + INT_STRLEN_BOUND (unsigned int);
722 if (val < 0)
724 obstack_1grow (obs, '-');
725 uval = -(unsigned int) val;
727 else
728 uval = val;
729 *p = '\0';
731 *--p = '0' + uval % 10;
732 while (uval /= 10);
733 obstack_grow (obs, p, strlen (p));
736 /* Output the text S, of length LEN, to OBS. If QUOTED, also output
737 current quote characters around S. If LEN is SIZE_MAX, use the
738 string length of S instead. */
739 void
740 m4_shipout_string (m4 *context, m4_obstack *obs, const char *s, size_t len,
741 bool quoted)
743 m4_shipout_string_trunc (obs, s, len,
744 quoted ? m4_get_syntax_quotes (M4SYNTAX) : NULL,
745 NULL);
748 /* Output the text S, of length LEN, to OBS. If QUOTES, also output
749 quote characters around S. If LEN is SIZE_MAX, use the string
750 length of S instead. If MAX_LEN, reduce *MAX_LEN by LEN. If LEN
751 is larger than *MAX_LEN, then truncate output and return true;
752 otherwise return false. Quotes do not count against MAX_LEN. */
753 bool
754 m4_shipout_string_trunc (m4_obstack *obs, const char *s, size_t len,
755 const m4_string_pair *quotes, size_t *max_len)
757 size_t max = max_len ? *max_len : SIZE_MAX;
759 assert (obs && s);
760 if (len == SIZE_MAX)
761 len = strlen (s);
762 if (quotes)
763 obstack_grow (obs, quotes->str1, quotes->len1);
764 if (len < max)
766 obstack_grow (obs, s, len);
767 max -= len;
769 else
771 obstack_grow (obs, s, max);
772 obstack_grow (obs, "...", 3);
773 max = 0;
775 if (quotes)
776 obstack_grow (obs, quotes->str2, quotes->len2);
777 if (max_len)
778 *max_len = max;
779 return max == 0;
784 /* --- FUNCTIONS FOR USE BY DIVERSIONS --- */
786 /* Make a file for diversion DIVNUM, and install it in the diversion table.
787 Grow the size of the diversion table as needed. */
789 /* The number of possible diversions is limited only by memory and
790 available file descriptors (each overflowing diversion uses one). */
792 void
793 m4_make_diversion (m4 *context, int divnum)
795 m4_diversion *diversion = NULL;
797 if (m4_get_current_diversion (context) == divnum)
798 return;
800 if (output_diversion)
802 assert (!output_file || output_diversion->u.file == output_file);
803 assert (output_diversion->divnum != divnum);
804 if (!output_diversion->size && !output_diversion->u.file)
806 assert (!output_diversion->used);
807 if (!gl_oset_remove (diversion_table, output_diversion))
808 assert (false);
809 output_diversion->u.next = free_list;
810 free_list = output_diversion;
812 else if (output_diversion->size)
813 output_diversion->used = output_diversion->size - output_unused;
814 else if (output_diversion->used)
816 assert (output_diversion->divnum != 0);
817 FILE *file = output_diversion->u.file;
818 output_diversion->u.file = NULL;
819 if (m4_tmpclose (file, output_diversion->divnum) != 0)
820 m4_error (context, 0, errno, NULL,
821 _("cannot close temporary file for diversion"));
823 output_diversion = NULL;
824 output_file = NULL;
825 output_cursor = NULL;
826 output_unused = 0;
829 m4_set_current_diversion (context, divnum);
831 if (divnum < 0)
832 return;
834 if (divnum == 0)
835 diversion = &div0;
836 else
838 const void *elt;
839 if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
840 &divnum, &elt))
842 m4_diversion *temp = (m4_diversion *) elt;
843 if (temp->divnum == divnum)
844 diversion = temp;
847 if (diversion == NULL)
849 /* First time visiting this diversion. */
850 if (free_list)
852 diversion = free_list;
853 free_list = diversion->u.next;
854 assert (!diversion->size && !diversion->used);
856 else
858 diversion = (m4_diversion *) obstack_alloc (&diversion_storage,
859 sizeof *diversion);
860 diversion->size = 0;
861 diversion->used = 0;
863 diversion->u.file = NULL;
864 diversion->divnum = divnum;
865 if (!gl_oset_add (diversion_table, diversion))
866 assert (false);
869 output_diversion = diversion;
870 if (output_diversion->size)
872 output_cursor = output_diversion->u.buffer + output_diversion->used;
873 output_unused = output_diversion->size - output_diversion->used;
875 else
877 if (!output_diversion->u.file && output_diversion->used)
878 output_diversion->u.file = m4_tmpopen (context,
879 output_diversion->divnum,
880 false);
881 output_file = output_diversion->u.file;
884 m4_set_output_line (context, -1);
887 /* Insert a FILE into the current output file, in the same manner
888 diversions are handled. If ESCAPED, ensure the output is all
889 ASCII. */
890 static void
891 insert_file (m4 *context, FILE *file, bool escaped)
893 static char buffer[COPY_BUFFER_SIZE];
894 size_t length;
895 char *str = buffer;
896 bool first = true;
898 assert (output_diversion);
899 /* Insert output by big chunks. */
900 while (1)
902 length = fread (buffer, 1, sizeof buffer, file);
903 if (ferror (file))
904 m4_error (context, EXIT_FAILURE, errno, NULL,
905 _("reading inserted file"));
906 if (length == 0)
907 break;
908 if (escaped)
910 if (first)
911 first = false;
912 else
913 m4_output_text (context, "\\\n", 2);
914 str = quotearg_style_mem (escape_quoting_style, buffer, length);
916 m4_output_text (context, str, escaped ? strlen (str) : length);
920 /* Insert a FILE into the current output file, in the same manner
921 diversions are handled. This allows files to be included, without
922 having them rescanned by m4. */
923 void
924 m4_insert_file (m4 *context, FILE *file)
926 /* Optimize out inserting into a sink. */
927 if (output_diversion)
928 insert_file (context, file, false);
931 /* Insert DIVERSION living at NODE into the current output file. The
932 diversion is NOT placed on the expansion obstack, because it must
933 not be rescanned. If ESCAPED, ensure the output is ASCII. When
934 the file is closed, it is deleted by the system. */
935 static void
936 insert_diversion_helper (m4 *context, m4_diversion *diversion, bool escaped)
938 assert (diversion->divnum > 0
939 && diversion->divnum != m4_get_current_diversion (context));
940 /* Effectively undivert only if an output stream is active. */
941 if (output_diversion)
943 if (diversion->size)
945 if (!output_diversion->u.file)
947 /* Transferring diversion metadata is faster than
948 copying contents. */
949 assert (!output_diversion->used && output_diversion != &div0
950 && !output_file);
951 output_diversion->u.buffer = diversion->u.buffer;
952 output_diversion->size = diversion->size;
953 output_cursor = diversion->u.buffer + diversion->used;
954 output_unused = diversion->size - diversion->used;
955 diversion->u.buffer = NULL;
957 else
959 char *str = diversion->u.buffer;
960 size_t len = diversion->used;
961 /* Avoid double-charging the total in-memory size when
962 transferring from one in-memory diversion to
963 another. */
964 total_buffer_size -= diversion->size;
965 if (escaped)
966 str = quotearg_style_mem (escape_quoting_style, str, len);
967 m4_output_text (context, str, escaped ? strlen (str) : len);
970 else if (!output_diversion->u.file)
972 /* Transferring diversion metadata is faster than copying
973 contents. */
974 assert (!output_diversion->used && output_diversion != &div0
975 && !output_file);
976 output_diversion->u.file = m4_tmprename (context, diversion->divnum,
977 output_diversion->divnum);
978 output_diversion->used = 1;
979 output_file = output_diversion->u.file;
980 diversion->u.file = NULL;
981 diversion->size = 1;
983 else
985 assert (diversion->used);
986 if (!diversion->u.file)
987 diversion->u.file = m4_tmpopen (context, diversion->divnum, true);
988 insert_file (context, diversion->u.file, escaped);
991 m4_set_output_line (context, -1);
994 /* Return all space used by the diversion. */
995 if (diversion->size)
997 if (!output_diversion)
998 total_buffer_size -= diversion->size;
999 free (diversion->u.buffer);
1000 diversion->size = 0;
1002 else
1004 if (diversion->u.file)
1006 FILE *file = diversion->u.file;
1007 diversion->u.file = NULL;
1008 if (m4_tmpclose (file, diversion->divnum) != 0)
1009 m4_error (context, 0, errno, NULL,
1010 _("cannot clean temporary file for diversion"));
1012 if (m4_tmpremove (diversion->divnum) != 0)
1013 m4_error (context, 0, errno, NULL,
1014 _("cannot clean temporary file for diversion"));
1016 diversion->used = 0;
1017 if (!gl_oset_remove (diversion_table, diversion))
1018 assert (false);
1019 diversion->u.next = free_list;
1020 free_list = diversion;
1023 /* Insert diversion number DIVNUM into the current output file. The
1024 diversion is NOT placed on the expansion obstack, because it must not
1025 be rescanned. When the file is closed, it is deleted by the system. */
1026 void
1027 m4_insert_diversion (m4 *context, int divnum)
1029 const void *elt;
1031 /* Do not care about nonexistent diversions, and undiverting stdout
1032 or self is a no-op. */
1033 if (divnum <= 0 || m4_get_current_diversion (context) == divnum)
1034 return;
1035 if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
1036 &divnum, &elt))
1038 m4_diversion *diversion = (m4_diversion *) elt;
1039 if (diversion->divnum == divnum)
1040 insert_diversion_helper (context, diversion, false);
1044 /* Get back all diversions. This is done just before exiting from main,
1045 and from m4_undivert (), if called without arguments. */
1046 void
1047 m4_undivert_all (m4 *context)
1049 int divnum = m4_get_current_diversion (context);
1050 const void *elt;
1051 gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
1052 while (gl_oset_iterator_next (&iter, &elt))
1054 m4_diversion *diversion = (m4_diversion *) elt;
1055 if (diversion->divnum != divnum)
1056 insert_diversion_helper (context, diversion, false);
1058 gl_oset_iterator_free (&iter);
1061 /* Produce all diversion information in frozen format on FILE. */
1062 void
1063 m4_freeze_diversions (m4 *context, FILE *file)
1065 int saved_number;
1066 int last_inserted;
1067 gl_oset_iterator_t iter;
1068 const void *elt;
1070 saved_number = m4_get_current_diversion (context);
1071 last_inserted = 0;
1072 m4_make_diversion (context, 0);
1073 output_file = file; /* kludge in the frozen file */
1075 iter = gl_oset_iterator (diversion_table);
1076 while (gl_oset_iterator_next (&iter, &elt))
1078 m4_diversion *diversion = (m4_diversion *) elt;
1079 if (diversion->size || diversion->used)
1081 if (diversion->size)
1083 assert (diversion->used == (int) diversion->used);
1084 xfprintf (file, "D%d,%d\n", diversion->divnum,
1085 (int) diversion->used);
1087 else
1089 struct stat file_stat;
1090 assert (!diversion->u.file);
1091 diversion->u.file = m4_tmpopen (context, diversion->divnum,
1092 true);
1093 if (fstat (fileno (diversion->u.file), &file_stat) < 0)
1094 m4_error (context, EXIT_FAILURE, errno, NULL,
1095 _("cannot stat diversion"));
1096 /* FIXME - support 64-bit off_t with 32-bit long, and
1097 fix frozen file format to support 64-bit integers.
1098 This implies fixing m4_divert_text to take off_t. */
1099 if (file_stat.st_size < 0
1100 || file_stat.st_size != (unsigned long int) file_stat.st_size)
1101 m4_error (context, EXIT_FAILURE, errno, NULL,
1102 _("diversion too large"));
1103 xfprintf (file, "%c%d,%lu\n", 'D', diversion->divnum,
1104 (unsigned long int) file_stat.st_size);
1107 insert_diversion_helper (context, diversion, true);
1108 putc ('\n', file);
1110 last_inserted = diversion->divnum;
1113 gl_oset_iterator_free (&iter);
1115 /* Save the active diversion number, if not already. */
1117 if (saved_number != last_inserted)
1118 xfprintf (file, "D%d,0\n\n", saved_number);