Re: Another POSIX incompatibility
Eric Blake-1 <[email protected]>
| Newsgroups | gmane.comp.gnu.m4.patches |
|---|---|
| Message-ID | <[email protected]> |
> 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 <[email protected]> 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 -@option{--} 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 +@env{POSIXLY_CORRECT} 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 -@env{POSIXLY_CORRECT}, @kbd{m4 -QPDfoo -d a -d+f} is equivalent to +be provided as a single argument. In other words, +@kbd{m4 -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 -@kbd{m4 -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 -@file{m4-@value{VERSION}/@/configure}. +@file{m4-@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 @samp{=@var{VALUE}} 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 --include=@var{DIRECTORY} @@ -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 --trace=@var{NAME} 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 +@option{--load-module} (@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: + +@comment file: foo +@example +$ @kbd{cat foo} +bar +@end example + +The text @samp{bar} can then be redefined over multiple uses of +@file{foo}: + +@comment options: -Dbar=hello foo -Dbar=world foo +@example +$ @kbd{m4 -Dbar=hello foo -Dbar=world foo} +@result{}hello +@result{}world +@end 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@&t@4_dnl() ]]) @@ -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.