]> Savannah Git Hosting - m4.git/commitdiff

Savannah Git Hosting - m4.git/commitdiff

git git@sv / m4.git / commitdiff
? search:
summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1761b0d)
Stage 20b: make m4wrap obey POSIX fifo ordering.
2008年3月18日 20:00:39 +0000 (14:00 -0600)
2008年3月18日 20:00:39 +0000 (14:00 -0600)
* 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 <ebb9@byu.net>

diff --git a/ChangeLog b/ChangeLog
index 8f5898123f7733817fb27299d830cd4bcb23c884..9d3c8601bcb97e692108ea92fce25dfa1882f3b3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2008年03月18日 Eric Blake <ebb9@byu.net>
+
+ 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 <ebb9@byu.net>
Stage 20a: reduce unget's in input engine.
diff --git a/NEWS b/NEWS
index 6e2fa40c130597766e1f39b522b357e33b42bd84..eea52876f42999c371e80cb5beed1c1710ca8223 100644 (file)
--- 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 175d923bb722eba4f9fbbf32948c473feb4f82fa..6e836f6632c396129cf43535b927b11316c443db 100644 (file)
--- 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.
-@deffn {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.
+
+@deffn {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}.
-@comment FIXME: this contradicts POSIX, which requires that "If the
-@comment m4wrap macro is used multiple times, the arguments specified
-@comment shall be processed in the order in which the m4wrap macros were
-@comment 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}.
+
+@example
+m4wrap(`1
+')
+@result{}
+m4wrap(`2', `3
+')
+@result{}
+^D
+@result{}1
+@result{}2 3
+@end 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
+@code{atexit}. It is possible to emulate @acronym{POSIX} behavior even
with older versions of @acronym{GNU} M4 by including the file
@file{m4-@value{VERSION}/@/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
-@result{}AA
+@result{}AB
@end example
@noindent
@@ -7778,9 +7797,9 @@ m4wrap(`__line__
')
@result{}
^D
-@result{}12
@result{}6
@result{}6
+@result{}12
@end example
The @code{@w{__program__}} macro behaves like @samp{0ドル} in shell
@@ -8286,6 +8305,15 @@ Some traditional implementations only allow reading standard input
once, but @acronym{GNU} @code{m4} correctly handles multiple instances
of @samp{-} on the command line.
+@item
+@acronym{POSIX} 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
+@acronym{GNU} @code{m4} saves and processes all arguments, with output
+separated by spaces.
+
@item
@acronym{POSIX} states that builtins that require arguments, but are
called without arguments, have undefined behavior. Traditional
@@ -8943,8 +8971,8 @@ builtin(`m4wrap', ``'define(`bar', ``0ドル:'-1ドル-$*-$#-')bar(`a', `b')
')
@result{}
^D
-@result{}bar:-a-a,b-2-
@result{}m4wrap0:---0-
+@result{}bar:-a-a,b-2-
@end example
Additionally, the computation of @code{_m4wrap_level} and creation of
diff --git a/m4/input.c b/m4/input.c
index 71b901445b628572604391f743bc6dd03d5ba0cb..a7f1da98fc3d411877f383ce4b99d6d109a0d554 100644 (file)
--- a/m4/input.c
+++ b/m4/input.c
@@ -204,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. */
@@ -755,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 ();
@@ -821,6 +819,12 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote,
chain->u.u_a.comma = true;
m4_push_string_finish ();
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 ();
@@ -885,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 ();
@@ -1001,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;
}
@@ -1016,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);
}
\f
diff --git a/m4/m4module.h b/m4/m4module.h
index 6cbe185c0c4c51c737d75487ab0737b8d0406393..357baca25a068ba9d889d318916cdb1c93979d89 100644 (file)
--- 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 *);
\f
/* --- RUNTIME DEBUGGING --- */
diff --git a/m4/m4private.h b/m4/m4private.h
index 5ff7c950f0c1aa54976e4b6f60630100906018a3..86f18e8e8bbe18b9683a4bf76b410491fe20e650 100644 (file)
--- 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 $@. */
} 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 d03f5519141c5a8a9aeec3b2b81101ee60d79c12..6d1976d6a7f2bb92dc203ccae4db607051cc4318 100644 (file)
--- 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 ();
+}
+
\f
/* 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 359839b9c320c35a844b174af77d26ffffd202e4..02ac090d02dd58d0c43725c8706a841d5390e264 100644 (file)
--- 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);
}
\f
/* Enable tracing of all specified macros, or all, if none is specified.
diff --git a/tests/builtins.at b/tests/builtins.at
index 08c881bea62aaafa405d73b483a45a3519ef71ff..34143a14c514ea22d71e0cb1935938061f3e7114 100644 (file)
--- 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
]])
GNU M4 source repository
RSS Atom

AltStyle によって変換されたページ (->オリジナル) /