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/>.
25 #include "m4private.h"
27 #include "binary-io.h"
28 #include "clean-temp.h"
30 #include "gl_avltree_oset.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
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
53 This code is fairly entangled with the code in input.c, and maybe it
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
;
71 FILE *file
; /* Diversion file on disk. */
72 char *buffer
; /* Malloc'd diversion buffer. */
73 m4_diversion
*next
; /* Free-list pointer */
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
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
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. */
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. */
158 cleanup_tmpfile (void)
160 /* Close any open diversions. */
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)
174 _("cannot clean temporary file for diversion"));
178 gl_oset_iterator_free (&iter
);
181 /* Clean up the temporary directory. */
182 if (cleanup_temp_dir (output_temp_dir
) != 0)
185 _exit (exit_failure
);
188 /* Convert DIVNUM into a temporary file name for use in m4_tmp*. */
190 m4_tmpname (int divnum
)
193 static size_t offset
;
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
));
202 if (snprintf (&buffer
[offset
], INT_BUFSIZE_BOUND (divnum
), "%d", divnum
) < 0)
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
215 m4_tmpfile (m4
*context
, int divnum
)
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+");
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"));
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
248 m4_tmpopen (m4
*context
, int divnum
, bool reread
)
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;
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;
269 name
= m4_tmpname (divnum
);
270 /* We need update mode, to avoid truncation. */
271 file
= fopen_temp (name
, O_BINARY
? "rb+" : "r+");
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
279 else if (!reread
&& fseeko (file
, 0, SEEK_END
) != 0)
280 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
281 _("cannot seek within diversion"));
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. */
291 m4_tmpclose (FILE *file
, int divnum
)
294 if (divnum
!= tmp_file1_owner
&& divnum
!= tmp_file2_owner
)
296 if (tmp_file2_recent
)
299 result
= close_stream_temp (tmp_file1
);
301 tmp_file1_owner
= divnum
;
306 result
= close_stream_temp (tmp_file2
);
308 tmp_file2_owner
= divnum
;
314 /* Delete a closed temporary FILE for diversion DIVNUM. */
316 m4_tmpremove (int divnum
)
318 if (divnum
== tmp_file1_owner
)
320 int result
= close_stream_temp (tmp_file1
);
325 else if (divnum
== tmp_file2_owner
)
327 int result
= close_stream_temp (tmp_file2
);
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. */
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
;
352 if (close_stream_temp (tmp_file1
))
353 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
354 _("cannot close temporary file for diversion"));
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
;
365 if (close_stream_temp (tmp_file2
))
366 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
367 _("cannot close temporary file for diversion"));
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
);
378 return m4_tmpopen (context
, newnum
, false);
382 /* --- OUTPUT INITIALIZATION --- */
384 /* Initialize the output engine. */
386 m4_output_init (m4
*context
)
388 diversion_table
= gl_oset_create_empty (GL_AVLTREE_OSET
, cmp_diversion_CB
,
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. */
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);
406 m4_tmpremove (tmp_file1_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. */
421 make_room_for (m4
*context
, size_t length
)
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
;
451 gl_oset_iterator_t iter
;
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
);
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
;
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
);
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) \
546 putc ((Char), output_file); \
547 else if (output_unused == 0) \
548 output_character_helper (context, (Char)); \
550 (output_unused--, *output_cursor++ = (Char))
553 output_character_helper (m4
*context
, int character
)
555 make_room_for (context
, 1);
558 putc (character
, output_file
);
561 *output_cursor
++ = character
;
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. */
569 m4_output_text (m4
*context
, const char *text
, size_t length
)
573 if (!output_diversion
|| !length
)
576 if (!output_file
&& length
> output_unused
)
577 make_room_for (context
, length
);
581 count
= fwrite (text
, length
, 1, output_file
);
583 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
584 _("copying inserted file"));
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. */
607 m4_divert_text (m4
*context
, m4_obstack
*obs
, const char *text
, size_t length
,
610 static bool start_of_output_line
= true;
612 /* If output goes to an obstack, merely add TEXT to it. */
616 obstack_grow (obs
, text
, length
);
620 /* Do nothing if TEXT should be discarded. */
622 if (!output_diversion
|| !length
)
625 /* Output TEXT to a file, or in-memory diversion buffer. */
627 if (!m4_get_syncoutput_opt (context
))
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
);
644 /* Optimize longer texts. */
647 m4_output_text (context
, text
, length
);
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
655 if (start_of_output_line
)
657 start_of_output_line
= false;
658 m4_set_output_line (context
, m4_get_output_line (context
) + 1);
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
));
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);
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
));
704 OUTPUT_CHARACTER (*text
);
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
715 m4_shipout_int (m4_obstack
*obs
, int val
)
717 /* Using obstack_printf (obs, "%d", val) has too much overhead. */
719 char buf
[INT_BUFSIZE_BOUND (unsigned int)];
720 char *p
= buf
+ INT_STRLEN_BOUND (unsigned int);
724 obstack_1grow (obs
, '-');
725 uval
= -(unsigned int) val
;
731 *--p
= '0' + 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. */
740 m4_shipout_string (m4
*context
, m4_obstack
*obs
, const char *s
, size_t len
,
743 m4_shipout_string_trunc (obs
, s
, len
,
744 quoted
? m4_get_syntax_quotes (M4SYNTAX
) : 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. */
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
;
763 obstack_grow (obs
, quotes
->str1
, quotes
->len1
);
766 obstack_grow (obs
, s
, len
);
771 obstack_grow (obs
, s
, max
);
772 obstack_grow (obs
, "...", 3);
776 obstack_grow (obs
, quotes
->str2
, quotes
->len2
);
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). */
793 m4_make_diversion (m4
*context
, int divnum
)
795 m4_diversion
*diversion
= NULL
;
797 if (m4_get_current_diversion (context
) == divnum
)
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
))
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
;
825 output_cursor
= NULL
;
829 m4_set_current_diversion (context
, divnum
);
839 if (gl_oset_search_atleast (diversion_table
, threshold_diversion_CB
,
842 m4_diversion
*temp
= (m4_diversion
*) elt
;
843 if (temp
->divnum
== divnum
)
847 if (diversion
== NULL
)
849 /* First time visiting this diversion. */
852 diversion
= free_list
;
853 free_list
= diversion
->u
.next
;
854 assert (!diversion
->size
&& !diversion
->used
);
858 diversion
= (m4_diversion
*) obstack_alloc (&diversion_storage
,
863 diversion
->u
.file
= NULL
;
864 diversion
->divnum
= divnum
;
865 if (!gl_oset_add (diversion_table
, diversion
))
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
;
877 if (!output_diversion
->u
.file
&& output_diversion
->used
)
878 output_diversion
->u
.file
= m4_tmpopen (context
,
879 output_diversion
->divnum
,
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
891 insert_file (m4
*context
, FILE *file
, bool escaped
)
893 static char buffer
[COPY_BUFFER_SIZE
];
898 assert (output_diversion
);
899 /* Insert output by big chunks. */
902 length
= fread (buffer
, 1, sizeof buffer
, file
);
904 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
905 _("reading inserted file"));
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. */
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. */
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
)
945 if (!output_diversion
->u
.file
)
947 /* Transferring diversion metadata is faster than
949 assert (!output_diversion
->used
&& output_diversion
!= &div0
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
;
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
964 total_buffer_size
-= diversion
->size
;
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
974 assert (!output_diversion
->used
&& output_diversion
!= &div0
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
;
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. */
997 if (!output_diversion
)
998 total_buffer_size
-= diversion
->size
;
999 free (diversion
->u
.buffer
);
1000 diversion
->size
= 0;
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
))
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. */
1027 m4_insert_diversion (m4
*context
, int divnum
)
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
)
1035 if (gl_oset_search_atleast (diversion_table
, threshold_diversion_CB
,
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. */
1047 m4_undivert_all (m4
*context
)
1049 int divnum
= m4_get_current_diversion (context
);
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. */
1063 m4_freeze_diversions (m4
*context
, FILE *file
)
1067 gl_oset_iterator_t iter
;
1070 saved_number
= m4_get_current_diversion (context
);
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
);
1089 struct stat file_stat
;
1090 assert (!diversion
->u
.file
);
1091 diversion
->u
.file
= m4_tmpopen (context
, diversion
->divnum
,
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);
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
);