Re: RFC: m4 2.0 --prepend-include option

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches,gmane.comp.gnu.m4.general
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Eric Blake on 8/23/2006 9:24 AM:
> Here is my proposal for adding a --prepend-include option to m4 2.0, so
> that once autom4te requires 2.0, it can search for files outside of the
> current working directory first.

I've cleaned it up some, making -B an unconditional synonym for
- --prepend-include, per Paul's advice, with the caveat that -B1024 will
issue a warning that it is no longer compatible with other command line m4
implementations.  Perhaps I should tune it further to not even warn unless
./1024 is a directory?  I also added some tests to the testsuite.

I also added warnings for -T and -S, as well as for -N/--diversions (which
has been a no-op in 1.4.x), but I left -H/--hashsize as a silent
compatibility option for now (since it had an effect in 1.4.x, and might
make the transition from 1.4.x to 2.0 smoother).  Let me know if I should
change any of these decisions.

There are more things to do in regards to POSIXLY_CORRECT, so this thread
is by no means closed, but I am checking in the following:

2006-08-25  Eric Blake  <[email protected]>

	* tests/options.at (debug-flags): Update to reflect new message.
	(deprecated options, prepend-include, help and version): New
	tests.
	* tests/testsuite.at (AT_CHECK_M4): Avoid hanging testsuite if
	test omits an input file name.
	* src/main.c (long_options, main): Add -B/--prepend-include.
	(usage): Document it.
	(main): `m4 --help --version' now displays help, not version.
	* ltdl/m4/gnulib-cache.m4: Augment with gnulib-tool --import
	dirname filenamecat.
	* m4/m4module.h (m4_add_include_directory): Add parameter.
	* m4/m4private.h (m4__include_init): New prototype.
	* m4/m4.c (m4_create): Put `.' on path before options are
	collected.
	* m4/path.c (includes): Assume C89.  Use gnulib for file name
	management.
	(m4__include_init): New function.
	(search_path_add): Allow prepending.
	(m4_add_include_directory, search_path_env_init): Adjust callers.
	(m4_path_search): Relative names now invoke path search, since
	`.' might not be first.
	* doc/m4.texinfo (Invoking m4, Search Path): Document new option.

- --
Life is short - so eat dessert first!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFE703s84KuGfSFAYARAkQbAJ9qqflEcz2v7olFsZXY52PtLYGBGQCfRIbX
id3GH9fR8LKYNMB6QRIu/1Y=
=XW+Z
-----END PGP SIGNATURE-----

_______________________________________________
M4-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-patches
m4.patch139 (text/plain, 26.7 KB)
? ltdl/m4/dirname.m4
? ltdl/m4/dos.m4
? ltdl/m4/double-slash-root.m4
? ltdl/m4/filenamecat.m4
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.34
diff -u -p -r1.34 m4.texinfo
--- doc/m4.texinfo	25 Aug 2006 15:34:09 -0000	1.34
+++ doc/m4.texinfo	25 Aug 2006 19:00:14 -0000
@@ -497,8 +497,19 @@ Imports every variable in the environmen
 before @option{-D} and @option{-U}, so they can override the
 enviroment.
 
-@comment FIXME - need to implement -B/--prepend=DIR, to prepend to the
-@comment search path prior to `.'.
+@item -B @var{DIRECTORY}
+@itemx --prepend-include=@var{DIRECTORY}
+Make @code{m4} search @var{DIRECTORY} for included files, prior to
+searching the current working directory.  @xref{Search Path}, for more
+details.  This option may be given more than once.  Some other
+implementations of @code{m4} use @code{-B @var{number}} to change their
+hard-coded limits, but that is unnecessary in @acronym{GNU} where the
+only limit is your hardware capability.  So although it is unlikely that
+you will want to include a relative directory whose name is purely
+numeric, @acronym{GNU} @code{m4} will warn you about this potential
+compatibility issue; you can avoid the warning by using the long
+spelling, or by using @samp{./@var{number}} if you really meant it.
+
 @item -D @var{NAME}@r{[}=@var{VALUE}@r{]}
 @itemx --define=@var{NAME}@r{[}=@var{VALUE}@r{]}
 This enters @var{NAME} into the symbol table, before any input files are
@@ -586,13 +597,14 @@ problem in general, if not undecidable!
 @itemx --diversions=@var{NUM}
 These options are present only for compatibility with previous
 versions of GNU @code{m4}.  They do nothing, because the symbol table
-size and number of diversions are not fixed anymore.
+size and number of diversions are not fixed anymore.  They will
+eventually disappear in future releases.
 
-@item -B @var{NUM}
 @itemx -S @var{NUM}
 @itemx -T @var{NUM}
 These options are present for compatibility with System V @code{m4}, but
-do nothing in this implementation.
+do nothing in this implementation.  They may disappear in future
+releases.
 @end table
 
 @acronym{GNU} @code{m4} comes with a feature of freezing internal state
@@ -2184,7 +2196,7 @@ Show the the current input line number i
 
 @item p
 Print a message when a named file is found through the path search
-mecanism (@pxref{Search Path}), giving the actual file name used.
+mechanism (@pxref{Search Path}), giving the actual file name used.
 
 @item i
 Print a message each time the current input file is changed, giving file
@@ -2941,12 +2953,14 @@ In GNU @code{m4}, an alternative method 
 GNU @code{m4} allows included files to be found in other directories
 than the current working directory.
 
-If a file is not found in the current working directory, and the file
-name is not absolute, the file will be looked for in a specified search
-path.  First, the directories specified with the @samp{-I} option will
-be searched, in the order found on the command line.  Second, if the
-@samp{M4PATH} environment variable is set, it is expected to contain a
-colon-separated list of directories, which will be searched in order.
+If the @option{--prepend-include} or @option{-B} option was provided
+(@pxref{Invoking m4}), those directories are searched first, in reverse
+order that those options were listed on the command line.  Then
+@code{m4} looks in the current working directory.  Next comes the
+directories specified with the @option{--include} or @option{-I} option
+will be searched, in the order found on the command line.  Finally, if
+the @env{M4PATH} environment variable is set, it is expected to contain
+a colon-separated list of directories, which will be searched in order.
 
 If the automatic search for include-files causes trouble, the @samp{p}
 debug flag (@pxref{Debug Levels}) can help isolate the problem.
Index: ltdl/m4/gnulib-cache.m4
===================================================================
RCS file: /sources/m4/m4/ltdl/m4/gnulib-cache.m4,v
retrieving revision 1.8
diff -u -p -r1.8 gnulib-cache.m4
--- ltdl/m4/gnulib-cache.m4	22 Aug 2006 22:36:28 -0000	1.8
+++ ltdl/m4/gnulib-cache.m4	25 Aug 2006 19:00:14 -0000
@@ -15,10 +15,10 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 assert binary-io cloexec close-stream error exit fdl fopen-safer free gendocs getopt gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs getopt gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
-gl_MODULES([assert binary-io cloexec close-stream error exit fdl fopen-safer free gendocs getopt gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf])
+gl_MODULES([assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-safer free gendocs getopt gettext gnupload mkstemp obstack progname regex regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-die xstrndup xvasprintf])
 gl_AVOID([])
 gl_SOURCE_BASE([gnu])
 gl_M4_BASE([ltdl/m4])
Index: m4/m4.c
===================================================================
RCS file: /sources/m4/m4/m4/m4.c,v
retrieving revision 1.16
diff -u -p -r1.16 m4.c
--- m4/m4.c	27 Jul 2006 22:34:55 -0000	1.16
+++ m4/m4.c	25 Aug 2006 19:00:14 -0000
@@ -37,6 +37,7 @@ m4_create (void)
   context->nesting_limit = DEFAULT_NESTING_LIMIT;
 
   context->search_path	 = xzalloc (sizeof context->search_path);
+  m4__include_init (context);
 
   return context;
 }
Index: m4/m4module.h
===================================================================
RCS file: /sources/m4/m4/m4/m4module.h,v
retrieving revision 1.78
diff -u -p -r1.78 m4module.h
--- m4/m4module.h	23 Aug 2006 11:39:26 -0000	1.78
+++ m4/m4module.h	25 Aug 2006 19:00:14 -0000
@@ -386,7 +386,7 @@ extern void	m4_undivert_all	     (m4 *);
 /* --- PATH MANAGEMENT --- */
 
 extern void	m4_include_env_init      (m4 *);
-extern void	m4_add_include_directory (m4 *, const char *);
+extern void	m4_add_include_directory (m4 *, const char *, bool);
 extern FILE *   m4_path_search           (m4 *, const char *, char **);
 
 
Index: m4/m4private.h
===================================================================
RCS file: /sources/m4/m4/m4/m4private.h,v
retrieving revision 1.54
diff -u -p -r1.54 m4private.h
--- m4/m4private.h	22 Aug 2006 22:36:28 -0000	1.54
+++ m4/m4private.h	25 Aug 2006 19:00:14 -0000
@@ -323,6 +323,7 @@ struct m4__search_path_info {
   int max_length;		/* length of longest directory name */
 };
 
+extern void m4__include_init (m4 *);
 
 
 /* Debugging the memory allocator.  */
Index: m4/path.c
===================================================================
RCS file: /sources/m4/m4/m4/path.c,v
retrieving revision 1.18
diff -u -p -r1.18 path.c
--- m4/path.c	22 Aug 2006 22:36:28 -0000	1.18
+++ m4/path.c	25 Aug 2006 19:00:14 -0000
@@ -26,25 +26,19 @@
 #  include <config.h>
 #endif
 
-#if HAVE_STDLIB_H
-#  include <stdlib.h>
-#endif
-
-#if HAVE_STRING_H
-#  include <string.h>
-#else
-#  if HAVE_STRINGS_H
-#    include <strings.h>
-#  endif
-#endif
+#include <stdlib.h>
+#include <string.h>
 
 #include "m4module.h"
 #include "m4private.h"
 
+#include "dirname.h"
+#include "filenamecat.h"
+
 /* Define this to see runtime debug info.  Implied by DEBUG.  */
 /*#define DEBUG_INCL */
 
-static void search_path_add (m4__search_path_info *, const char *);
+static void search_path_add (m4__search_path_info *, const char *, bool);
 static void search_path_env_init (m4__search_path_info *, char *, bool);
 
 
@@ -53,25 +47,33 @@ static void search_path_env_init (m4__se
  */
 
 static void
-search_path_add (m4__search_path_info *info, const char *dir)
+search_path_add (m4__search_path_info *info, const char *dir, bool prepend)
 {
   m4__search_path *path = xmalloc (sizeof *path);
 
-  if (*dir == '\0')
-    dir = ".";
-
-  path->next = NULL;
   path->len = strlen (dir);
   path->dir = xstrdup (dir);
 
   if (path->len > info->max_length) /* remember len of longest directory */
     info->max_length = path->len;
 
-  if (info->list_end == NULL)
-    info->list = path;
+  if (prepend)
+    {
+      path->next = info->list;
+      info->list = path;
+      if (info->list_end == NULL)
+	info->list_end = path;
+    }
   else
-    info->list_end->next = path;
-  info->list_end = path;
+    {
+      path->next = NULL;
+
+      if (info->list_end == NULL)
+	info->list = path;
+      else
+	info->list_end->next = path;
+      info->list_end = path;
+    }
 }
 
 static void
@@ -88,7 +90,7 @@ search_path_env_init (m4__search_path_in
       if (path_end)
 	*path_end = '\0';
       if (!isabs || *path == '/')
-	search_path_add (info, path);
+	search_path_add (info, path, false);
       path = path_end + 1;
     }
   while (path_end);
@@ -108,25 +110,33 @@ m4_include_env_init (m4 *context)
 }
 
 void
-m4_add_include_directory (m4 *context, const char *dir)
+m4_add_include_directory (m4 *context, const char *dir, bool prepend)
 {
   if (m4_get_no_gnu_extensions_opt (context))
     return;
 
-  search_path_add (m4__get_search_path (context), dir);
+  search_path_add (m4__get_search_path (context), dir, prepend);
 
 #ifdef DEBUG_INCL
-  fprintf (stderr, "add_include_directory (%s);\n", dir);
+  fprintf (stderr, "add_include_directory (%s) %s;\n", dir,
+	   prepend ? "prepend" : "append");
 #endif
 }
 
+/* Search for FILE according to -B options, `.', -I options, then
+   M4PATH environment.  If successful, return the open file, and if
+   RESULT is not NULL, set *RESULT to a malloc'd string that
+   represents the file found with respect to the current working
+   directory.  Otherwise, return NULL, and errno reflects the failure
+   from searching `.' (regardless of what else was searched).  */
+
 FILE *
 m4_path_search (m4 *context, const char *file, char **expanded_name)
 {
   FILE *fp;
   m4__search_path *incl;
   char *name;			/* buffer for constructed name */
-  int e;
+  int e = 0;
 
   if (expanded_name != NULL)
     *expanded_name = NULL;
@@ -138,32 +148,27 @@ m4_path_search (m4 *context, const char 
       return NULL;
     }
 
-  /* Look in current working directory first.  */
-  fp = fopen (file, "r");
-  if (fp != NULL)
-    {
-      if (set_cloexec_flag (fileno (fp), true) != 0)
-	m4_error (context, 0, errno,
-		  _("cannot protect input file across forks"));
-      if (expanded_name != NULL)
-	*expanded_name = xstrdup (file);
-      return fp;
-    }
-
-  /* If file not found, and filename absolute, fail.  */
-  if (*file == '/' || m4_get_no_gnu_extensions_opt (context))
-    return NULL;
-  e = errno;
-
-  name = (char *) xmalloc (m4__get_search_path (context)->max_length
-			   + 1 + strlen (file) + 1);
+  /* If file is absolute, or if we are not searching a path, a single
+     lookup will do the trick.  */
+  if (IS_ABSOLUTE_FILE_NAME (file) || m4_get_no_gnu_extensions_opt (context))
+    {
+      fp = fopen (file, "r");
+      if (fp != NULL)
+	{
+	  if (set_cloexec_flag (fileno (fp), true) != 0)
+	    m4_error (context, 0, errno,
+		      _("cannot protect input file across forks"));
+	  if (expanded_name != NULL)
+	    *expanded_name = xstrdup (file);
+	  return fp;
+	}
+      return NULL;
+    }
 
   for (incl = m4__get_search_path (context)->list;
        incl != NULL; incl = incl->next)
     {
-      strncpy (name, incl->dir, incl->len);
-      name[incl->len] = '/';
-      strcpy (name + incl->len + 1, file);
+      name = file_name_concat (incl->dir, file, NULL);
 
 #ifdef DEBUG_INCL
       fprintf (stderr, "path_search (%s) -- trying %s\n", file, name);
@@ -183,26 +188,38 @@ m4_path_search (m4 *context, const char 
 	    *expanded_name = name;
 	  else
 	    free (name);
-	  errno = e;
 	  return fp;
 	}
+      else if (!incl->len)
+	/* Capture errno only when searching `.'.  */
+	e = errno;
+      free (name);
     }
 
-  free (name);
-
   errno = e;
-  return fp;
+  return NULL;
+}
+
+void
+m4__include_init (m4 *context)
+{
+  m4__search_path_info *info = m4__get_search_path (context);
+
+  assert (info);
+  search_path_add (info, "", false);
 }
 
+
 #ifdef DEBUG_INCL
 
-static void
+static void M4_GNUC_UNUSED
 include_dump (m4 *context)
 {
   m4__search_path *incl;
 
   fprintf (stderr, "include_dump:\n");
-  for (incl = m4__get_search_path (context)->list; incl != NULL; incl = incl->next)
+  for (incl = m4__get_search_path (context)->list;
+       incl != NULL; incl = incl->next)
     fprintf (stderr, "\t%s\n", incl->dir);
 }
 
Index: src/main.c
===================================================================
RCS file: /sources/m4/m4/src/main.c,v
retrieving revision 1.76
diff -u -p -r1.76 main.c
--- src/main.c	23 Aug 2006 11:39:26 -0000	1.76
+++ src/main.c	25 Aug 2006 19:00:14 -0000
@@ -25,6 +25,8 @@
 #include "version-etc.h"
 #include "gnu/progname.h"
 
+#include <limits.h>
+
 #define AUTHORS _("Rene' Seindal"), "Gary V. Vaughan"
 
 
@@ -34,14 +36,8 @@ const char *frozen_file_to_read = NULL;
 /* Name of frozen file to produce near completion.  */
 const char *frozen_file_to_write = NULL;
 
-/* If nonzero, display usage information and exit.  */
-static int show_help = 0;
-
-/* If nonzero, print the version on standard output and exit.  */
-static int show_version = 0;
-
 /* If nonzero, import the environment as macros.  */
-static int import_environment = 0;
+static bool import_environment = false;
 
 typedef struct macro_definition
 {
@@ -109,15 +105,16 @@ SPEC is any one of:\n\
       printf (_("\
 \n\
 Dynamic loading features:\n\
-  -M, --module-directory=DIRECTORY  add DIRECTORY to the module search path\n\
-  -m, --load-module=MODULE          load dynamic MODULE from %s\n\
+  -M, --module-directory=DIR   add DIR to the module search path\n\
+  -m, --load-module=MODULE     load dynamic MODULE from %s\n\
 "), USER_MODULE_PATH_ENV);
       fputs (_("\
 \n\
 Preprocessor features:\n\
       --import-environment     import all environment variables as macros\n\
+  -B, --prepend-include=DIR    add DIR to include path before `.'\n\
   -D, --define=NAME[=VALUE]    define NAME has having VALUE, or empty\n\
-  -I, --include=DIRECTORY      append DIRECTORY to include path\n\
+  -I, --include=DIR            add DIR to include path after `.'\n\
   -s, --synclines              generate `#line NUM \"FILE\"' lines\n\
   -U, --undefine=NAME          undefine NAME\n\
 "), stdout);
@@ -158,6 +155,13 @@ FLAGS is any of:\n\
 "), stdout);
       fputs (_("\
 \n\
+If defined, the environment variable `M4PATH' is a colon-separated list\n\
+of directories included after any specified by `-I', and the variable\n\
+`M4MODPATH' is a colon-separated list of directories searched after any\n\
+specified by `-M'.\n\
+"), stdout);
+      fputs (_("\
+\n\
 Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\
 mismatch, or whatever value was passed to the m4exit macro.\n\
 "), stdout);
@@ -166,14 +170,26 @@ mismatch, or whatever value was passed t
   exit (status);
 }
 
+/* For long options that have no equivalent short option, use a
+   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
+enum
+{
+  DIVERSIONS_OPTION = CHAR_MAX + 1,	/* not quite -N, because of message */
+  IMPORT_ENVIRONMENT_OPTION,		/* no short opt */
+  PREPEND_INCLUDE_OPTION,		/* not quite -B, because of message */
+
+  HELP_OPTION,				/* no short opt */
+  VERSION_OPTION			/* no short opt */
+};
+
 /* Decode options and launch execution.  */
 static const struct option long_options[] =
 {
   {"arglength", required_argument, NULL, 'l'},
   {"batch", no_argument, NULL, 'b'},
   {"debug", optional_argument, NULL, 'd'},
+  {"define", required_argument, NULL, 'D'},
   {"discard-comments", no_argument, NULL, 'c'},
-  {"diversions", required_argument, NULL, 'N'},
   {"error-output", required_argument, NULL, 'o'},
   {"fatal-warnings", no_argument, NULL, 'E'},
   {"freeze-state", required_argument, NULL, 'F'},
@@ -189,20 +205,19 @@ static const struct option long_options[
   {"reload-state", required_argument, NULL, 'R'},
   {"silent", no_argument, NULL, 'Q'},
   {"synclines", no_argument, NULL, 's'},
+  {"trace", required_argument, NULL, 't'},
   {"traditional", no_argument, NULL, 'G'},
+  {"undefine", required_argument, NULL, 'U'},
   {"word-regexp", required_argument, NULL, 'W'},
 
-  {"import-environment", no_argument, &import_environment, 1},
-
-  {"help", no_argument, &show_help, 1},
-  {"version", no_argument, &show_version, 1},
+  {"diversions", required_argument, NULL, DIVERSIONS_OPTION},
+  {"import-environment", no_argument, NULL, IMPORT_ENVIRONMENT_OPTION},
+  {"prepend-include", required_argument, NULL, PREPEND_INCLUDE_OPTION},
 
-  /* These are somewhat troublesome.  */
-  { "define", required_argument, NULL, 'D' },
-  { "undefine", required_argument, NULL, 'U' },
-  { "trace", required_argument, NULL, 't' },
+  {"help", no_argument, NULL, HELP_OPTION},
+  {"version", no_argument, NULL, VERSION_OPTION},
 
-  { 0, 0, 0, 0 },
+  { NULL, 0, NULL, 0 },
 };
 
 #define OPTSTRING "B:D:EF:GH:I:L:M:N:PQR:S:T:U:bcd::el:m:o:r:st:"
@@ -212,7 +227,7 @@ main (int argc, char *const *argv, char 
 {
   macro_definition *head;	/* head of deferred argument list */
   macro_definition *tail;
-  macro_definition *new;
+  macro_definition *defn;
   int optchar;			/* option character */
 
   macro_definition *defines;
@@ -251,22 +266,33 @@ main (int argc, char *const *argv, char 
 
   head = tail = NULL;
 
-  while (optchar = getopt_long (argc, (char **) argv, OPTSTRING,
-				long_options, NULL),
-	 optchar != EOF)
+  while ((optchar = getopt_long (argc, (char **) argv, OPTSTRING,
+				 long_options, NULL)) != -1)
     switch (optchar)
       {
       default:
 	usage (EXIT_FAILURE);
 
-      case 0:
+      case 'H':
+	/* -H was supported in 1.4.x.  FIXME - make obsolete after
+            2.0, and remove after 2.1.  For now, keep it silent.  */
 	break;
 
-      case 'B':			/* compatibility junk */
-      case 'H':
       case 'N':
+      case DIVERSIONS_OPTION:
+	/* -N became an obsolete no-op in 1.4.x.  FIXME - remove
+            support for -N after 2.0.  */
+	error (0, 0, _("Warning: `m4 %s' is deprecated"),
+	       optchar == 'N' ? "-N" : "--diversions");
+	break;
+
       case 'S':
       case 'T':
+	/* Compatibility junk: options that other implementations
+	   support, but which we ignore as no-ops and don't list in
+	   --help.  */
+	error (0, 0, _("Warning: `m4 -%c' may be removed in a future release"),
+	       optchar);
 	break;
 
       case 'D':
@@ -276,19 +302,37 @@ main (int argc, char *const *argv, char 
       case 'r':
 	/* Arguments that cannot be handled until later are accumulated.  */
 
-	new = xmalloc (sizeof *new);
-	new->code = optchar;
-	new->macro = optarg;
-	new->next = NULL;
+	defn = xmalloc (sizeof *defn);
+	defn->code = optchar;
+	defn->macro = optarg;
+	defn->next = NULL;
 
 	if (head == NULL)
-	  head = new;
+	  head = defn;
 	else
-	  tail->next = new;
-	tail = new;
+	  tail->next = defn;
+	tail = defn;
 
 	break;
 
+      case 'B':
+	/* In 1.4.x, -B<num> was a no-op option for compatibility with
+	   Solaris m4.  Warn if optarg is all numeric.  FIXME -
+	   silence this warning after 2.0.  */
+	if (isdigit ((unsigned char) *optarg))
+	  {
+	    char *end;
+	    errno = 0;
+	    strtol (optarg, &end, 10);
+	    if (*end == '\0' && errno == 0)
+	      error (0, 0, _("Warning: recommend using `m4 -B ./%s' instead"),
+		     optarg);
+	  }
+	/* fall through */
+      case PREPEND_INCLUDE_OPTION:
+	m4_add_include_directory (context, optarg, true);
+	break;
+
       case 'E':
 	m4_set_fatal_warnings_opt (context, true);
 	break;
@@ -303,12 +347,13 @@ main (int argc, char *const *argv, char 
 	break;
 
       case 'I':
-	m4_add_include_directory (context, optarg);
+	m4_add_include_directory (context, optarg, false);
 	break;
 
       case 'L':
 	m4_set_nesting_limit_opt (context, atoi (optarg));
 	break;
+
       case 'M':
 	if (lt_dlinsertsearchdir (lt_dlgetsearchpath(), optarg) != 0)
 	  {
@@ -375,19 +420,23 @@ main (int argc, char *const *argv, char 
       case 's':
 	m4_set_sync_output_opt (context, true);
 	break;
-      }
 
-  if (show_version)
-    {
-      version_etc (stdout, PACKAGE, PACKAGE_NAME TIMESTAMP,
-		   VERSION, AUTHORS, NULL);
-      exit (EXIT_SUCCESS);
-    }
+      case IMPORT_ENVIRONMENT_OPTION:
+	import_environment = true;
+	break;
 
-  if (show_help)
-    usage (EXIT_SUCCESS);
+      case VERSION_OPTION:
+	version_etc (stdout, PACKAGE, PACKAGE_NAME TIMESTAMP,
+		     VERSION, AUTHORS, NULL);
+	exit (EXIT_SUCCESS);
+	break;
+
+      case HELP_OPTION:
+	usage (EXIT_SUCCESS);
+	break;
+      }
 
-  /* Do the basic initialisations.  */
+  /* Do the basic initializations.  */
 
   m4_input_init (context);
   m4_output_init ();
@@ -405,7 +454,7 @@ main (int argc, char *const *argv, char 
     }
 
   /* Import environment variables as macros.  The definition are
-     preprended to the macro definition list, so -U can override
+     prepended to the macro definition list, so -U can override
      environment variables. */
 
   if (import_environment)
@@ -414,16 +463,16 @@ main (int argc, char *const *argv, char 
 
       for (env = envp; *env != NULL; env++)
 	{
-	  new = xmalloc (sizeof *new);
-	  new->code = 'D';
-	  new->macro = *env;
-	  new->next = head;
-	  head = new;
+	  defn = xmalloc (sizeof *defn);
+	  defn->code = 'D';
+	  defn->macro = *env;
+	  defn->next = head;
+	  head = defn;
 	}
     }
 
   /* Handle deferred command line macro definitions.  Must come after
-     initialisation of the symbol table.  */
+     initialization of the symbol table.  */
   {
     defines = head;
 
Index: tests/options.at
===================================================================
RCS file: /sources/m4/m4/tests/options.at,v
retrieving revision 1.4
diff -u -p -r1.4 options.at
--- tests/options.at	23 Aug 2006 11:39:26 -0000	1.4
+++ tests/options.at	25 Aug 2006 19:00:14 -0000
@@ -35,7 +35,7 @@ comment
  --> ends.
 ]])
 
-AT_CHECK_M4([-c in], 0,
+AT_CHECK_M4([-c in], [0],
 [[This is not a comment This should not disappear.
 
 html  ends.
@@ -66,8 +66,8 @@ export ZAPPED
 OVERRIDE='This is an environment variable which we will change'
 export OVERRIDE
 
-AT_CHECK_M4([--import-environment -UZAPPED -DOVERRIDE='It is changed.' in], 0,
-[[TEST=This is an environment variable
+AT_CHECK_M4([--import-environment -UZAPPED -DOVERRIDE='It is changed.' in],
+[0], [[TEST=This is an environment variable
 ZAPPED=ZAPPED
 OVERRIDE=It is changed.
 ]])
@@ -87,15 +87,16 @@ len(`abc')
 ]])
 
 dnl AT_CHECK_M4 starts life with -d.  Make sure it looks like -daeq.
-AT_CHECK_M4([-tlen in], 0, [[0
+AT_CHECK_M4([-tlen in], [0], [[0
 3
 ]], [[m4trace: -1- len(`abc') -> `3'
 ]])
 
 dnl Test all flags.
-AT_CHECK_M4([-dV in], 0, [[0
+AT_CHECK_M4([-dV in], [0], [[0
 3
-]], [[m4debug: input read from in
+]], [[m4debug: path search for `in' found `in'
+m4debug: input read from in
 m4trace:in:1: -1- id 1: divnum ...
 m4trace:in:1: -1- id 1: divnum -> ???
 m4trace:in:1: -1- id 1: divnum -> `0'
@@ -106,10 +107,114 @@ m4debug:in:3: input exhausted
 ]])
 
 dnl Test addition and subtraction of flags.
-AT_CHECK_M4([-d-e -d+xt in], 0, [[0
+AT_CHECK_M4([-d-e -d+xt in], [0], [[0
 3
 ]], [[m4trace: -1- id 1: divnum
 m4trace: -1- id 2: len(`abc')
 ]])
 
 AT_CLEANUP
+
+
+## ---------------- ##
+## obsolete options ##
+## ---------------- ##
+
+AT_SETUP([deprecated options])
+
+dnl -N/--diversions are no-ops since 1.4.x
+AT_CHECK_M4([-N1 --diversions=1], [0], [],
+[[m4: Warning: `m4 -N' is deprecated
+m4: Warning: `m4 --diversions' is deprecated
+]])
+
+dnl -H/--hashsize are no-ops since 2.0, and still silent for now...
+AT_CHECK_M4([-H1 --hashsize=1])
+
+dnl -S/-T are no-ops for compatibility
+AT_CHECK_M4([-S1 -T1], [0], [],
+[[m4: Warning: `m4 -S' may be removed in a future release
+m4: Warning: `m4 -T' may be removed in a future release
+]])
+
+dnl -Bint can be confused with its no-op meaning in 1.4.x, but all other
+dnl uses of -B or its long option are okay
+AT_CHECK_M4([-B1 -B./1 --prepend-include=1], [0], [],
+[[m4: Warning: recommend using `m4 -B ./1' instead
+]])
+
+AT_CLEANUP
+
+
+## --------------- ##
+## prepend-include ##
+## --------------- ##
+
+AT_SETUP([prepend-include])
+
+dnl Lots of data to set up.
+AT_DATA([[in]],
+[[include(`foo')dnl
+include(`bar')dnl
+include(`bad')dnl
+include(`blah')dnl
+]])
+
+AT_CHECK([mkdir pre post])
+
+AT_DATA([[pre/foo]], [[in pre/foo
+]])
+AT_DATA([[foo]], [[in ./foo
+]])
+AT_DATA([[bar]], [[in ./bar
+]])
+AT_DATA([[post/bar]], [[in post/bar
+]])
+AT_DATA([[post/blah]], [[in post/blah
+]])
+
+dnl Make circular links in the subdirectories, to ensure that the error
+dnl message when bad cannot be opened comes from the search in ., regardless
+dnl of what else was searched.
+AT_CHECK([ln -s bad pre/bad])
+AT_CHECK([ln -s bad post/bad])
+
+dnl Finally, see that it all works.
+AT_CHECK_M4([-I post -B pre in], [1],
+[[in pre/foo
+in ./bar
+in post/blah
+]], [[m4:in:3: include: cannot open `bad': No such file or directory
+]])
+
+AT_CLEANUP
+
+
+## ---------------- ##
+## help and version ##
+## ---------------- ##
+
+AT_SETUP([help and version])
+
+AT_CHECK_M4([--help], [0], [stdout])
+AT_CHECK([[sed -n -e 's|Usage:.*\[OPTION\]... \[FILE\]...|success|p' stdout]],
+[0], [success
+])
+
+AT_CHECK_M4([--version], [0], [stdout])
+AT_CHECK([[sed -n -e 's|There is NO WARRANTY.*|success|p' stdout]],
+[0], [success
+])
+
+dnl make sure option specified first takes precedence
+AT_CHECK_M4([--help --version], [0], [stdout])
+AT_CHECK([[sed -n -e 's|Usage:.*\[OPTION\]... \[FILE\]...|success|p' stdout]],
+[0], [success
+])
+
+AT_CHECK_M4([--version --help], [0], [stdout])
+AT_CHECK([[sed -n -e 's|There is NO WARRANTY.*|success|p' stdout]],
+[0], [success
+])
+
+AT_CLEANUP
Index: tests/testsuite.at
===================================================================
RCS file: /sources/m4/m4/tests/testsuite.at,v
retrieving revision 1.19
diff -u -p -r1.19 testsuite.at
--- tests/testsuite.at	22 Aug 2006 16:16:48 -0000	1.19
+++ tests/testsuite.at	25 Aug 2006 19:00:14 -0000
@@ -23,8 +23,10 @@ m4_version_prereq([2.52e])
 
 # AT_CHECK_M4(ARGS, [EXIT-STATUS = 0], [STDOUT = `'], [STDERR = `'])
 # ------------------------------------------------------------------
+# Run m4 with ARGS, and stdin redirected from /dev/null.  Expect EXIT-STATUS,
+# with output matching STDOUT and STDERR as in AT_CHECK.
 m4_define([AT_CHECK_M4],
-[AT_CHECK([m4 -b -d $1], [$2], [$3], [$4])
+[AT_CHECK([m4 -b -d $1 < /dev/null], [$2], [$3], [$4])
 ])
 
 # AT_TEST_M4(TITLE, INPUT, [STDOUT = `'], [STDERR = `'])
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.