[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Another POSIX incompatibility
From: |
Eric Blake-1 |
Subject: |
Re: Another POSIX incompatibility |
Date: |
Wed, 8 Nov 2006 09:58:33 -0800 (PST) |
> Here's the patch for the branch. I'm thinking that for the head, maybe I
> should turn --synclines into an option with an optional argument, so that
> you can turn synclines off between files as well as on by using -s0 (and
> keeping -s as a synonym for -s1). And maybe it is time to think about
> adding command line options --pushdef, --popdef, and --traceoff (of those,
> only --pushdef might be a candidate for a short option -p), for even more
> inter-file operational capability. Head also would support -m and -r
> between files (mainly because it was easiest to use the existing deferred
> argument handling mechanism to achieve this patch, by treating intermixed
> files as deferred arguments to option '\1').
Here's the first part of the patch - fixing -D to match the branch. In
fact, a regression had crept in; on the branch, -D always did a define,
but for a while, on head it was doing a pushdef since rev 1.39 of main.c
in 2003.
On further thought, -s cannot be made an optional argument, because
it would break POSIX-mandated usage like 'm4 -sDfoo' (even though
a POSIX app should use 'm4 -s -D foo' instead). But I can instead
add a new option, '--syncoutput', with an optional argument, and make
that match the syncoutput builtin, then redefine -s/--synclines to be
a synonym for --syncoutput=1. I also plan to add --pushdef/-p,
--popdef, add --traceon as a synonym for --trace, and add --traceoff,
all as part of the second part of the patch.
2006-11-08 Eric Blake <address@hidden>
Merge deferred handling of -D option from branch.
* doc/m4.texinfo (Debugging options, Preprocessor features)
(Dynamic loading features, Operation modes, Invoking m4):
Document this change.
* src/main.c (OPTSTRING): Specify in-order processing.
(process_file): New function.
(main): Use it to interleave files and deferred options.
* tests/macros.at (Command line define): New test.
* tests/generate.awk: Allow '@comment file' as first example
within a node.
* tests/options.at (option grouping): Update to reflect actual
POSIX semantics.
(file names): New test.
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.76
diff -u -r1.76 m4.texinfo
--- doc/m4.texinfo 7 Nov 2006 19:18:10 -0000 1.76
+++ doc/m4.texinfo 8 Nov 2006 17:49:51 -0000
@@ -537,19 +537,22 @@
@cindex @env{POSIXLY_CORRECT}
All options begin with @samp{-}, or if long option names are used, with
@samp{--}. A long option name need not be written completely, any
-unambiguous prefix is sufficient. Unless @env{POSIXLY_CORRECT} is set
-in the environment, options may be intermixed with files. The argument
address@hidden is a marker to denote the end of options.
+unambiguous prefix is sufficient. @acronym{POSIX} requires @code{m4} to
+recognize arguments intermixed with files, even when
address@hidden is set in the environment. Most options take
+effect at startup regardless of their position, but some are documented
+below as taking effect after any files that occurred earlier in the
+command line. The argument @option{--} is a marker to denote the end of
+options.
With short options, options that do not take arguments may be combined
into a single command line argument with subsequent options, options
with mandatory arguments may be provided either as a single command line
argument or as two arguments, and options with optional arguments must
-be provided as a single argument. In other words, without
address@hidden, @kbd{m4 -QPDfoo -d a -d+f} is equivalent to
+be provided as a single argument. In other words,
address@hidden -QPDfoo -d a -d+f} is equivalent to
@kbd{m4 -Q -P -D foo -d -d+f -- ./a}, although the latter form is
-considered canonical. (With @env{POSIXLY_CORRECT}, it is equivalent to
address@hidden -Q -P -D foo -d -- ./a ./-d+f}).
+considered canonical.
With long options, options with mandatory arguments may be provided with
an equal sign (@samp{=}) in a single argument, or as two arguments, and
@@ -643,7 +646,8 @@
Set the regular expression syntax according to @var{RESYNTAX-SPEC}.
When this option is not given, @acronym{GNU} M4 uses emacs compatible
regular expressions. @xref{Changeresyntax}, for more details on the
-format and meaning of @var{RESYNTAX-SPEC}.
+format and meaning of @var{RESYNTAX-SPEC}. This option may be given
+more than once, and order with respect to file names is significant.
@item --safer
Cripple the builtins @code{maketemp}, @code{mkstemp} (@pxref{Mkstemp}),
@@ -675,7 +679,8 @@
By default, the modules @samp{m4}, @samp{traditional}, and @samp{gnu}
are preloaded, although this can be controlled during configuration
with the @option{--with-modules} option to
address@hidden@value{VERSION}/@/configure}.
address@hidden@value{VERSION}/@/configure}. This option may be given more
+than once, and order with respect to file names is significant.
@end table
@node Preprocessor features
@@ -713,8 +718,9 @@
read. If @address@hidden is missing, the value is taken to be the
empty string. The @var{VALUE} can be any string, and the macro can be
defined to take arguments, just as if it was defined from within the
-input. This option may be given more than once; order is significant,
-and redefining the same @var{NAME} loses the previous value.
+input. This option may be given more than once; order with respect to
+file names is significant, and redefining the same @var{NAME} loses the
+previous value.
@item -I @var{DIRECTORY}
@itemx address@hidden
@@ -725,7 +731,8 @@
@item -s
@itemx --synclines
Generate synchronization lines, for use by the C preprocessor or other
-similar tools. This is useful, for example, when @code{m4} is used as a
+similar tools. Order is significant with respect to file names. This
+option is useful, for example, when @code{m4} is used as a
front end to a compiler. Source file name and line number information
is conveyed by directives of the form @samp{#line @var{linenum}
"@var{file}"}, which are inserted as needed into the middle of the
@@ -745,7 +752,8 @@
This deletes any predefined meaning @var{NAME} might have. Obviously,
only predefined macros can be deleted in this way. This option may be
given more than once; undefining a @var{NAME} that does not have a
-definition is silently ignored.
+definition is silently ignored. Order is significant with respect to
+file names.
@end table
@node Limits control
@@ -890,7 +898,8 @@
@itemx address@hidden
This enables tracing for the macro @var{NAME}, at any point where it is
defined. @var{NAME} need not be defined when this option is given.
-This option may be given more than once. @xref{Trace}, for more details.
+This option may be given more than once, and order is significant with
+respect to file names. @xref{Trace}, for more details.
@end table
@node Command line files
@@ -914,6 +923,29 @@
@comment interactive use when switching to stdin in a non-default parse
@comment state.
+The options @option{--define} (@option{-D}), @option{--undefine}
+(@option{-U}), @option{--synclines} (@option{-s}), @option{--trace}
+(@option{-t}), @option{--regexp-syntax} (@option{-r}), and
address@hidden (@option{-m}) only take effect after processing
+input from any file names that occur earlier on the command line. For
+example, assume the file @file{foo} contains:
+
address@hidden file: foo
address@hidden
+$ @kbd{cat foo}
+bar
address@hidden example
+
+The text @samp{bar} can then be redefined over multiple uses of
address@hidden:
+
address@hidden options: -Dbar=hello foo -Dbar=world foo
address@hidden
+$ @kbd{m4 -Dbar=hello foo -Dbar=world foo}
address@hidden
address@hidden
address@hidden example
+
If none of the input files invoked @code{m4exit} (@pxref{M4exit}), the
exit status of @code{m4} will be 0 for success, 1 for general failure
(such as problems with reading an input file), and 63 for version
@@ -4401,6 +4433,7 @@
@comment file: foo
@example
+$ @kbd{cat foo}
bar
@end example
Index: src/main.c
===================================================================
RCS file: /sources/m4/m4/src/main.c,v
retrieving revision 1.100
diff -u -r1.100 main.c
--- src/main.c 27 Oct 2006 04:03:28 -0000 1.100
+++ src/main.c 8 Nov 2006 17:49:51 -0000
@@ -35,7 +35,7 @@
typedef struct macro_definition
{
struct macro_definition *next;
- int code; /* D, U or t */
+ int code; /* deferred optchar */
const char *macro;
} macro_definition;
@@ -232,7 +232,12 @@
{ NULL, 0, NULL, 0 },
};
-#define OPTSTRING "B:D:EF:GH:I:L:M:N:PQR:S:T:U:bcd::eil:m:o:r:st:"
+/* POSIX requires only -D, -U, and -s; and says that the first two
+ must be recognized when interspersed with file names. Traditional
+ behavior also handles -s between files. Starting OPTSTRING with
+ '-' forces getopt_long to hand back file names as arguments to opt
+ '\1', rather than reordering the command line. */
+#define OPTSTRING "-B:D:EF:GH:I:L:M:N:PQR:S:T:U:bcd::eil:m:o:r:st:"
/* For determining whether to be interactive. */
enum interactive_choice
@@ -256,6 +261,33 @@
return size;
}
+/* Process a command line file NAME, and return true only if it was
+ stdin. */
+static bool
+process_file (m4 *context, const char *name)
+{
+ bool result = false;
+ if (strcmp (name, "-") == 0)
+ {
+ m4_push_file (context, stdin, "stdin", false);
+ result = true;
+ }
+ else
+ {
+ char *full_name;
+ FILE *fp = m4_path_search (context, name, &full_name);
+ if (fp == NULL)
+ {
+ m4_error (context, 0, errno, _("cannot open file `%s'"), name);
+ return false;
+ }
+ m4_push_file (context, fp, full_name, true);
+ free (full_name);
+ }
+ m4_macro_expand_input (context);
+ return result;
+}
+
/* Main entry point. Parse arguments, load modules, then parse input. */
int
@@ -268,9 +300,9 @@
size_t size; /* for parsing numeric option arguments */
macro_definition *defines;
- FILE *fp;
bool read_stdin = false; /* true iff we have read from stdin */
bool import_environment = false; /* true to import environment */
+ bool seen_file = false;
const char *debugfile = NULL;
const char *frozen_file_to_read = NULL;
const char *frozen_file_to_write = NULL;
@@ -339,9 +371,11 @@
case 'D':
case 'U':
- case 't':
case 'm':
case 'r':
+ case 's':
+ case 't':
+ case '\1':
/* Arguments that cannot be handled until later are accumulated. */
defn = xmalloc (sizeof *defn);
@@ -478,10 +512,6 @@
debugfile = optarg;
break;
- case 's':
- m4_set_sync_output_opt (context, true);
- break;
-
case IMPORT_ENVIRONMENT_OPTION:
import_environment = true;
break;
@@ -502,13 +532,20 @@
}
/* Interactive if specified, or if no input files and stdin and
- stderr are terminals, to match sh behavior. */
+ stderr are terminals, to match sh behavior. Interactive mode
+ means unbuffered output, and interrupts ignored. */
m4_set_interactive_opt (context, (interactive == INTERACTIVE_YES
|| (interactive == INTERACTIVE_UNKNOWN
&& optind == argc
&& isatty (STDIN_FILENO)
&& isatty (STDERR_FILENO))));
+ if (m4_get_interactive_opt (context))
+ {
+ signal (SIGINT, SIG_IGN);
+ setbuf (stdout, NULL);
+ }
+
/* Do the basic initializations. */
if (debugfile && !m4_debug_set_output (context, debugfile))
@@ -554,7 +591,6 @@
while (defines != NULL)
{
macro_definition *next;
- char *macro_value;
const char *arg = defines->macro;
switch (defines->code)
@@ -563,13 +599,17 @@
{
m4_symbol_value *value = m4_symbol_value_create ();
- macro_value = strchr (arg, '=');
+ /* defines->arg is read-only, so we need a copy. */
+ char *macro_name = xstrdup (arg);
+ char *macro_value = strchr (macro_name, '=');
+
if (macro_value != NULL)
*macro_value++ = '\0';
m4_set_symbol_value_text (value, xstrdup (macro_value
- ? macro_value :
""));
+ ? macro_value : ""));
- m4_symbol_pushdef (M4SYMTAB, arg, value);
+ m4_symbol_define (M4SYMTAB, macro_name, value);
+ free (macro_name);
}
break;
@@ -577,10 +617,6 @@
m4_symbol_delete (M4SYMTAB, arg);
break;
- case 't':
- m4_set_symbol_name_traced (M4SYMTAB, arg, true);
- break;
-
case 'm':
m4_module_load (context, arg, 0);
break;
@@ -595,6 +631,19 @@
}
break;
+ case 's':
+ m4_set_sync_output_opt (context, true);
+ break;
+
+ case 't':
+ m4_set_symbol_name_traced (M4SYMTAB, arg, true);
+ break;
+
+ case '\1':
+ seen_file = true;
+ read_stdin |= process_file (context, arg);
+ break;
+
default:
assert (!"INTERNAL ERROR: bad code in deferred arguments");
abort ();
@@ -606,52 +655,17 @@
}
}
- /* Interactive mode means unbuffered output, and interrupts ignored. */
-
- if (m4_get_interactive_opt (context))
- {
- signal (SIGINT, SIG_IGN);
- setbuf (stdout, (char *) NULL);
- }
+ /* Handle remaining input files. Each file is pushed on the input,
+ and the input read. */
- /* Handle the various input files. Each file is pushed on the input,
- and the input read. Wrapup text is handled separately later. */
-
- exit_status = EXIT_SUCCESS;
- if (optind == argc)
- {
- m4_push_file (context, stdin, "stdin", false);
- read_stdin = true;
- m4_macro_expand_input (context);
- }
+ if (optind == argc && !seen_file)
+ read_stdin = process_file (context, "-");
else
for (; optind < argc; optind++)
- {
- if (strcmp (argv[optind], "-") == 0)
- {
- m4_push_file (context, stdin, "stdin", false);
- read_stdin = true;
- }
- else
- {
- char *name;
- fp = m4_path_search (context, argv[optind], &name);
- if (fp == NULL)
- {
- error (0, errno, "%s", argv[optind]);
- exit_status = EXIT_FAILURE;
- continue;
- }
- else
- {
- m4_push_file (context, fp, name, true);
- free (name);
- }
- }
- m4_macro_expand_input (context);
- }
+ read_stdin |= process_file (context, argv[optind]);
- /* Now handle wrapup text. */
+ /* Now handle wrapup text.
+ FIXME - when -F is in effect, should wrapped text be frozen? */
while (m4_pop_wrapup (context))
m4_macro_expand_input (context);
@@ -680,8 +694,7 @@
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);
+ exit_status = m4_get_exit_status (context);
m4_delete (context);
m4_hash_exit ();
Index: tests/generate.awk
===================================================================
RCS file: /sources/m4/m4/tests/generate.awk,v
retrieving revision 1.23
diff -u -r1.23 generate.awk
--- tests/generate.awk 21 Oct 2006 15:23:56 -0000 1.23
+++ tests/generate.awk 8 Nov 2006 17:49:51 -0000
@@ -80,8 +80,7 @@
{
if (seq == 0)
new_group(node);
- if (!file)
- seq++;
+ seq++;
printf ("echo \"$at_srcdir/%s:%d:\"\n", FILENAME, NR)
next;
}
Index: tests/macros.at
===================================================================
RCS file: /sources/m4/m4/tests/macros.at,v
retrieving revision 1.10
diff -u -r1.10 macros.at
--- tests/macros.at 10 Oct 2006 12:47:23 -0000 1.10
+++ tests/macros.at 8 Nov 2006 17:49:51 -0000
@@ -99,6 +99,41 @@
AT_CLEANUP(freezeme.m4 frozen.m4f)
+## ------------------- ##
+## Command line define ##
+## ------------------- ##
+
+AT_SETUP([Command line define])
+
+dnl Test that -D after last file still affects m4wrap'd text.
+AT_DATA([in1], [[m4wrap(`foo
+')foo
+]])
+AT_DATA([in2], [[foo
+]])
+AT_CHECK_M4([-Dfoo=1 in1 -Dfoo=2 in2 -Dfoo=3], [0],
+[[1
+2
+3
+]])
+
+dnl Test that -D only affects top-most definition.
+AT_DATA([in1], [[define(`foo', `1')pushdef(`foo', `2')dnl
+]])
+AT_DATA([in2], [[foo
+popdef(`foo')foo
+popdef(`foo')foo
+]])
+AT_CHECK_M4([in1 -Dfoo=3 in2], [0],
+[[3
+1
+foo
+]])
+
+AT_CLEANUP
+
+
+
## ---------------- ##
## pushdef/popdef. ##
## ---------------- ##
Index: tests/options.at
===================================================================
RCS file: /sources/m4/m4/tests/options.at,v
retrieving revision 1.22
diff -u -r1.22 options.at
--- tests/options.at 19 Oct 2006 23:13:45 -0000 1.22
+++ tests/options.at 8 Nov 2006 17:49:51 -0000
@@ -76,6 +76,35 @@
AT_CLEANUP
+## ---------- ##
+## file names ##
+## ---------- ##
+
+AT_SETUP([file names])
+
+dnl Check that all files are processed even after missing file
+AT_DATA([in], [[hello world
+]])
+AT_CHECK_M4([oops in], [1], [[hello world
+]], [[m4: cannot open file `oops': No such file or directory
+]])
+
+dnl Check that '-' means stdin, even if ./- exists.
+AT_DATA([-], [[hi
+]])
+AT_CHECK_M4([-], [0])
+AT_CHECK_M4([- --], [0])
+AT_CHECK_M4([-- -], [0])
+AT_CHECK_M4([./-], [0], [[hi
+]])
+AT_CHECK_M4([./- --], [0], [[hi
+]])
+AT_CHECK_M4([-- ./-], [0], [[hi
+]])
+
+AT_CLEANUP
+
+
## --------------- ##
## option grouping ##
## --------------- ##
@@ -107,6 +136,14 @@
AT_CHECK_M4([-Q -P -D foo -d -d+f -- a], [0], [[ 1
]])
+AT_CHECK_M4([-QPDfoo -d -- a -d+f], [0], [[ 1
+hi
+]])
+
+AT_CHECK_M4([-Q -P -D foo -d ./a ./-d+f], [0], [[ 1
+hi
+]])
+
AT_CHECK_M4([--def foo --debug a], [0], [[ 1
m@&address@hidden()
]])
@@ -120,10 +157,16 @@
export POSIXLY_CORRECT
AT_CHECK_M4([-QPDfoo -d a -d+f], [0], [[ 1
+]])
+
+AT_CHECK_M4([-Q -P -D foo -d -d+f -- ./a], [0], [[ 1
+]])
+
+AT_CHECK_M4([-QPDfoo -d -- a -d+f], [0], [[ 1
hi
]])
-AT_CHECK_M4([-Q -P -D foo -d -- a ./-d+f], [0], [[ 1
+AT_CHECK_M4([-Q -P -D foo -d ./a ./-d+f], [0], [[ 1
hi
]])
--
View this message in context:
http://www.nabble.com/Re%3A-Another-POSIX-incompatibility-tf2553305.html#a7243522
Sent from the Gnu - M4 - Patches mailing list archive at Nabble.com.