[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RFC: m4 2.0 --prepend-include option
From: |
Eric Blake |
Subject: |
RFC: m4 2.0 --prepend-include option |
Date: |
Wed, 23 Aug 2006 09:24:14 -0600 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060719 Thunderbird/1.5.0.5 Mnenhy/0.7.4.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Digging through the archives of m4 wish list items:
http://lists.gnu.org/archive/html/m4-patches/2003-09/msg00027.html
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 do have a question, though. Some implementations of m4 (such as
Solaris) have a -B<num> option, which changes the size of the rescan
buffer from its default of 4096 bytes. Obviously, this is an arbitrary
limit, so GNU m4 doesn't need this option, but m4 1.4.x silently accepts
and ignores the -B option for compatibility.
If I make -B a synonym for --prepend-include, then a user doing 'm4
- -B1024' and expecting traditional Solaris semantics would have subtly
different behavior if they happened to have a ./1024/ directory. But
since POSIX does not specify -B, a user can't expect it to be portable
anyways. So should I go ahead and make -B a short option synonym?
One other thing to think of. Right now, CVS m4 has different behavior
depending on whether POSIXLY_CORRECT vs. -G was specified, although both
of those disable various GNU extensions incompatible with POSIX and/or
traditional implementations. This is a maintenance nightmare, and I would
rather see POSIXLY_CORRECT imply -G, add an option -g (--gnu) to override
it (and some BSD versions already have -g to turn on GNU compatibility),
and then base all compatibility decisions solely on whether -G is in
effect. And currently, -G disables path searches for including files. So
by that proposal, a user could then do 'POSIXLY_CORRECT=1 m4 -B1024' to
get the same behavior with GNU or Solaris m4, regardless of the presence
of ./1024, because path searches would be disabled in the GNU version
thanks to the implicit -G.
This patch also fixes 'm4 --help --version' to display help, consistent
with coreutils, rather than its current behavior of showing the version.
2006-08-23 Eric Blake <address@hidden>
* src/main.c (long_options, main): Add --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 address@hidden
-----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
iD8DBQFE7HMe84KuGfSFAYARAmo9AKCDAFEHpIgo43f38UakVzpI5HwWiwCgx8+v
hnAJnWEQ11yZCC9DIaXpyzk=
=/4dj
-----END PGP SIGNATURE-----
? 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.32
diff -u -p -r1.32 m4.texinfo
--- doc/m4.texinfo 23 Aug 2006 11:39:26 -0000 1.32
+++ doc/m4.texinfo 23 Aug 2006 15:02:40 -0000
@@ -261,7 +261,7 @@ Fast loading of frozen state
Compatibility with other versions of @code{m4}
-* Extensions:: Extensions in @acronym{GNU} m4
+* Extensions:: Extensions in @acronym{GNU} M4
* Incompatibilities:: Other incompatibilities
Copying This Manual
@@ -497,8 +497,16 @@ Imports every variable in the environmen
before @option{-D} and @option{-U}, so they can override the
enviroment.
address@hidden FIXME - need to implement -B/--prepend=DIR, to prepend to the
address@hidden search path prior to `.'.
address@hidden FIXME - should we make -B a synonym for --prepend-include? The
address@hidden only drawback is that -B1024 is currently ignored for
address@hidden compatibility, but if the user actually had a directory ./1024,
address@hidden it would subtly change the semantics. But POSIX doesn't
address@hidden specify -B, so we are free to define it how we want.
address@hidden address@hidden
+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.
+
@item -D @address@hidden@address@hidden
@itemx address@hidden@address@hidden@r{]}
This enters @var{NAME} into the symbol table, before any input files are
@@ -2803,12 +2811,13 @@ 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
address@hidden environment variable is set, it is expected to contain a
-colon-separated list of directories, which will be searched in order.
+If the @option{-B} option was provided (@pxref{Invoking m4}), those
+directories are searched first, in the order found on the command line.
+Then @code{m4} looks in the current working directory. Next comes the
+directories specified with the @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 23 Aug 2006 15:02:40 -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 23 Aug 2006 15:02:40 -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 23 Aug 2006 15:02:40 -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 23 Aug 2006 15:02:40 -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 23 Aug 2006 15:02:40 -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 23 Aug 2006 15:02:40 -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\
+ --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,6 +170,17 @@ 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
+{
+ IMPORT_ENVIRONMENT_OPTION = CHAR_MAX + 1,
+ PREPEND_INCLUDE_OPTION,
+
+ HELP_OPTION,
+ VERSION_OPTION
+};
+
/* Decode options and launch execution. */
static const struct option long_options[] =
{
@@ -192,17 +207,18 @@ static const struct option long_options[
{"traditional", no_argument, NULL, 'G'},
{"word-regexp", required_argument, NULL, 'W'},
- {"import-environment", no_argument, &import_environment, 1},
+ {"import-environment", no_argument, NULL, IMPORT_ENVIRONMENT_OPTION},
+ {"prepend-include", required_argument, NULL, PREPEND_INCLUDE_OPTION},
- {"help", no_argument, &show_help, 1},
- {"version", no_argument, &show_version, 1},
+ {"help", no_argument, NULL, HELP_OPTION},
+ {"version", no_argument, NULL, VERSION_OPTION},
/* These are somewhat troublesome. */
{ "define", required_argument, NULL, 'D' },
{ "undefine", required_argument, NULL, 'U' },
{ "trace", required_argument, NULL, 't' },
- { 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 +228,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 +267,21 @@ 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:
- break;
-
- case 'B': /* compatibility junk */
+ case 'B': /* FIXME - should -B be a synonym of --prepend-include? */
case 'H':
case 'N':
case 'S':
case 'T':
+ /* Compatibility junk: options that other implementations
+ support, but which we ignore as no-ops and don't list in
+ --help. */
break;
case 'D':
@@ -276,16 +291,16 @@ 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;
@@ -303,12 +318,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 +391,27 @@ 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 PREPEND_INCLUDE_OPTION:
+ m4_add_include_directory (context, optarg, true);
+ break;
+
+ 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 +429,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 +438,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;
- RFC: m4 2.0 --prepend-include option,
Eric Blake <=
multidigit arguments [was: RFC: m4 2.0 --prepend-include option], Eric Blake, 2006/08/24
Re: RFC: m4 2.0 --prepend-include option, Eric Blake, 2006/08/25