From dd978e990064e693842b2b22b73221ef62ac53f8 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 1 Nov 2006 13:44:53 +0000 Subject: [PATCH] * doc/m4.texinfo (Invoking m4): Update according to POSIX 200x draft wording. * src/m4.h (m4_path_search): Tweak signature. * src/path.c (m4_path_search): Likewise. * src/builtin.c (include): Update caller. * src/m4.c (main): Allow -D, -U, -t, and -s to be interspersed with file names. Don't write to **argv. (process_file): New helper method. * NEWS: Document this fix. --- ChangeLog | 12 +++++ NEWS | 3 ++ doc/m4.texinfo | 36 ++++++++----- src/builtin.c | 4 +- src/m4.c | 163 +++++++++++++++++++++++++++++++-------------------------- src/m4.h | 2 +- src/path.c | 2 +- 7 files changed, 132 insertions(+), 90 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d7f5b94..93c39260 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-11-01 Eric Blake + + * doc/m4.texinfo (Invoking m4): Update according to POSIX 200x + draft wording. + * src/m4.h (m4_path_search): Tweak signature. + * src/path.c (m4_path_search): Likewise. + * src/builtin.c (include): Update caller. + * src/m4.c (main): Allow -D, -U, -t, and -s to be interspersed + with file names. Don't write to **argv. + (process_file): New helper method. + * NEWS: Document this fix. + 2006-10-31 Eric Blake * m4/gnulib-cache.m4: Augment with 'gnulib-tool --import strstr'. diff --git a/NEWS b/NEWS index 78c1df38..7206904e 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,9 @@ Version 1.4.8 - ?? ??? 2006, by ?? (CVS version 1.4.7a) argument the same as if it were missing, rather than using the empty string and making it impossible to end a comment or quote. * The `translit' macro now operates in linear instead of quadratic time. +* The `-D', `-U', `-s', and `-t' command line options now take effect + after any files encountered earlier on the command line, rather than up + front, as is done in traditional implementations and required by POSIX. Version 1.4.7 - 25 September 2006, by Eric Blake (CVS version 1.4.6a) diff --git a/doc/m4.texinfo b/doc/m4.texinfo index e9d4808d..9968a3ae 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -495,19 +495,22 @@ The format of the @code{m4} command is: @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 @@ -596,8 +599,9 @@ This enters @var{NAME} into the symbol table, before any input files are 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} @@ -608,7 +612,8 @@ details. This option may be given more than once. @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 @@ -627,7 +632,8 @@ until the beginning of the next generated line. 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 @@ -752,7 +758,8 @@ unlimited. @xref{Debug Levels}, for more details. @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 @@ -772,6 +779,11 @@ terminal or other special file type. It is an error if an input file ends in the middle of argument collection, a comment, or a quoted string. +The options @option{--define} (@option{-D}), @option{--undefine} +(@option{-U}), @option{--synclines} (@option{-s}), and @option{--trace} +(@option{-t}) only take effect after processing input from any file +names that occur earlier on the command line. + 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 diff --git a/src/builtin.c b/src/builtin.c index 405c95b3..cc490635 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1199,7 +1199,7 @@ static void include (int argc, token_data **argv, boolean silent) { FILE *fp; - const char *name; + char *name; if (bad_argc (argv[0], argc, 2, 2)) return; @@ -1214,7 +1214,7 @@ include (int argc, token_data **argv, boolean silent) } push_file (fp, name, TRUE); - free ((char *) name); + free (name); } /*------------------------------------------------. diff --git a/src/m4.c b/src/m4.c index 7cf28faa..fc6c42e4 100644 --- a/src/m4.c +++ b/src/m4.c @@ -65,8 +65,8 @@ const char *program_name; struct macro_definition { struct macro_definition *next; - int code; /* D, U or t */ - const char *macro; + int code; /* D, U, s, t, or '\1' */ + const char *arg; }; typedef struct macro_definition macro_definition; @@ -257,10 +257,49 @@ static const struct option long_options[] = where we try to continue execution in the meantime. */ int retcode; +/* Process a command line file NAME, and return TRUE only if it was + stdin. */ +static boolean +process_file (const char *name) +{ + boolean result = FALSE; + if (strcmp (name, "-") == 0) + { + /* If stdin is a terminal, we want to allow 'm4 - file -' + to read input from stdin twice, like GNU cat. Besides, + there is no point closing stdin before wrapped text, to + minimize bugs in syscmd called from wrapped text. */ + push_file (stdin, "stdin", FALSE); + result = TRUE; + } + else + { + char *full_name; + FILE *fp = m4_path_search (name, &full_name); + if (fp == NULL) + { + error (0, errno, "%s", name); + /* Set the status to EXIT_FAILURE, even though we + continue to process files after a missing file. */ + retcode = EXIT_FAILURE; + return FALSE; + } + push_file (fp, full_name, TRUE); + free (full_name); + } + expand_input (); + return result; +} + +/* 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. */ #ifdef ENABLE_CHANGEWORD -#define OPTSTRING "B:D:EF:GH:I:L:N:PQR:S:T:U:W:d::eil:o:st:" +#define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:W:d::eil:o:st:" #else -#define OPTSTRING "B:D:EF:GH:I:L:N:PQR:S:T:U:d::eil:o:st:" +#define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:d::eil:o:st:" #endif int @@ -268,13 +307,13 @@ main (int argc, char *const *argv, char *const *envp) { macro_definition *head; /* head of deferred argument list */ macro_definition *tail; - macro_definition *new; + macro_definition *defn; int optchar; /* option character */ macro_definition *defines; - FILE *fp; boolean read_stdin = FALSE; boolean interactive = FALSE; + boolean seen_file = FALSE; const char *debugfile = NULL; const char *frozen_file_to_read = NULL; const char *frozen_file_to_write = NULL; @@ -293,9 +332,8 @@ main (int argc, char *const *argv, char *const *envp) 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: @@ -319,20 +357,21 @@ main (int argc, char *const *argv, char *const *envp) case 'D': case 'U': + case 's': case 't': - + case '\1': /* Arguments that cannot be handled until later are accumulated. */ - new = (macro_definition *) xmalloc (sizeof (macro_definition)); - new->code = optchar; - new->macro = optarg; - new->next = NULL; + defn = (macro_definition *) xmalloc (sizeof (macro_definition)); + defn->code = optchar; + defn->arg = optarg; + defn->next = NULL; if (head == NULL) - head = new; + head = defn; else - tail->next = new; - tail = new; + tail->next = defn; + tail = defn; break; @@ -412,10 +451,6 @@ main (int argc, char *const *argv, char *const *envp) debugfile = optarg; break; - case 's': - sync_output = 1; - break; - case VERSION_OPTION: printf ("%s\n", PACKAGE_STRING); fputs ("\ @@ -449,33 +484,54 @@ Written by Rene' Seindal.\n\ else builtin_init (); + /* Interactive mode means unbuffered output, and interrupts ignored. */ + + if (interactive) + { + signal (SIGINT, SIG_IGN); + setbuf (stdout, (char *) NULL); + } + /* Handle deferred command line macro definitions. Must come after - initialisation of the symbol table. */ + initialization of the symbol table. */ while (defines != NULL) { macro_definition *next; - char *macro_value; symbol *sym; switch (defines->code) { case 'D': - macro_value = strchr (defines->macro, '='); - if (macro_value) - *macro_value++ = '\0'; - define_user_macro (defines->macro, macro_value, SYMBOL_INSERT); + { + /* defines->arg is read-only, so we need a copy. */ + char *macro_name = xstrdup (defines->arg); + char *macro_value = strchr (macro_name, '='); + if (macro_value) + *macro_value++ = '\0'; + define_user_macro (macro_name, macro_value, SYMBOL_INSERT); + free (macro_name); + } break; case 'U': - lookup_symbol (defines->macro, SYMBOL_DELETE); + lookup_symbol (defines->arg, SYMBOL_DELETE); break; case 't': - sym = lookup_symbol (defines->macro, SYMBOL_INSERT); + sym = lookup_symbol (defines->arg, SYMBOL_INSERT); SYMBOL_TRACED (sym) = TRUE; break; + case 's': + sync_output = 1; + break; + + case '\1': + seen_file = TRUE; + read_stdin |= process_file (defines->arg); + break; + default: M4ERROR ((warning_status, 0, "INTERNAL ERROR: bad code in deferred arguments")); @@ -487,55 +543,14 @@ Written by Rene' Seindal.\n\ defines = next; } - /* Interactive mode means unbuffered output, and interrupts ignored. */ - - if (interactive) - { - signal (SIGINT, SIG_IGN); - setbuf (stdout, (char *) NULL); - } - - /* Handle the various input files. Each file is pushed on the input, + /* Handle remaining input files. Each file is pushed on the input, and the input read. Wrapup text is handled separately later. */ - if (optind == argc) - { - /* No point closing stdin until after wrapped text is - processed. */ - push_file (stdin, "stdin", FALSE); - read_stdin = TRUE; - expand_input (); - } + if (optind == argc && !seen_file) + read_stdin = process_file ("-"); else for (; optind < argc; optind++) - { - if (strcmp (argv[optind], "-") == 0) - { - /* If stdin is a terminal, we want to allow 'm4 - file -' - to read input from stdin twice, like GNU cat. Besides, - there is no point closing stdin before wrapped text, to - minimize bugs in syscmd called from wrapped text. */ - push_file (stdin, "stdin", FALSE); - read_stdin = TRUE; - } - else - { - const char *name; - fp = m4_path_search (argv[optind], &name); - if (fp == NULL) - { - error (0, errno, "%s", argv[optind]); - /* Set the status to EXIT_FAILURE, even though we - continue to process files after a missing file. */ - retcode = EXIT_FAILURE; - continue; - } - push_file (fp, name, TRUE); - free ((char *) name); - } - expand_input (); - } -#undef NEXTARG + read_stdin |= process_file (argv[optind]); /* Now handle wrapup text. */ diff --git a/src/m4.h b/src/m4.h index b6d9080d..e7fc2145 100644 --- a/src/m4.h +++ b/src/m4.h @@ -422,7 +422,7 @@ const builtin *find_builtin_by_name (const char *); void include_init (void); void include_env_init (void); void add_include_directory (const char *); -FILE *m4_path_search (const char *, const char **); +FILE *m4_path_search (const char *, char **); /* File: eval.c --- expression evaluation. */ diff --git a/src/path.c b/src/path.c index 69aa315d..634b1ec6 100644 --- a/src/path.c +++ b/src/path.c @@ -111,7 +111,7 @@ add_include_directory (const char *dir) respect to the current working directory. */ FILE * -m4_path_search (const char *file, const char **result) +m4_path_search (const char *file, char **result) { FILE *fp; includes *incl; -- 2.11.4.GIT