This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU M4 source repository".
http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=6608fa6d084d320401f049b259adcf6b383eaa43 The branch, master has been updated via 6608fa6d084d320401f049b259adcf6b383eaa43 (commit) via 1761b0d68f12c701abfdcf0a36d955f787849e3c (commit) via 44c6706b4fa8c438df0f1ff44a5da6e2b3f8b294 (commit) from 6b1c5a2cbd84a5eb48fe352b7bc8c0568a020d62 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6608fa6d084d320401f049b259adcf6b383eaa43 Author: Eric Blake <[EMAIL PROTECTED]> Date: Tue Mar 18 14:00:39 2008 -0600 Stage 20b: make m4wrap obey POSIX fifo ordering. * m4/m4module.h (m4_wrap_args): Add prototype. * m4/m4private.h (enum m4__symbol_chain_type): Add M4__CHAIN_LOC. (struct m4__symbol_chain): Add struct u_l. * m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Use new link type. (composite_peek, composite_read, composite_clean): Handle location link. * m4/macro.c (m4_wrap_args): New function. * modules/m4.c (m4wrap): Use it. * doc/m4.texinfo (M4wrap): Sync with branch and POSIX. (Extensions): Document extension of multiple arguments. (Location, Improved m4wrap): Adjust example to match FIFO order. * tests/builtins.at (wrap): Likewise. * NEWS: Document this change. Signed-off-by: Eric Blake <[EMAIL PROTECTED]> commit 1761b0d68f12c701abfdcf0a36d955f787849e3c Author: Eric Blake <[EMAIL PROTECTED]> Date: Mon Mar 17 16:03:57 2008 -0600 Stage 20a: reduce unget's in input engine. * m4/input.c (struct input_funcs): Alter read_func prototype. (next_char, file_read, buildin_read, string_read, composite_read): Add allow_argv parameter. (init_builtin_token, init_argv_symbol): Require all prior input to be consumed. (m4_skip_line, match_input, consume_syntax): Adjust callers. (m4__next_token): Consume first byte without peek. Signed-off-by: Eric Blake <[EMAIL PROTECTED]> commit 44c6706b4fa8c438df0f1ff44a5da6e2b3f8b294 Author: Eric Blake <[EMAIL PROTECTED]> Date: Mon Mar 17 08:16:45 2008 -0600 Update for fresh bootstrap. * ltdl/m4/gnulib-cache.m4: Updated copyright from upstream. Signed-off-by: Eric Blake <[EMAIL PROTECTED]> ----------------------------------------------------------------------- Summary of changes: ChangeLog | 44 +++++++++++- NEWS | 6 +- doc/m4.texinfo | 62 ++++++++++++----- ltdl/m4/gnulib-cache.m4 | 2 +- m4/input.c | 179 ++++++++++++++++++++++++++++------------------- m4/m4module.h | 2 +- m4/m4private.h | 13 +++- m4/macro.c | 68 ++++++++++++++++++ modules/m4.c | 8 +-- tests/builtins.at | 2 +- 10 files changed, 279 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e602e1..9d3c860 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2008-03-18 Eric Blake <[EMAIL PROTECTED]> + + Stage 20b: make m4wrap obey POSIX fifo ordering. + Improve input engine to support location changes within symbol + chains, then convert m4wrap to always build symbol chain. + Memory impact: none. + Speed impact: slight penalty, from more m4wrap bookkeeping. + * m4/m4module.h (m4_wrap_args): Add prototype. + * m4/m4private.h (enum m4__symbol_chain_type): Add M4__CHAIN_LOC. + (struct m4__symbol_chain): Add struct u_l. + * m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Use + new link type. + (composite_peek, composite_read, composite_clean): Handle location + link. + * m4/macro.c (m4_wrap_args): New function. + * modules/m4.c (m4wrap): Use it. + * doc/m4.texinfo (M4wrap): Sync with branch and POSIX. + (Extensions): Document extension of multiple arguments. + (Location, Improved m4wrap): Adjust example to match FIFO order. + * tests/builtins.at (wrap): Likewise. + * NEWS: Document this change. + +2008-03-17 Eric Blake <[EMAIL PROTECTED]> + + Stage 20a: reduce unget's in input engine. + Now that out-of-range input placeholders like CHAR_BUILTIN are + consumed outside of next_char, next_token should always consume + rather than peek at the first character. Fewer peeks results in + less ungetc overhead. + Memory impact: none. + Speed impact: noticeable improvement, from fewer function calls. + * m4/input.c (struct input_funcs): Alter read_func prototype. + (next_char, file_read, buildin_read, string_read, composite_read): + Add allow_argv parameter. + (init_builtin_token, init_argv_symbol): Require all prior input to + be consumed. + (m4_skip_line, match_input, consume_syntax): Adjust callers. + (m4__next_token): Consume first byte without peek. + + Update for fresh bootstrap. + * ltdl/m4/gnulib-cache.m4: Updated copyright from upstream. + 2008-03-15 Eric Blake <[EMAIL PROTECTED]> Document join, in order to fix bug in m4wrap example. @@ -6,7 +48,7 @@ * Makefile.am (EXTRA_DIST): Add new files. * doc/m4.texinfo (Improved m4wrap): New node. (Defn, Location): Enhance tests. - (Shift): Document the composit macro join. + (Shift): Document the composite macro join. (Incompatibilities): Move documentation of LIFO vs. FIFO... (M4wrap): ...here, to match improved example. diff --git a/NEWS b/NEWS index 6e2fa40..eea5287 100644 --- a/NEWS +++ b/NEWS @@ -91,8 +91,6 @@ promoted to 2.0. - FIXME: POSIX recommends using ${10} instead of $10 for the tenth positional argument. We should deprecate $10. - - FIXME: `m4wrap' semantics need an update to FIFO. - ** Removed builtins *** The experimental `epatsubst' and `eregexp' builtins have been removed @@ -216,6 +214,10 @@ promoted to 2.0. ** Fix regression introduced in 1.4.10b where using `builtin' or `indir' to perform nested `shift' calls triggered an assertion failure. +** Fix the `m4wrap' builtin to accumulate wrapped text in FIFO order, as + required by POSIX. The manual mentions a way to restore the LIFO order + present in earlier GNU M4 versions. + ** Enhance the `ifdef', `ifelse', and `shift' builtins, as well as all user macros, to transparently handle builtin tokens generated by `defn'. diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 175d923..6e836f6 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -5204,10 +5204,18 @@ normal input has been exhausted. This feature is normally used to initiate cleanup actions before normal exit, e.g., deleting temporary files. [EMAIL PROTECTED] {Builtin (m4)} m4wrap (@var{string}, @dots{}) To save input text, use the builtin @code{m4wrap}: -which stores @var{string} and the rest of the arguments in a safe place, -to be reread when end of input is reached. + [EMAIL PROTECTED] {Builtin (m4)} m4wrap (@var{string}, @dots{}) +Stores @var{string} in a safe place, to be reread when end of input is +reached. As a @acronym{GNU} extension, additional arguments are +concatenated with a space to the @var{string}. + +Successive invocations of @code{m4wrap} accumulate saved text in +first-in, first-out order, as required by @acronym{POSIX}. + +The expansion of @code{m4wrap} is void. +The macro @code{m4wrap} is recognized only with parameters. @end deffn @example @@ -5225,16 +5233,27 @@ This is the first and last normal input line. The saved input is only reread when the end of normal input is seen, and not if @code{m4exit} is used to exit @code{m4}. [EMAIL PROTECTED] FIXME: this contradicts POSIX, which requires that "If the [EMAIL PROTECTED] m4wrap macro is used multiple times, the arguments specified [EMAIL PROTECTED] shall be processed in the order in which the m4wrap macros were [EMAIL PROTECTED] processed." -It is safe to call @code{m4wrap} from saved text, but then the order in -which the saved text is reread is undefined. If @code{m4wrap} is not used -recursively, the saved pieces of text are reread in the opposite order -in which they were saved (LIFO---last in, first out). +It is safe to call @code{m4wrap} from wrapped text, where all the +recursively wrapped text is deferred until the current wrapped text is +exhausted. As of M4 1.4.11, when @code{m4wrap} is not used recursively, +the saved pieces of text are reread in the same order in which they were +saved (FIFO---first in, first out), as required by @acronym{POSIX}. + [EMAIL PROTECTED] +m4wrap(`1 +') [EMAIL PROTECTED] +m4wrap(`2', `3 +') [EMAIL PROTECTED] +^D [EMAIL PROTECTED] [EMAIL PROTECTED] 3 [EMAIL PROTECTED] example -It is possible to emulate @acronym{POSIX} behavior even +However, earlier versions had reverse ordering (LIFO---last in, first +out), as this behavior is more like the semantics of the C function [EMAIL PROTECTED] It is possible to emulate @acronym{POSIX} behavior even with older versions of @acronym{GNU} M4 by including the file @[EMAIL PROTECTED]/@/examples/@/wrapfifo.m4} from the distribution: @@ -5310,13 +5329,13 @@ Invocations of @code{m4wrap} at the same recursion level are concatenated and rescanned as usual: @example -define(`aa', `AA +define(`ab', `AB ') @result{} -m4wrap(`a')m4wrap(`a') +m4wrap(`a')m4wrap(`b') @result{} ^D [EMAIL PROTECTED] [EMAIL PROTECTED] @end example @noindent @@ -7778,9 +7797,9 @@ m4wrap(`__line__ ') @result{} ^D [EMAIL PROTECTED] @result{}6 @result{}6 [EMAIL PROTECTED] @end example The @[EMAIL PROTECTED] macro behaves like @samp{$0} in shell @@ -8287,6 +8306,15 @@ once, but @acronym{GNU} @code{m4} correctly handles multiple instances of @samp{-} on the command line. @item [EMAIL PROTECTED] requires @code{m4wrap} (@pxref{M4wrap}) to act in FIFO +(first-in, first-out) order, and most other implementations obey this. +However, versions of @acronym{GNU} @code{m4} earlier than 1.4.11 used +LIFO order. Furthermore, @acronym{POSIX} states that only the first +argument to @code{m4wrap} is saved for later evaluation, but [EMAIL PROTECTED] @code{m4} saves and processes all arguments, with output +separated by spaces. + [EMAIL PROTECTED] @acronym{POSIX} states that builtins that require arguments, but are called without arguments, have undefined behavior. Traditional implementations simply behave as though empty strings had been passed. @@ -8943,8 +8971,8 @@ builtin(`m4wrap', ``'define(`bar', ``$0:'-$1-$*-$#-')bar(`a', `b') ') @result{} ^D [EMAIL PROTECTED]:-a-a,b-2- @result{}m4wrap0:---0- [EMAIL PROTECTED]:-a-a,b-2- @end example Additionally, the computation of @code{_m4wrap_level} and creation of diff --git a/ltdl/m4/gnulib-cache.m4 b/ltdl/m4/gnulib-cache.m4 index 882db83..958e7b3 100644 --- a/ltdl/m4/gnulib-cache.m4 +++ b/ltdl/m4/gnulib-cache.m4 @@ -1,4 +1,4 @@ -# Copyright (C) 2004-2007 Free Software Foundation, Inc. +# Copyright (C) 2002-2008 Free Software Foundation, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General diff --git a/m4/input.c b/m4/input.c index 7d27dad..a7f1da9 100644 --- a/m4/input.c +++ b/m4/input.c @@ -93,20 +93,24 @@ between input blocks must update the context accordingly. */ static int file_peek (m4_input_block *, m4 *, bool); -static int file_read (m4_input_block *, m4 *, bool, bool); +static int file_read (m4_input_block *, m4 *, bool, bool, + bool); static void file_unget (m4_input_block *, int); static bool file_clean (m4_input_block *, m4 *, bool); static void file_print (m4_input_block *, m4 *, m4_obstack *); static int builtin_peek (m4_input_block *, m4 *, bool); -static int builtin_read (m4_input_block *, m4 *, bool, bool); +static int builtin_read (m4_input_block *, m4 *, bool, bool, + bool); static void builtin_unget (m4_input_block *, int); static void builtin_print (m4_input_block *, m4 *, m4_obstack *); static int string_peek (m4_input_block *, m4 *, bool); -static int string_read (m4_input_block *, m4 *, bool, bool); +static int string_read (m4_input_block *, m4 *, bool, bool, + bool); static void string_unget (m4_input_block *, int); static void string_print (m4_input_block *, m4 *, m4_obstack *); static int composite_peek (m4_input_block *, m4 *, bool); -static int composite_read (m4_input_block *, m4 *, bool, bool); +static int composite_read (m4_input_block *, m4 *, bool, bool, + bool); static void composite_unget (m4_input_block *, int); static bool composite_clean (m4_input_block *, m4 *, bool); static void composite_print (m4_input_block *, m4 *, m4_obstack *); @@ -115,7 +119,7 @@ static void init_builtin_token (m4 *, m4_symbol_value *); static void append_quote_token (m4 *, m4_obstack *, m4_symbol_value *); static bool match_input (m4 *, const char *, bool); -static int next_char (m4 *, bool, bool); +static int next_char (m4 *, bool, bool, bool); static int peek_char (m4 *, bool); static bool pop_input (m4 *, bool); static void unget_input (int); @@ -138,9 +142,11 @@ struct input_funcs /* Read input, return an unsigned char, CHAR_BUILTIN if it is a builtin, or CHAR_RETRY if none available. If ALLOW_QUOTE, then - CHAR_QUOTE may be returned. If SAFE, then do not alter the - current file or line. */ - int (*read_func) (m4_input_block *, m4 *, bool allow_quote, bool safe); + CHAR_QUOTE may be returned. If ALLOW_ARGV, then CHAR_ARGV may be + returned. If SAFE, then do not alter the current file or + line. */ + int (*read_func) (m4_input_block *, m4 *, bool allow_quote, + bool allow_argv, bool safe); /* Unread a single unsigned character or CHAR_BUILTIN, must be the same character previously read by read_func. */ @@ -198,11 +204,7 @@ static m4_obstack token_stack; /* Obstack for storing input file names. */ static m4_obstack file_names; -/* Wrapup input stack. - - FIXME - m4wrap should be FIFO, which implies a queue, not a stack. - While fixing this, m4wrap should also remember what the current - file and line are for each chunk of wrapped text. */ +/* Wrapup input stack. */ static m4_obstack *wrapup_stack; /* Current stack, from input or wrapup. */ @@ -268,7 +270,7 @@ file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED, static int file_read (m4_input_block *me, m4 *context, bool allow_quote M4_GNUC_UNUSED, - bool safe M4_GNUC_UNUSED) + bool allow_argv M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED) { int ch; @@ -394,7 +396,8 @@ builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED, static int builtin_read (m4_input_block *me, m4 *context M4_GNUC_UNUSED, - bool allow_quote M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED) + bool allow_quote M4_GNUC_UNUSED, bool allow_argv M4_GNUC_UNUSED, + bool safe M4_GNUC_UNUSED) { /* Not consumed here - wait until init_builtin_token. */ return me->u.builtin ? CHAR_BUILTIN : CHAR_RETRY; @@ -453,7 +456,8 @@ string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED, static int string_read (m4_input_block *me, m4 *context M4_GNUC_UNUSED, - bool allow_quote M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED) + bool allow_quote M4_GNUC_UNUSED, bool allow_argv M4_GNUC_UNUSED, + bool safe M4_GNUC_UNUSED) { if (!me->u.u_s.len) return CHAR_RETRY; @@ -747,6 +751,8 @@ composite_peek (m4_input_block *me, m4 *context, bool allow_argv) chain->u.u_a.comma = true; m4_push_string_finish (); return peek_char (context, allow_argv); + case M4__CHAIN_LOC: + break; default: assert (!"composite_peek"); abort (); @@ -757,9 +763,11 @@ composite_peek (m4_input_block *me, m4 *context, bool allow_argv) } static int -composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe) +composite_read (m4_input_block *me, m4 *context, bool allow_quote, + bool allow_argv, bool safe) { m4__symbol_chain *chain = me->u.u_c.chain; + size_t argc; while (chain) { if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX)) @@ -782,7 +790,8 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe) return CHAR_BUILTIN; break; case M4__CHAIN_ARGV: - if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv)) + argc = m4_arg_argc (chain->u.u_a.argv); + if (chain->u.u_a.index == argc) { m4__arg_adjust_refcount (context, chain->u.u_a.argv, false); break; @@ -792,6 +801,11 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe) chain->u.u_a.comma = false; return ','; /* FIXME - support M4_SYNTAX_COMMA. */ } + /* Only return a reference in the quoting is correct and the + reference has more than one argument left. */ + if (allow_argv && chain->quote_age == m4__quote_age (M4SYNTAX) + && chain->u.u_a.quotes && chain->u.u_a.index + 1 < argc) + return CHAR_ARGV; /* Rather than directly parse argv here, we push another input block containing the next unparsed argument from argv. */ @@ -804,7 +818,13 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe) chain->u.u_a.index++; chain->u.u_a.comma = true; m4_push_string_finish (); - return next_char (context, allow_quote, !safe); + return next_char (context, allow_quote, allow_argv, !safe); + case M4__CHAIN_LOC: + me->file = chain->u.u_l.file; + me->line = chain->u.u_l.line; + input_change = true; + me->u.u_c.chain = chain->next; + return next_char (context, allow_quote, allow_argv, !safe); default: assert (!"composite_read"); abort (); @@ -869,6 +889,8 @@ composite_clean (m4_input_block *me, m4 *context, bool cleanup) } m4__arg_adjust_refcount (context, chain->u.u_a.argv, false); break; + case M4__CHAIN_LOC: + return false; default: assert (!"composite_clean"); abort (); @@ -985,14 +1007,36 @@ m4_obstack * m4_push_wrapup_init (m4 *context) { m4_input_block *i; + m4__symbol_chain *chain; - i = (m4_input_block *) obstack_alloc (wrapup_stack, sizeof *i); - i->prev = wsp; - - i->funcs = &string_funcs; - i->file = m4_get_current_file (context); - i->line = m4_get_current_line (context); - wsp = i; + assert (obstack_object_size (wrapup_stack) == 0); + if (wsp) + { + i = wsp; + assert (i->funcs == &composite_funcs && i->u.u_c.end + && i->u.u_c.end->type != M4__CHAIN_LOC); + } + else + { + i = (m4_input_block *) obstack_alloc (wrapup_stack, sizeof *i); + i->prev = wsp; + i->funcs = &composite_funcs; + i->file = m4_get_current_file (context); + i->line = m4_get_current_line (context); + i->u.u_c.chain = i->u.u_c.end = NULL; + wsp = i; + } + chain = (m4__symbol_chain *) obstack_alloc (wrapup_stack, sizeof *chain); + if (i->u.u_c.end) + i->u.u_c.end->next = chain; + else + i->u.u_c.chain = chain; + i->u.u_c.end = chain; + chain->next = NULL; + chain->type = M4__CHAIN_LOC; + chain->quote_age = 0; + chain->u.u_l.file = m4_get_current_file (context); + chain->u.u_l.line = m4_get_current_line (context); return wrapup_stack; } @@ -1000,17 +1044,8 @@ m4_push_wrapup_init (m4 *context) void m4_push_wrapup_finish (void) { - m4_input_block *i = wsp; - if (obstack_object_size (wrapup_stack) == 0) - { - wsp = i->prev; - obstack_free (wrapup_stack, i); - } - else - { - i->u.u_s.len = obstack_object_size (wrapup_stack); - i->u.u_s.str = (char *) obstack_finish (wrapup_stack); - } + m4__make_text_link (wrapup_stack, &wsp->u.u_c.chain, &wsp->u.u_c.end); + assert (wsp->u.u_c.end->type != M4__CHAIN_LOC); } @@ -1085,9 +1120,6 @@ m4_pop_wrapup (m4 *context) static void init_builtin_token (m4 *context, m4_symbol_value *token) { - int ch = next_char (context, false, true); - assert (ch == CHAR_BUILTIN); - if (isp->funcs == &builtin_funcs) { assert (isp->u.builtin); @@ -1159,11 +1191,10 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value) { m4__symbol_chain *src_chain; m4__symbol_chain *chain; - int ch = next_char (context, true, true); + int ch; const m4_string_pair *comments = m4_get_syntax_comments (M4SYNTAX); - assert (ch == CHAR_QUOTE && value->type == M4_SYMBOL_VOID - && isp->funcs == &composite_funcs + assert (value->type == M4_SYMBOL_VOID && isp->funcs == &composite_funcs && isp->u.u_c.chain->type == M4__CHAIN_ARGV && obs && obstack_object_size (obs) == 0); @@ -1201,7 +1232,7 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value) || (!m4_has_syntax (M4SYNTAX, *comments->str1, M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE) && *comments->str1 != *src_chain->u.u_a.quotes->str1)); - ch = peek_char (context, false); + ch = peek_char (context, true); if (!m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)) { isp->u.u_c.chain = src_chain; @@ -1217,10 +1248,12 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value) next_char () is used to read and advance the input to the next character. If ALLOW_QUOTE, and the current input matches the current quote age, return CHAR_QUOTE and leave consumption of data - for append_quote_token. If RETRY, then avoid returning CHAR_RETRY - by popping input. */ + for append_quote_token; otherwise, if ALLOW_ARGV, and the current + input matches an argv reference with the correct quoting, return + CHAR_ARGV and leave consumption of data for init_argv_symbol. If + RETRY, then avoid returning CHAR_RETRY by popping input. */ static int -next_char (m4 *context, bool allow_quote, bool retry) +next_char (m4 *context, bool allow_quote, bool allow_argv, bool retry) { int ch; @@ -1240,7 +1273,8 @@ next_char (m4 *context, bool allow_quote, bool retry) } assert (isp->funcs->read_func); - while (((ch = isp->funcs->read_func (isp, context, allow_quote, !retry)) + while (((ch = isp->funcs->read_func (isp, context, allow_quote, + allow_argv, !retry)) != CHAR_RETRY) || !retry) { @@ -1273,7 +1307,7 @@ peek_char (m4 *context, bool allow_argv) if (ch != CHAR_RETRY) { /* if (IS_IGNORE (ch)) */ -/* return next_char (context, false, true); */ +/* return next_char (context, false, true, true); */ return ch; } @@ -1283,7 +1317,7 @@ peek_char (m4 *context, bool allow_argv) /* The function unget_input () puts back a character on the input stack, using an existing input_block if possible. This is not safe - to call except immediately after next_char(context, allow, false). */ + to call except immediately after next_char(context, aq, aa, false). */ static void unget_input (int ch) { @@ -1301,7 +1335,8 @@ m4_skip_line (m4 *context, const char *name) const char *file = m4_get_current_file (context); int line = m4_get_current_line (context); - while ((ch = next_char (context, false, true)) != CHAR_EOF && ch != '\n') + while ((ch = next_char (context, false, false, true)) != CHAR_EOF + && ch != '\n') ; if (ch == CHAR_EOF) /* current_file changed; use the previous value we cached. */ @@ -1346,14 +1381,14 @@ match_input (m4 *context, const char *s, bool consume) if (s[1] == '\0') { if (consume) - next_char (context, false, true); + next_char (context, false, false, true); return true; /* short match */ } - next_char (context, false, true); + next_char (context, false, false, true); for (n = 1, t = s++; (ch = peek_char (context, false)) == to_uchar (*s++); ) { - next_char (context, false, true); + next_char (context, false, false, true); n++; if (*s == '\0') /* long match */ { @@ -1391,29 +1426,29 @@ static bool consume_syntax (m4 *context, m4_obstack *obs, unsigned int syntax) { int ch; - bool allow_quote = m4__safe_quotes (M4SYNTAX); + bool allow = m4__safe_quotes (M4SYNTAX); assert (syntax); while (1) { /* It is safe to call next_char without first checking peek_char, except at input source boundaries, which we detect by CHAR_RETRY. We exploit the fact that CHAR_EOF, - CHAR_BUILTIN, and CHAR_QUOTE do not satisfy any syntax - categories. */ - while ((ch = next_char (context, allow_quote, false)) != CHAR_RETRY + CHAR_BUILTIN, CHAR_QUOTE, and CHAR_ARGV do not satisfy any + syntax categories. */ + while ((ch = next_char (context, allow, allow, false)) != CHAR_RETRY && m4_has_syntax (M4SYNTAX, ch, syntax)) { assert (ch < CHAR_EOF); obstack_1grow (obs, ch); } - if (ch == CHAR_RETRY || ch == CHAR_QUOTE) + if (ch == CHAR_RETRY || ch == CHAR_QUOTE || ch == CHAR_ARGV) { ch = peek_char (context, false); if (m4_has_syntax (M4SYNTAX, ch, syntax)) { assert (ch < CHAR_EOF); obstack_1grow (obs, ch); - next_char (context, false, true); + next_char (context, false, false, true); continue; } return ch == CHAR_EOF; @@ -1499,15 +1534,14 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, do { obstack_free (&token_stack, token_bottom); - /* Must consume an input character, but not until CHAR_BUILTIN is - handled. */ - ch = peek_char (context, allow_argv && m4__quote_age (M4SYNTAX)); + /* Must consume an input character. */ + ch = next_char (context, false, allow_argv && m4__quote_age (M4SYNTAX), + true); if (ch == CHAR_EOF) /* EOF */ { #ifdef DEBUG_INPUT xfprintf (stderr, "next_token -> EOF\n"); #endif - next_char (context, false, true); return M4_TOKEN_EOF; } @@ -1528,15 +1562,13 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, return M4_TOKEN_ARGV; } - /* Consume character we already peeked at. */ - next_char (context, false, true); file = m4_get_current_file (context); *line = m4_get_current_line (context); if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ESCAPE)) { /* ESCAPED WORD */ obstack_1grow (&token_stack, ch); - if ((ch = next_char (context, false, true)) < CHAR_EOF) + if ((ch = next_char (context, false, false, true)) < CHAR_EOF) { obstack_1grow (&token_stack, ch); if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ALPHA)) @@ -1564,7 +1596,8 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, type = M4_TOKEN_STRING; while (1) { - ch = next_char (context, obs && m4__quote_age (M4SYNTAX), true); + ch = next_char (context, obs && m4__quote_age (M4SYNTAX), false, + true); if (ch == CHAR_EOF) m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller, _("end of file in string")); @@ -1581,7 +1614,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, ch = peek_char (context, false); if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_RQUOTE)) { - ch = next_char (context, false, true); + ch = next_char (context, false, false, true); #ifdef DEBUG_INPUT m4_print_token (context, "next_token", M4_TOKEN_MACDEF, token); @@ -1623,7 +1656,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, assert (!m4__quote_age (M4SYNTAX)); while (1) { - ch = next_char (context, false, true); + ch = next_char (context, false, false, true); if (ch == CHAR_EOF) m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller, _("end of file in string")); @@ -1641,7 +1674,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, if (MATCH (context, ch, context->syntax->quote.str2, false)) { - ch = next_char (context, false, true); + ch = next_char (context, false, false, true); MATCH (context, ch, context->syntax->quote.str2, true); #ifdef DEBUG_INPUT m4_print_token (context, "next_token", M4_TOKEN_MACDEF, @@ -1681,7 +1714,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, obstack_1grow (obs_safe, ch); while (1) { - ch = next_char (context, false, true); + ch = next_char (context, false, false, true); if (ch == CHAR_EOF) m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller, _("end of file in comment")); @@ -1713,7 +1746,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line, context->syntax->comm.len1); while (1) { - ch = next_char (context, false, true); + ch = next_char (context, false, false, true); if (ch == CHAR_EOF) m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller, _("end of file in comment")); diff --git a/m4/m4module.h b/m4/m4module.h index 6cbe185..357baca 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -1,5 +1,4 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -374,6 +373,7 @@ extern void m4_push_arg (m4 *, m4_obstack *, m4_macro_args *, size_t); extern void m4_push_args (m4 *, m4_obstack *, m4_macro_args *, bool, bool); +extern void m4_wrap_args (m4 *, m4_macro_args *); /* --- RUNTIME DEBUGGING --- */ diff --git a/m4/m4private.h b/m4/m4private.h index 5ff7c95..86f18e8 100644 --- a/m4/m4private.h +++ b/m4/m4private.h @@ -1,7 +1,6 @@ /* GNU m4 -- A simple macro processor - - Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2004, 2005, - 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2004, + 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GNU M4. @@ -212,7 +211,8 @@ enum m4__symbol_chain_type { M4__CHAIN_STR, /* Link contains a string, u.u_s is valid. */ M4__CHAIN_FUNC, /* Link contains builtin token, u.builtin is valid. */ - M4__CHAIN_ARGV /* Link contains a $@ reference, u.u_a is valid. */ + M4__CHAIN_ARGV, /* Link contains a $@ reference, u.u_a is valid. */ + M4__CHAIN_LOC /* Link contains m4wrap location, u.u_l is valid. */ }; /* Composite symbols are built of a linked list of chain objects. */ @@ -240,6 +240,11 @@ struct m4__symbol_chain bool_bitfield has_func : 1; /* True if argv includes func. */ const m4_string_pair *quotes; /* NULL for $*, quotes for [EMAIL PROTECTED] */ } u_a; /* M4__CHAIN_ARGV. */ + struct + { + const char *file; /* File where subsequent links originate. */ + int line; /* Line where subsequent links originate. */ + } u_l; /* M4__CHAIN_LOC. */ } u; }; diff --git a/m4/macro.c b/m4/macro.c index d03f551..6d1976d 100644 --- a/m4/macro.c +++ b/m4/macro.c @@ -1670,6 +1670,74 @@ m4_push_args (m4 *context, m4_obstack *obs, m4_macro_args *argv, bool skip, arg_mark (argv); } +/* Push arguments from ARGV onto the wrap stack for later rescanning. + If GNU extensions are disabled, only the first argument is pushed; + otherwise, all arguments are pushed and separated with a space. */ +void +m4_wrap_args (m4 *context, m4_macro_args *argv) +{ + size_t i; + m4_obstack *obs; + m4_symbol_value *value; + m4__symbol_chain *chain; + size_t limit = m4_get_posixly_correct_opt (context) ? 2 : argv->argc; + + if (limit == 2 && m4_arg_empty (argv, 1)) + return; + + obs = m4_push_wrapup_init (context); + for (i = 1; i < limit; i++) + { + if (i != 1) + obstack_1grow (obs, ' '); + value = m4_arg_symbol (argv, i); + switch (value->type) + { + case M4_SYMBOL_TEXT: + obstack_grow (obs, m4_get_symbol_value_text (value), + m4_get_symbol_value_len (value)); + break; + case M4_SYMBOL_FUNC: + /* TODO allow builtins. */ + assert (false); + break; + case M4_SYMBOL_COMP: + chain = value->u.u_c.chain; + while (chain) + { + switch (chain->type) + { + case M4__CHAIN_STR: + obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len); + break; + case M4__CHAIN_FUNC: + /* TODO allow builtins. */ + assert (false); + break; + case M4__CHAIN_ARGV: + m4_arg_print (context, obs, chain->u.u_a.argv, + chain->u.u_a.index, + m4__quote_cache (M4SYNTAX, NULL, + chain->quote_age, + chain->u.u_a.quotes), + chain->u.u_a.flatten, NULL, NULL, false, + false); + break; + default: + assert (!"m4_wrap_args"); + abort (); + } + chain = chain->next; + } + break; + default: + assert (!"m4_wrap_args"); + abort (); + } + } + m4_push_wrapup_finish (); +} + /* Define these last, so that earlier uses can benefit from the macros in m4private.h. */ diff --git a/modules/m4.c b/modules/m4.c index 359839b..02ac090 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -833,13 +833,7 @@ M4BUILTIN_HANDLER (m4exit) version only the first. */ M4BUILTIN_HANDLER (m4wrap) { - obs = m4_push_wrapup_init (context); - if (m4_get_posixly_correct_opt (context)) - obstack_grow (obs, M4ARG (1), M4ARGLEN (1)); - else - /* TODO allow pushing builtins. */ - m4_arg_print (context, obs, argv, 1, NULL, true, " ", NULL, false, false); - m4_push_wrapup_finish (); + m4_wrap_args (context, argv); } /* Enable tracing of all specified macros, or all, if none is specified. diff --git a/tests/builtins.at b/tests/builtins.at index 08c881b..34143a1 100644 --- a/tests/builtins.at +++ b/tests/builtins.at @@ -1227,8 +1227,8 @@ No. 33: The End. AT_CHECK_M4([wrap.m4], 0, [[ No. 33: The End. -Wrapper no. 2 Wrapper no. 1 +Wrapper no. 2 Wrapper no. 3 Wrapper no. 4 ]]) hooks/post-receive -- GNU M4 source repository
