head: m4 -otrace --help

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
This bug affects both branch and head, but I don't want to waste effort on 
creating a 1.4.8 unless I am fixing multiple bugs, and this one is relatively 
minor.

$ rm -f trace
$ m4 --debugfile=trace --help >/dev/null
$ ls -l trace
-rw-r--r-- 1 eblake eblake 0 Sep 29 11:25 trace

Oops - we created the debug file before realizing that we weren't going to 
generate trace data because of --help.  My scan of main() did not turn up any 
other permanent side effect interactions with --help or --version.  On the 
other hand, I can live with behavior like this:

$ m4 -S1 --version
m4: Warning: `m4 -S' may be removed in a future release
GNU M4 1.4.7
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Written by Rene' Seindal.

The debug file change still has to take place quite early, so that module 
loading traces go to the right place.  I also fixed it up so that we don't 
close the trace file too early when tracing modules (a bug on head only).


2006-09-29  Eric Blake  <[email protected]>

	Even when not the first option, --help can't have side effects.
	* tests/options.at (--debugfile): Detect bugs in this area.
	* src/main.c (main): Fix it by deferring debugfile change.  Also,
	defer closing streams until after module tracing is done.
	* modules/gnu.c (debugfile): Make message consistent with command
	line.
	* doc/m4.texinfo (Invoking m4): Touch up the documentation.
	* NEWS: Document this fix.

Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.23
diff -u -r1.23 NEWS
--- NEWS	29 Sep 2006 12:26:06 -0000	1.23
+++ NEWS	29 Sep 2006 18:04:42 -0000
@@ -105,6 +105,10 @@
   overflow.  Also, the option now performs argument validation and accepts
   an optional multiplier suffix.
 
+* The `--help' and `--version' command line options now consistently
+  override all earlier options.  For example, `m4 -otrace --help' now no
+  longer accidentally creates an empty file `trace'.
+
 * FIXME: `m4wrap' semantics need an update to FIFO.
 
 * FIXME: include the (long) list of changes in 1.4.x that were not already
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.56
diff -u -r1.56 m4.texinfo
--- doc/m4.texinfo	29 Sep 2006 13:33:13 -0000	1.56
+++ doc/m4.texinfo	29 Sep 2006 18:04:42 -0000
@@ -428,11 +428,13 @@
 @table @code
 @item --help
 Print a help summary on standard output, then immediately exit
-@code{m4} without reading any input files.
+@code{m4} without reading any input files or performing any other
+actions.
 
 @item --version
 Print the version number of the program on standard output, then
-immediately exit @code{m4} without reading any input files.
+immediately exit @code{m4} without reading any input files or
+performing any other actions.
 
 @item -b
 @itemx --batch
Index: modules/gnu.c
===================================================================
RCS file: /sources/m4/m4/modules/gnu.c,v
retrieving revision 1.58
diff -u -r1.58 gnu.c
--- modules/gnu.c	27 Sep 2006 12:24:53 -0000	1.58
+++ modules/gnu.c	29 Sep 2006 18:04:42 -0000
@@ -404,7 +404,7 @@
   else if (m4_get_safer_opt (context) && *M4ARG (1))
     m4_error (context, 0, 0, _("%s: disabled by --safer"), M4ARG (0));
   else if (!m4_debug_set_output (context, M4ARG (1)))
-    m4_error (context, 0, errno, _("%s: cannot set debug file: %s"),
+    m4_error (context, 0, errno, _("%s: cannot set debug file `%s'"),
 	      M4ARG (0), M4ARG (1));
 }
 
Index: src/main.c
===================================================================
RCS file: /sources/m4/m4/src/main.c,v
retrieving revision 1.90
diff -u -r1.90 main.c
--- src/main.c	29 Sep 2006 13:33:14 -0000	1.90
+++ src/main.c	29 Sep 2006 18:04:42 -0000
@@ -256,17 +256,17 @@
 int
 main (int argc, char *const *argv, char *const *envp)
 {
-  macro_definition *head;	/* head of deferred argument list */
-  macro_definition *tail;
+  macro_definition *head = NULL;	/* head of deferred argument list */
+  macro_definition *tail = NULL;
   macro_definition *defn;
   int optchar;			/* option character */
   size_t size;			/* for parsing numeric option arguments */
 
   macro_definition *defines;
   FILE *fp;
-  char *filename;
   bool read_stdin = false;	/* true iff we have read from stdin */
   bool import_environment = false; /* true to import environment */
+  const char *debugfile = NULL;
   const char *frozen_file_to_read = NULL;
   const char *frozen_file_to_write = NULL;
   enum interactive_choice interactive = INTERACTIVE_UNKNOWN;
@@ -296,10 +296,9 @@
   if (getenv ("POSIXLY_CORRECT"))
     m4_set_posixly_correct_opt (context, true);
 
-  /* First, we decode the arguments, to size up tables and stuff.  */
-
-  head = tail = NULL;
-
+  /* First, we decode the arguments, to size up tables and stuff.
+     Avoid lasting side effects; for example 'm4 --debugfile=oops
+     --help' must not create the file `oops'.  */
   while ((optchar = getopt_long (argc, (char **) argv, OPTSTRING,
 				 long_options, NULL)) != -1)
     switch (optchar)
@@ -465,8 +464,8 @@
 	       optchar == 'o' ? "-o" : "--error-output", "--debugfile");
 	/* fall through */
       case DEBUGFILE_OPTION:
-	if (!m4_debug_set_output (context, optarg))
-	  error (0, errno, "%s", optarg);
+	/* Don't call m4_debug_set_output here, as it has side effects.	 */
+	debugfile = optarg;
 	break;
 
       case 's':
@@ -502,7 +501,8 @@
 					&& isatty (STDERR_FILENO))));
 
   /* Do the basic initializations.  */
-
+  if (debugfile && !m4_debug_set_output (context, debugfile))
+    m4_error (context, 0, errno, _("cannot set debug file `%s'"), debugfile);
   m4_input_init (context);
   m4_output_init ();
   m4_include_env_init (context);
@@ -625,7 +625,8 @@
 	  }
 	else
 	  {
-	    fp = m4_path_search (context, argv[optind], &filename);
+	    char *name;
+	    fp = m4_path_search (context, argv[optind], &name);
 	    if (fp == NULL)
 	      {
 		error (0, errno, "%s", argv[optind]);
@@ -634,8 +635,8 @@
 	      }
 	    else
 	      {
-		m4_push_file (context, fp, filename, true);
-		free (filename);
+		m4_push_file (context, fp, name, true);
+		free (name);
 	      }
 	  }
 	m4_macro_expand_input (context);
@@ -645,13 +646,6 @@
   while (m4_pop_wrapup ())
     m4_macro_expand_input (context);
 
-  /* Change debug stream back to stderr, to force flushing the debug
-     stream and detect any errors it might have encountered.  Close
-     stdin if we read from it, to detect any errors.  */
-  m4_debug_set_output (context, NULL);
-  if (read_stdin && fclose (stdin) == EOF)
-    m4_error (context, 0, errno, _("error closing stdin"));
-
   if (frozen_file_to_write)
     produce_frozen_state (context, frozen_file_to_write);
   else
@@ -670,6 +664,13 @@
   m4_output_exit ();
   m4_input_exit ();
 
+  /* Change debug stream back to stderr, to force flushing the debug
+     stream and detect any errors it might have encountered.  Close
+     stdin if we read from it, to detect any errors.  */
+  m4_debug_set_output (context, NULL);
+  if (read_stdin && fclose (stdin) == EOF)
+    m4_error (context, 0, errno, _("error closing stdin"));
+
   if (exit_status == EXIT_SUCCESS)
     exit_status = m4_get_exit_status (context);
   m4_delete (context);
Index: tests/options.at
===================================================================
RCS file: /sources/m4/m4/tests/options.at,v
retrieving revision 1.14
diff -u -r1.14 options.at
--- tests/options.at	29 Sep 2006 12:26:07 -0000	1.14
+++ tests/options.at	29 Sep 2006 18:04:42 -0000
@@ -239,7 +239,7 @@
 
 AT_SETUP([--debugfile])
 
-dnl For a while, CVS m4 mistakenly replaced debug output with stdout
+dnl For a while, CVS m4 mistakenly sent debug output to stdout
 dnl when stdout and stderr were the same file.
 
 AT_DATA([[in]], [[foo
@@ -253,6 +253,34 @@
 
 AT_CHECK([cmp trace1 trace2])
 
+dnl m4 1.4.x mistakenly created the trace file.  --help and --version
+dnl should always override, even if they come later in the command line
+AT_CHECK_M4([--debugfile=trace3 --help], [0], [ignore])
+AT_CHECK_M4([--debugfile=trace3 --version], [0], [ignore])
+AT_CHECK([test -f trace3], [1])
+
+dnl check that trace file failure causes an error, but allows processing
+AT_CHECK_M4([--debugfile=no_such_dir/trace -tfoo -Dfoo=bar in], [1],
+[[bar
+]], [[m4: cannot set debug file `no_such_dir/trace': No such file or directory
+m4trace: -1- foo -> `bar'
+]])
+
+dnl check that empty trace file discards trace data
+AT_CHECK_M4([--debugfile= -tfoo -Dfoo=bar in], [0],
+[[bar
+]])
+
+dnl check that all tracing gets diverted to the trace file.  Don't use
+dnl AT_CHECK_M4 on the first run, because sanitizing stderr breaks the
+dnl comparison with the raw data in the trace file of the second run.
+AT_CHECK([m4 -b -dV in], [0], [[foo
+]], [stderr])
+mv stderr expout
+AT_CHECK_M4([--debugfile=trace4 -dV in], [0], [[foo
+]])
+AT_CHECK([cat trace4], [0], [expout])
+
 AT_CLEANUP
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.