Re: add some fd tests to head
Eric Blake <[email protected]>
| Newsgroups | gmane.comp.gnu.m4.patches |
|---|---|
| Message-ID | <[email protected]> |
Eric Blake <ebb9 <at> byu.net> writes: > > 2006-10-06 Eric Blake <ebb9 <at> byu.net> > > Replace uses of tmpfile with clean-temp, since tmpfile is > incompatible with closeout. This was relatively easy to port to the branch (although it breaks mingw builds unless a pending patch of mine is accepted in gnulib). 2006-10-13 Eric Blake <[email protected]> Backport head's usage of clean-temp module, as it is cleaner than using tmpfile-safer. * m4/gnulib-cache.m4: Augment with 'gnulib-tool --import clean-temp closeout', and remove tmpfile-safer. * src/m4.h (includes): Adjust. (m4_path_search): Rename from path_search, to avoid collision with gnulib. * src/m4.c (main): Install closeout handler. Adjust caller. (usage): Now done by closeout module. * src/builtin.c (m4_m4exit): Likewise. (m4_undivert, include): Adjust callers. * src/freeze.c (reload_frozen_state): Likewise. * src/path.c (m4_path_search): Rename from path_search. * src/output.c (output_temp_dir): New variable. (cleanup_tmpfile, m4_tmpfile): New functions, from head. (insert_diversion, make_room_for): Use them. * doc/m4.texinfo (Diversions): Document this, and add a test. (Improved fatal_error): Fix typo. (Maketemp): Port test to mingw, and no longer hide from documentation. * NEWS: Document the change in TMPDIR behavior. Index: NEWS =================================================================== RCS file: /sources/m4/m4/NEWS,v retrieving revision 1.1.1.1.2.71 diff -u -r1.1.1.1.2.71 NEWS --- NEWS 13 Oct 2006 12:59:16 -0000 1.1.1.1.2.71 +++ NEWS 13 Oct 2006 22:20:55 -0000 @@ -22,6 +22,10 @@ token in an included file. * The `builtin' and `indir' macros now transparently handle builtin tokens generated by `defn'. +* When diversions created by the `divert' macro collect enough text that + M4 must use temporary files, the environment variable $TMPDIR is now + consulted, and a better effort is made to clean up those files in the + event of a fatal signal. Version 1.4.7 - 25 September 2006, by Eric Blake (CVS version 1.4.6a) Index: doc/m4.texinfo =================================================================== RCS file: /sources/m4/m4/doc/m4.texinfo,v retrieving revision 1.1.1.1.2.84 diff -u -r1.1.1.1.2.84 m4.texinfo --- doc/m4.texinfo 13 Oct 2006 12:59:17 -0000 1.1.1.1.2.84 +++ doc/m4.texinfo 13 Oct 2006 22:20:55 -0000 @@ -3240,9 +3240,46 @@ (512K, currently). When this maximum is about to be exceeded, a temporary file is opened to receive the contents of the biggest diversion still in memory, freeing this memory for other diversions. +When creating the temporary file, @code{m4} honors the value of the +environment variable @env{TMPDIR}, and falls back to @file{/tmp}. So, it is theoretically possible that the number of diversions be limited by the number of available file descriptors. +@ignore +@comment We need to test spilled diversions, but don't need to expose +@comment this highly repetitive test in the manual. + +@example +divert(`-1')define(`f', `.') +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +define(`f', defn(`f')defn(`f')) +divert`'dnl +len(f) +@result{}1048576 +divert(`1') +f +divert(`-1')undivert +@end example +@end ignore + @c FIXME: need some explanation here why this is a useful feature, not @c just how you use it. @@ -4394,16 +4431,9 @@ @code{maketemp}, so a future version of @acronym{GNU} M4 may have changes in this area. -@ignore -@c This test makes sure maketemp gets testsuite coverage, but is -@c somewhat complex for use in the manual. @example -dnl This test assumes /tmp is a valid directory name, which is not true -dnl for native Windows. -ifdef(`__unix__', , `errprint(` skipping: not sure /tmp exists -')m4exit(`77')')dnl -define(`file1', maketemp(`/tmp/fooXXXXXX'))dnl -define(`file2', maketemp(`/tmp/fooXXXXXX'))dnl +define(`file1', maketemp(`fooXXXXXX'))dnl +define(`file2', maketemp(`fooXXXXXX'))dnl ifelse(file1, file2, `same', `different') @result{}different syscmd(`rm 'file1 file2) @@ -4411,7 +4441,6 @@ sysval @result{}0 @end example -@end ignore @node Miscellaneous @chapter Miscellaneous builtin macros @@ -5189,7 +5218,7 @@ @example define(`fatal_error', - `errprint(ifdef(`__program', `__program__', ``m4'')'dnl + `errprint(ifdef(`__program__', `__program__', ``m4'')'dnl `:ifelse(__line__, `0', `', `__file__:__line__:')` fatal error: $* ')m4exit(`1')') Index: m4/gnulib-cache.m4 =================================================================== RCS file: /sources/m4/m4/m4/Attic/gnulib-cache.m4,v retrieving revision 1.1.2.15 diff -u -r1.1.2.15 gnulib-cache.m4 --- m4/gnulib-cache.m4 7 Sep 2006 22:48:15 -0000 1.1.2.15 +++ m4/gnulib-cache.m4 13 Oct 2006 22:20:55 -0000 @@ -15,11 +15,11 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --lib=libm4 --source-base=lib --m4-base=m4 -- doc-base=doc --aux-dir=. --no-libtool --macro-prefix=M4 binary-io cloexec close- stream error fdl fopen-safer free gendocs getopt gnupload mkstemp obstack regex stdlib-safer strtol tmpfile-safer unlocked-io verror xalloc xvasprintf +# gnulib-tool --import --dir=. --lib=libm4 --source-base=lib --m4-base=m4 -- doc-base=doc --aux-dir=. --no-libtool --macro-prefix=M4 binary-io clean-temp cloexec close-stream closeout error fdl fopen-safer free gendocs getopt gnupload mkstemp obstack regex stdlib-safer strtol unlocked-io verror xalloc xvasprintf # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([]) -gl_MODULES([binary-io cloexec close-stream error fdl fopen-safer free gendocs getopt gnupload mkstemp obstack regex stdlib-safer strtol tmpfile-safer unlocked-io verror xalloc xvasprintf]) +gl_MODULES([binary-io clean-temp cloexec close-stream closeout error fdl fopen- safer free gendocs getopt gnupload mkstemp obstack regex stdlib-safer strtol unlocked-io verror xalloc xvasprintf]) gl_AVOID([]) gl_SOURCE_BASE([lib]) gl_M4_BASE([m4]) Index: src/builtin.c =================================================================== RCS file: /sources/m4/m4/src/Attic/builtin.c,v retrieving revision 1.1.1.1.2.42 diff -u -r1.1.1.1.2.42 builtin.c --- src/builtin.c 13 Oct 2006 12:59:17 -0000 1.1.1.1.2.42 +++ src/builtin.c 13 Oct 2006 22:20:55 -0000 @@ -1088,7 +1088,7 @@ "non-numeric argument to builtin `%s'", ARG (0))); else { - fp = path_search (ARG (i), NULL); + fp = m4_path_search (ARG (i), NULL); if (fp != NULL) { insert_file (fp); @@ -1200,7 +1200,7 @@ if (bad_argc (argv[0], argc, 2, 2)) return; - fp = path_search (ARG (1), &name); + fp = m4_path_search (ARG (1), &name); if (fp == NULL) { if (!silent) @@ -1329,16 +1329,11 @@ detect any errors it might have encountered. */ debug_set_output (NULL); debug_flush_files (); - if (close_stream (stdout) != 0) - { - M4ERROR ((warning_status, errno, "write error")); - if (exit_code == 0) - exit_code = EXIT_FAILURE; - } - if (close_stream (stderr) != 0 && exit_code == 0) - exit_code = EXIT_FAILURE; - if (exit_code == 0 && retcode != 0) + if (exit_code == EXIT_SUCCESS && retcode != EXIT_SUCCESS) exit_code = retcode; + /* Propagate non-zero status to atexit handlers. */ + if (exit_code != EXIT_SUCCESS) + exit_failure = exit_code; exit (exit_code); } Index: src/freeze.c =================================================================== RCS file: /sources/m4/m4/src/freeze.c,v retrieving revision 1.1.1.1.2.12 diff -u -r1.1.1.1.2.12 freeze.c --- src/freeze.c 30 Jul 2006 03:18:12 -0000 1.1.1.1.2.12 +++ src/freeze.c 13 Oct 2006 22:20:55 -0000 @@ -222,7 +222,7 @@ } \ while (character == '\n') - file = path_search (name, NULL); + file = m4_path_search (name, NULL); if (file == NULL) M4ERROR ((EXIT_FAILURE, errno, "cannot open %s", name)); Index: src/m4.c =================================================================== RCS file: /sources/m4/m4/src/Attic/m4.c,v retrieving revision 1.1.1.1.2.33 diff -u -r1.1.1.1.2.33 m4.c --- src/m4.c 10 Oct 2006 03:54:26 -0000 1.1.1.1.2.33 +++ src/m4.c 13 Oct 2006 22:20:55 -0000 @@ -204,11 +204,6 @@ ", stdout); printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT); } - - if (close_stream (stdout) != 0) - M4ERROR ((EXIT_FAILURE, errno, "write error")); - if (close_stream (stderr) != 0) - exit (EXIT_FAILURE); /* Can't really do much else without stderr. */ exit (status); } @@ -286,6 +281,7 @@ program_name = argv[0]; retcode = EXIT_SUCCESS; + atexit (close_stdout); include_init (); debug_init (); @@ -421,20 +417,15 @@ break; case VERSION_OPTION: - printf ("%s\n", PACKAGE_STRING); - fputs ("\ + printf ("%s\n", PACKAGE_STRING); + fputs ("\ Copyright (C) 2006 Free Software Foundation, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ \n\ Written by Rene' Seindal.\n\ ", stdout); - - if (close_stream (stdout) != 0) - M4ERROR ((EXIT_FAILURE, errno, "write error")); - if (close_stream (stderr) != 0) - exit (EXIT_FAILURE); - exit (EXIT_SUCCESS); + exit (EXIT_SUCCESS); break; case HELP_OPTION: @@ -532,7 +523,7 @@ else { const char *name; - fp = path_search (argv[optind], &name); + fp = m4_path_search (argv[optind], &name); if (fp == NULL) { error (0, errno, "%s", argv[optind]); @@ -570,10 +561,5 @@ make_diversion (0); undivert_all (); } - - if (close_stream (stdout) != 0) - M4ERROR ((EXIT_FAILURE, errno, "write error")); - if (close_stream (stderr) != 0) - exit (EXIT_FAILURE); /* Can't really do much else without stderr. */ exit (retcode); } Index: src/m4.h =================================================================== RCS file: /sources/m4/m4/src/m4.h,v retrieving revision 1.1.1.1.2.29 diff -u -r1.1.1.1.2.29 m4.h --- src/m4.h 7 Sep 2006 22:48:15 -0000 1.1.1.1.2.29 +++ src/m4.h 13 Oct 2006 22:20:55 -0000 @@ -49,16 +49,20 @@ #include <sys/types.h> #include "binary-io.h" +#include "clean-temp.h" #include "cloexec.h" #include "close-stream.h" +#include "closeout.h" #include "error.h" #include "exit.h" +#include "exitfail.h" #include "obstack.h" #include "stdio--.h" #include "stdlib--.h" #include "unistd--.h" #include "verror.h" #include "xalloc.h" +#include "xvasprintf.h" /* If FALSE is defined, we presume TRUE is defined too. In this case, merely typedef boolean as being int. Or else, define these all. */ @@ -418,7 +422,7 @@ void include_init (void); void include_env_init (void); void add_include_directory (const char *); -FILE *path_search (const char *, const char **); +FILE *m4_path_search (const char *, const char **); /* File: eval.c --- expression evaluation. */ Index: src/output.c =================================================================== RCS file: /sources/m4/m4/src/Attic/output.c,v retrieving revision 1.1.1.1.2.10 diff -u -r1.1.1.1.2.10 output.c --- src/output.c 18 Aug 2006 23:11:37 -0000 1.1.1.1.2.10 +++ src/output.c 13 Oct 2006 22:20:56 -0000 @@ -76,6 +76,13 @@ /* 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. | @@ -99,6 +106,48 @@ output_unused = 0; } +/* Clean up any temporary directory. Designed for use as an atexit + handler, where it is not safe to call exit() recursively; so this + calls _exit if a problem is encountered. */ +static void +cleanup_tmpfile (void) +{ + if (cleanup_temp_dir (output_temp_dir) != 0) + _exit (exit_failure); +} + +/* Create a temporary file open for reading and writing in a secure + temp directory. The file will be automatically closed and deleted + on a fatal signal. When done with the file, close it with + close_stream_temp. Exits on failure, so the return value is always + an open file. */ +static FILE * +m4_tmpfile (void) +{ + static unsigned int count; + char *name; + FILE *file; + + if (output_temp_dir == NULL) + { + errno = 0; + output_temp_dir = create_temp_dir ("m4-", NULL, true); + if (output_temp_dir == NULL) + M4ERROR ((EXIT_FAILURE, errno, + "cannot create temporary file for diversion")); + atexit (cleanup_tmpfile); + } + name = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, count++); + register_temp_file (output_temp_dir, name); + errno = 0; + file = fopen_temp (name, O_BINARY ? "wb+" : "w+"); + if (file == NULL) + M4ERROR ((EXIT_FAILURE, errno, + "cannot create temporary file for diversion")); + free (name); + return file; +} + /*-----------------------------------------------------------------------. | Reorganize in-memory diversion buffers so the current diversion can | | accomodate LENGTH more characters without further reorganization. The | @@ -154,10 +203,7 @@ /* Create a temporary file, write the in-memory buffer of the diversion to this file, then release the buffer. */ - selected_diversion->file = tmpfile (); - if (selected_diversion->file == NULL) - M4ERROR ((EXIT_FAILURE, errno, - "ERROR: cannot create temporary file for diversion")); + selected_diversion->file = m4_tmpfile (); if (set_cloexec_flag (fileno (selected_diversion->file), true) != 0) M4ERROR ((warning_status, errno, "Warning: cannot protect diversion across forks")); @@ -485,7 +531,7 @@ if (diversion->file) { - fclose (diversion->file); + close_stream_temp (diversion->file); diversion->file = NULL; } else if (diversion->buffer) Index: src/path.c =================================================================== RCS file: /sources/m4/m4/src/Attic/path.c,v retrieving revision 1.1.1.1.2.11 diff -u -r1.1.1.1.2.11 path.c --- src/path.c 10 Oct 2006 11:36:40 -0000 1.1.1.1.2.11 +++ src/path.c 13 Oct 2006 22:20:56 -0000 @@ -111,7 +111,7 @@ respect to the current working directory. */ FILE * -path_search (const char *file, const char **result) +m4_path_search (const char *file, const char **result) { FILE *fp; includes *incl; @@ -154,7 +154,7 @@ strcpy (name + incl->len + 1, file); #ifdef DEBUG_INCL - fprintf (stderr, "path_search (%s) -- trying %s\n", file, name); + fprintf (stderr, "m4_path_search (%s) -- trying %s\n", file, name); #endif fp = fopen (name, "r");