1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006,
4 2007, 2008 Free Software Foundation, Inc.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "gl_avltree_oset.h"
28 /* Size of initial in-memory buffer size for diversions. Small diversions
29 would usually fit in. */
30 #define INITIAL_BUFFER_SIZE 512
32 /* Maximum value for the total of all in-memory buffer sizes for
34 #define MAXIMUM_TOTAL_SIZE (512 * 1024)
36 /* Size of buffer size to use while copying files. */
37 #define COPY_BUFFER_SIZE (32 * 512)
39 /* Output functions. Most of the complexity is for handling cpp like
42 This code is fairly entangled with the code in input.c, and maybe it
45 typedef struct temp_dir m4_temp_dir
;
47 /* When part of diversion_table, each struct m4_diversion either
48 represents an open file (zero size, non-NULL u.file), an in-memory
49 buffer (non-zero size, non-NULL u.buffer), or an unused placeholder
50 diversion (zero size, u is NULL, non-zero used indicates that a
51 file has been created). When not part of diversion_table, u.next
52 is a pointer to the free_list chain. */
54 typedef struct m4_diversion m4_diversion
;
60 FILE *file
; /* diversion file on disk */
61 char *buffer
; /* in-memory diversion buffer */
62 m4_diversion
*next
; /* free-list pointer */
64 int divnum
; /* which diversion this represents */
65 int size
; /* usable size before reallocation */
66 int used
; /* used length in characters */
69 /* Table of diversions 1 through INT_MAX. */
70 static gl_oset_t diversion_table
;
72 /* Diversion 0 (not part of diversion_table). */
73 static m4_diversion div0
;
75 /* Linked list of reclaimed diversion storage. */
76 static m4_diversion
*free_list
;
78 /* Obstack from which diversion storage is allocated. */
79 static struct obstack diversion_storage
;
81 /* Total size of all in-memory buffer sizes. */
82 static int total_buffer_size
;
84 /* The number of the currently active diversion. This variable is
85 maintained for the `divnum' builtin function. */
86 int current_diversion
;
88 /* Current output diversion, NULL if output is being currently discarded. */
89 static m4_diversion
*output_diversion
;
91 /* Values of some output_diversion fields, cached out for speed. */
92 static FILE *output_file
; /* current value of (file) */
93 static char *output_cursor
; /* current value of (buffer + used) */
94 static int output_unused
; /* current value of (size - used) */
96 /* Number of input line we are generating output for. */
97 int output_current_line
;
99 /* Temporary directory holding all spilled diversion files. */
100 static m4_temp_dir
*output_temp_dir
;
104 /*------------------------.
105 | Output initialization. |
106 `------------------------*/
108 /* Callback for comparing list elements ELT1 and ELT2 for order in
111 cmp_diversion_CB (const void *elt1
, const void *elt2
)
113 const m4_diversion
*d1
= (const m4_diversion
*) elt1
;
114 const m4_diversion
*d2
= (const m4_diversion
*) elt2
;
115 /* No need to worry about overflow, since we don't create diversions
116 with negative divnum. */
117 return d1
->divnum
- d2
->divnum
;
120 /* Callback for comparing list element ELT against THRESHOLD. */
122 threshold_diversion_CB (const void *elt
, const void *threshold
)
124 const m4_diversion
*div
= (const m4_diversion
*) elt
;
125 /* No need to worry about overflow, since we don't create diversions
126 with negative divnum. */
127 return div
->divnum
>= *(const int *) threshold
;
133 diversion_table
= gl_oset_create_empty (GL_AVLTREE_OSET
, cmp_diversion_CB
,
135 div0
.u
.file
= stdout
;
136 output_diversion
= &div0
;
137 output_file
= stdout
;
138 obstack_init (&diversion_storage
);
144 /* Order is important, since we may have registered cleanup_tmpfile
145 as an atexit handler, and it must not traverse stale memory. */
146 gl_oset_t table
= diversion_table
;
147 diversion_table
= NULL
;
148 gl_oset_free (table
);
149 obstack_free (&diversion_storage
, NULL
);
152 /* Clean up any temporary directory. Designed for use as an atexit
153 handler, where it is not safe to call exit() recursively; so this
154 calls _exit if a problem is encountered. */
156 cleanup_tmpfile (void)
158 /* Close any open diversions. */
164 gl_oset_iterator_t iter
= gl_oset_iterator (diversion_table
);
165 while (gl_oset_iterator_next (&iter
, &elt
))
167 m4_diversion
*diversion
= (m4_diversion
*) elt
;
168 if (!diversion
->size
&& diversion
->u
.file
169 && close_stream_temp (diversion
->u
.file
) != 0)
171 m4_warn (errno
, NULL
,
172 _("cannot clean temporary file for diversion"));
176 gl_oset_iterator_free (&iter
);
179 /* Clean up the temporary directory. */
180 if (cleanup_temp_dir (output_temp_dir
) != 0)
183 _exit (exit_failure
);
186 /* Convert DIVNUM into a temporary file name for use in m4_tmp*. */
188 m4_tmpname (int divnum
)
191 static size_t offset
;
194 obstack_grow (&diversion_storage
, output_temp_dir
->dir_name
,
195 strlen (output_temp_dir
->dir_name
));
196 obstack_1grow (&diversion_storage
, '/');
197 obstack_1grow (&diversion_storage
, 'm');
198 obstack_1grow (&diversion_storage
, '4');
199 obstack_1grow (&diversion_storage
, '-');
200 offset
= obstack_object_size (&diversion_storage
);
201 buffer
= obstack_alloc (&diversion_storage
, INT_BUFSIZE_BOUND (divnum
));
203 if (snprintf (&buffer
[offset
], INT_BUFSIZE_BOUND (divnum
), "%d", divnum
) < 0)
204 m4_error (EXIT_FAILURE
, errno
, NULL
,
205 _("cannot create temporary file for diversion"));
209 /* Create a temporary file for diversion DIVNUM open for reading and
210 writing in a secure temp directory. The file will be automatically
211 closed and deleted on a fatal signal. The file can be closed and
212 reopened with m4_tmpclose and m4_tmpopen; when finally done with
213 the file, close it with m4_tmpremove. Exits on failure, so the
214 return value is always an open file. */
216 m4_tmpfile (int divnum
)
221 if (output_temp_dir
== NULL
)
223 output_temp_dir
= create_temp_dir ("m4-", NULL
, true);
224 if (output_temp_dir
== NULL
)
225 m4_error (EXIT_FAILURE
, errno
, NULL
,
226 _("cannot create temporary file for diversion"));
227 atexit (cleanup_tmpfile
);
229 name
= m4_tmpname (divnum
);
230 register_temp_file (output_temp_dir
, name
);
231 file
= fopen_temp (name
, O_BINARY
? "wb+" : "w+");
234 unregister_temp_file (output_temp_dir
, name
);
235 m4_error (EXIT_FAILURE
, errno
, NULL
,
236 _("cannot create temporary file for diversion"));
238 else if (set_cloexec_flag (fileno (file
), true) != 0)
239 m4_warn (errno
, NULL
, _("cannot protect diversion across forks"));
243 /* Reopen a temporary file for diversion DIVNUM for reading and
244 writing in a secure temp directory. Exits on failure, so the
245 return value is always an open file. */
247 m4_tmpopen (int divnum
)
249 const char *name
= m4_tmpname (divnum
);
252 file
= fopen_temp (name
, O_BINARY
? "ab+" : "a+");
254 m4_error (EXIT_FAILURE
, errno
, NULL
,
255 _("cannot create temporary file for diversion"));
256 else if (set_cloexec_flag (fileno (file
), true) != 0)
257 m4_warn (errno
, NULL
, _("cannot protect diversion across forks"));
258 /* POSIX states that it is undefined whether an append stream starts
259 at offset 0 or at the end. We want the beginning. */
260 else if (fseeko (file
, 0, SEEK_SET
) != 0)
261 m4_error (EXIT_FAILURE
, errno
, NULL
,
262 _("cannot seek to beginning of diversion"));
266 /* Close, but don't delete, a temporary FILE. */
268 m4_tmpclose (FILE *file
)
270 return close_stream_temp (file
);
273 /* Delete a closed temporary FILE for diversion DIVNUM. */
275 m4_tmpremove (int divnum
)
277 return cleanup_temp_file (output_temp_dir
, m4_tmpname (divnum
));
280 /*-----------------------------------------------------------------------.
281 | Reorganize in-memory diversion buffers so the current diversion can |
282 | accomodate LENGTH more characters without further reorganization. The |
283 | current diversion buffer is made bigger if possible. But to make room |
284 | for a bigger buffer, one of the in-memory diversion buffers might have |
285 | to be flushed to a newly created temporary file. This flushed buffer |
286 | might well be the current one. |
287 `-----------------------------------------------------------------------*/
290 make_room_for (int length
)
293 m4_diversion
*selected_diversion
= NULL
;
295 /* Compute needed size for in-memory buffer. Diversions in-memory
296 buffers start at 0 bytes, then 512, then keep doubling until it is
297 decided to flush them to disk. */
299 output_diversion
->used
= output_diversion
->size
- output_unused
;
301 for (wanted_size
= output_diversion
->size
;
302 wanted_size
< output_diversion
->used
+ length
;
303 wanted_size
= wanted_size
== 0 ? INITIAL_BUFFER_SIZE
: wanted_size
* 2)
306 /* Check if we are exceeding the maximum amount of buffer memory. */
308 if (total_buffer_size
- output_diversion
->size
+ wanted_size
309 > MAXIMUM_TOTAL_SIZE
)
312 char *selected_buffer
;
313 m4_diversion
*diversion
;
315 gl_oset_iterator_t iter
;
318 /* Find out the buffer having most data, in view of flushing it to
319 disk. Fake the current buffer as having already received the
320 projected data, while making the selection. So, if it is
321 selected indeed, we will flush it smaller, before it grows. */
323 selected_diversion
= output_diversion
;
324 selected_used
= output_diversion
->used
+ length
;
326 iter
= gl_oset_iterator (diversion_table
);
327 while (gl_oset_iterator_next (&iter
, &elt
))
329 diversion
= (m4_diversion
*) elt
;
330 if (diversion
->used
> selected_used
)
332 selected_diversion
= diversion
;
333 selected_used
= diversion
->used
;
336 gl_oset_iterator_free (&iter
);
338 /* Create a temporary file, write the in-memory buffer of the
339 diversion to this file, then release the buffer. Zero the
340 diversion before doing anything that can exit () (including
341 m4_tmpfile), so that the atexit handler doesn't try to close
342 a garbage pointer as a file. */
344 selected_buffer
= selected_diversion
->u
.buffer
;
345 total_buffer_size
-= selected_diversion
->size
;
346 selected_diversion
->size
= 0;
347 selected_diversion
->u
.file
= NULL
;
348 selected_diversion
->u
.file
= m4_tmpfile (selected_diversion
->divnum
);
350 if (selected_diversion
->used
> 0)
352 count
= fwrite (selected_buffer
, (size_t) selected_diversion
->used
,
353 1, selected_diversion
->u
.file
);
355 m4_error (EXIT_FAILURE
, errno
, NULL
,
356 _("cannot flush diversion to temporary file"));
359 /* Reclaim the buffer space for other diversions. */
361 free (selected_buffer
);
362 selected_diversion
->used
= 1;
365 /* Reload output_file, just in case the flushed diversion was current. */
367 if (output_diversion
== selected_diversion
)
369 /* The flushed diversion was current indeed. */
371 output_file
= output_diversion
->u
.file
;
372 output_cursor
= NULL
;
377 /* Close any selected file since it is not the current diversion. */
378 if (selected_diversion
)
380 FILE *file
= selected_diversion
->u
.file
;
381 selected_diversion
->u
.file
= NULL
;
382 if (m4_tmpclose (file
) != 0)
383 m4_warn (errno
, NULL
,
384 _("cannot close temporary file for diversion"));
387 /* The current buffer may be safely reallocated. */
388 output_diversion
->u
.buffer
389 = xrealloc (output_diversion
->u
.buffer
, (size_t) wanted_size
);
391 total_buffer_size
+= wanted_size
- output_diversion
->size
;
392 output_diversion
->size
= wanted_size
;
394 output_cursor
= output_diversion
->u
.buffer
+ output_diversion
->used
;
395 output_unused
= wanted_size
- output_diversion
->used
;
399 /*------------------------------------------------------------------------.
400 | Output one character CHAR, when it is known that it goes to a diversion |
401 | file or an in-memory diversion buffer. |
402 `------------------------------------------------------------------------*/
404 #define OUTPUT_CHARACTER(Char) \
406 putc ((Char), output_file); \
407 else if (output_unused == 0) \
408 output_character_helper ((Char)); \
410 (output_unused--, *output_cursor++ = (Char))
413 output_character_helper (int character
)
418 putc (character
, output_file
);
421 *output_cursor
++ = character
;
426 /*------------------------------------------------------------------------.
427 | Output one TEXT having LENGTH characters, when it is known that it goes |
428 | to a diversion file or an in-memory diversion buffer. |
429 `------------------------------------------------------------------------*/
432 output_text (const char *text
, int length
)
436 if (!output_diversion
|| !length
)
439 if (!output_file
&& length
> output_unused
)
440 make_room_for (length
);
444 count
= fwrite (text
, length
, 1, output_file
);
446 m4_error (EXIT_FAILURE
, errno
, NULL
, _("error copying inserted file"));
450 memcpy (output_cursor
, text
, (size_t) length
);
451 output_cursor
+= length
;
452 output_unused
-= length
;
456 /*--------------------------------------------------------------------.
457 | Add some text into an obstack OBS, taken from TEXT, having LENGTH |
458 | characters. If OBS is NULL, output the text to an external file |
459 | or an in-memory diversion buffer instead. If OBS is NULL, and |
460 | there is no output file, the text is discarded. LINE is the line |
461 | where the token starts (not necessarily current_line, in the case |
462 | of multiline tokens). |
464 | If we are generating sync lines, the output has to be examined, |
465 | because we need to know how much output each input line generates. |
466 | In general, sync lines are output whenever a single input lines |
467 | generates several output lines, or when several input lines do not |
468 | generate any output. |
469 `--------------------------------------------------------------------*/
472 shipout_text (struct obstack
*obs
, const char *text
, int length
, int line
)
474 static bool start_of_output_line
= true;
477 /* If output goes to an obstack, merely add TEXT to it. */
481 obstack_grow (obs
, text
, length
);
485 /* Do nothing if TEXT should be discarded. */
487 if (output_diversion
== NULL
)
490 /* Output TEXT to a file, or in-memory diversion buffer. */
496 /* In-line short texts. */
498 case 8: OUTPUT_CHARACTER (*text
); text
++;
499 case 7: OUTPUT_CHARACTER (*text
); text
++;
500 case 6: OUTPUT_CHARACTER (*text
); text
++;
501 case 5: OUTPUT_CHARACTER (*text
); text
++;
502 case 4: OUTPUT_CHARACTER (*text
); text
++;
503 case 3: OUTPUT_CHARACTER (*text
); text
++;
504 case 2: OUTPUT_CHARACTER (*text
); text
++;
505 case 1: OUTPUT_CHARACTER (*text
);
509 /* Optimize longer texts. */
512 output_text (text
, length
);
516 /* Check for syncline only at the start of a token. Multiline
517 tokens, and tokens that are out of sync but in the middle of
518 the line, must wait until the next raw newline triggers a
520 if (start_of_output_line
)
522 start_of_output_line
= false;
523 output_current_line
++;
525 xfprintf (stderr
, "DEBUG: line %d, cur %d, cur out %d\n",
526 line
, current_line
, output_current_line
);
529 /* Output a `#line NUM' synchronization directive if needed.
530 If output_current_line was previously given a negative
531 value (invalidated), output `#line NUM "FILE"' instead. */
533 if (output_current_line
!= line
)
535 OUTPUT_CHARACTER ('#');
536 OUTPUT_CHARACTER ('l');
537 OUTPUT_CHARACTER ('i');
538 OUTPUT_CHARACTER ('n');
539 OUTPUT_CHARACTER ('e');
540 OUTPUT_CHARACTER (' ');
541 for (cursor
= ntoa (line
, 10); *cursor
; cursor
++)
542 OUTPUT_CHARACTER (*cursor
);
543 if (output_current_line
< 1 && current_file
[0] != '\0')
545 OUTPUT_CHARACTER (' ');
546 OUTPUT_CHARACTER ('"');
547 for (cursor
= current_file
; *cursor
; cursor
++)
548 OUTPUT_CHARACTER (*cursor
);
549 OUTPUT_CHARACTER ('"');
551 OUTPUT_CHARACTER ('\n');
552 output_current_line
= line
;
556 /* Output the token, and track embedded newlines. */
557 for (; length
-- > 0; text
++)
559 if (start_of_output_line
)
561 start_of_output_line
= false;
562 output_current_line
++;
564 xfprintf (stderr
, "DEBUG: line %d, cur %d, cur out %d\n",
565 line
, current_line
, output_current_line
);
568 OUTPUT_CHARACTER (*text
);
570 start_of_output_line
= true;
575 /* Functions for use by diversions. */
577 /*--------------------------------------------------------------------------.
578 | Make a file for diversion DIVNUM, and install it in the diversion table. |
579 | Grow the size of the diversion table as needed. |
580 `--------------------------------------------------------------------------*/
582 /* The number of possible diversions is limited only by memory and
583 available file descriptors (each overflowing diversion uses one). */
586 make_diversion (int divnum
)
588 m4_diversion
*diversion
= NULL
;
590 if (current_diversion
== divnum
)
593 if (output_diversion
)
595 if (!output_diversion
->size
&& !output_diversion
->u
.file
)
597 if (!gl_oset_remove (diversion_table
, output_diversion
))
599 output_diversion
->u
.next
= free_list
;
600 output_diversion
->used
= 0;
601 free_list
= output_diversion
;
603 else if (output_diversion
->size
)
604 output_diversion
->used
= output_diversion
->size
- output_unused
;
605 else if (output_diversion
->used
)
607 FILE *file
= output_diversion
->u
.file
;
608 output_diversion
->u
.file
= NULL
;
609 if (m4_tmpclose (file
) != 0)
610 m4_warn (errno
, NULL
,
611 _("cannot close temporary file for diversion"));
613 output_diversion
= NULL
;
615 output_cursor
= NULL
;
619 current_diversion
= divnum
;
629 if (gl_oset_search_atleast (diversion_table
, threshold_diversion_CB
,
632 m4_diversion
*temp
= (m4_diversion
*) elt
;
633 if (temp
->divnum
== divnum
)
637 if (diversion
== NULL
)
639 /* First time visiting this diversion. */
642 diversion
= free_list
;
643 free_list
= diversion
->u
.next
;
647 diversion
= (m4_diversion
*) obstack_alloc (&diversion_storage
,
652 diversion
->u
.file
= NULL
;
653 diversion
->divnum
= divnum
;
654 gl_oset_add (diversion_table
, diversion
);
657 output_diversion
= diversion
;
658 if (output_diversion
->size
)
660 output_cursor
= output_diversion
->u
.buffer
+ output_diversion
->used
;
661 output_unused
= output_diversion
->size
- output_diversion
->used
;
665 if (!output_diversion
->u
.file
&& output_diversion
->used
)
666 output_diversion
->u
.file
= m4_tmpopen (output_diversion
->divnum
);
667 output_file
= output_diversion
->u
.file
;
669 output_current_line
= -1;
672 /*-------------------------------------------------------------------.
673 | Insert a FILE into the current output file, in the same manner |
674 | diversions are handled. This allows files to be included, without |
675 | having them rescanned by m4. |
676 `-------------------------------------------------------------------*/
679 insert_file (FILE *file
)
681 char buffer
[COPY_BUFFER_SIZE
];
684 /* Optimize out inserting into a sink. */
686 if (!output_diversion
)
689 /* Insert output by big chunks. */
693 length
= fread (buffer
, 1, COPY_BUFFER_SIZE
, file
);
695 m4_error (EXIT_FAILURE
, errno
, NULL
, _("error reading inserted file"));
698 output_text (buffer
, length
);
702 /*-------------------------------------------------------------------.
703 | Insert DIVERSION (but not div0) into the current output file. The |
704 | diversion is NOT placed on the expansion obstack, because it must |
705 | not be rescanned. When the file is closed, it is deleted by the |
707 `-------------------------------------------------------------------*/
710 insert_diversion_helper (m4_diversion
*diversion
)
712 /* Effectively undivert only if an output stream is active. */
713 if (output_diversion
)
716 output_text (diversion
->u
.buffer
, diversion
->used
);
719 if (!diversion
->u
.file
)
720 diversion
->u
.file
= m4_tmpopen (diversion
->divnum
);
721 insert_file (diversion
->u
.file
);
724 output_current_line
= -1;
727 /* Return all space used by the diversion. */
730 free (diversion
->u
.buffer
);
736 if (diversion
->u
.file
)
738 FILE *file
= diversion
->u
.file
;
739 diversion
->u
.file
= NULL
;
741 if (m4_tmpclose (file
) != 0)
742 m4_warn (errno
, NULL
,
743 _("cannot clean temporary file for diversion"));
745 if (m4_tmpremove (diversion
->divnum
) != 0)
746 m4_warn (errno
, NULL
, _("cannot clean temporary file for diversion"));
748 gl_oset_remove (diversion_table
, diversion
);
749 diversion
->u
.next
= free_list
;
750 free_list
= diversion
;
753 /*-------------------------------------------------------------------------.
754 | Insert diversion number DIVNUM into the current output file. The |
755 | diversion is NOT placed on the expansion obstack, because it must not be |
756 | rescanned. When the file is closed, it is deleted by the system. |
757 `-------------------------------------------------------------------------*/
760 insert_diversion (int divnum
)
764 /* Do not care about nonexistent diversions, and undiverting stdout
765 or self is a no-op. */
766 if (divnum
<= 0 || current_diversion
== divnum
)
768 if (gl_oset_search_atleast (diversion_table
, threshold_diversion_CB
,
771 m4_diversion
*diversion
= (m4_diversion
*) elt
;
772 if (diversion
->divnum
== divnum
)
773 insert_diversion_helper (diversion
);
777 /*-------------------------------------------------------------------------.
778 | Get back all diversions. This is done just before exiting from main (), |
779 | and from m4_undivert (), if called without arguments. |
780 `-------------------------------------------------------------------------*/
786 gl_oset_iterator_t iter
= gl_oset_iterator (diversion_table
);
787 while (gl_oset_iterator_next (&iter
, &elt
))
789 m4_diversion
*diversion
= (m4_diversion
*) elt
;
790 if (diversion
->divnum
!= current_diversion
)
791 insert_diversion_helper (diversion
);
793 gl_oset_iterator_free (&iter
);
796 /*-------------------------------------------------------------.
797 | Produce all diversion information in frozen format on FILE. |
798 `-------------------------------------------------------------*/
801 freeze_diversions (FILE *file
)
805 gl_oset_iterator_t iter
;
808 saved_number
= current_diversion
;
811 output_file
= file
; /* kludge in the frozen file */
813 iter
= gl_oset_iterator (diversion_table
);
814 while (gl_oset_iterator_next (&iter
, &elt
))
816 m4_diversion
*diversion
= (m4_diversion
*) elt
;;
817 if (diversion
->size
|| diversion
->used
)
820 xfprintf (file
, "D%d,%d\n", diversion
->divnum
, diversion
->used
);
823 struct stat file_stat
;
824 diversion
->u
.file
= m4_tmpopen (diversion
->divnum
);
825 if (fstat (fileno (diversion
->u
.file
), &file_stat
) < 0)
826 m4_error (EXIT_FAILURE
, errno
, NULL
,
827 _("cannot stat diversion"));
828 if (file_stat
.st_size
< 0
829 || file_stat
.st_size
!= (unsigned long int) file_stat
.st_size
)
830 m4_error (EXIT_FAILURE
, 0, NULL
, _("diversion too large"));
831 xfprintf (file
, "D%d,%lu\n", diversion
->divnum
,
832 (unsigned long int) file_stat
.st_size
);
835 insert_diversion_helper (diversion
);
838 last_inserted
= diversion
->divnum
;
841 gl_oset_iterator_free (&iter
);
843 /* Save the active diversion number, if not already. */
845 if (saved_number
!= last_inserted
)
846 xfprintf (file
, "D%d,0\n\n", saved_number
);