[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-r
From: |
Eric Blake |
Subject: |
[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-59-g1080198 |
Date: |
Fri, 22 Feb 2008 13:32:34 +0000 |
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=10801988a863c045aa0dc06b56575f1cc52bc586
The branch, branch-1_4 has been updated
via 10801988a863c045aa0dc06b56575f1cc52bc586 (commit)
from d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f (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 10801988a863c045aa0dc06b56575f1cc52bc586
Author: Eric Blake <address@hidden>
Date: Thu Nov 15 14:56:36 2007 -0700
Stage 17: pass argv through quoted strings.
* src/input.c (append_quote_token): Allow an argv ref inside
quotes.
(init_argv_token): Populate new fields.
(push_macro): Ensure a macro is actually pushed.
* src/m4.h (struct token_chain): Add has_func member.
(struct token_data): Add wrapper and has_func members.
* src/macro.c (struct macro_arguments): Add flatten and has_func
members.
(expand_argument, collect_arguments, make_argv_ref_token)
(make_argv_ref): Populate new fields.
(arg_equal, arg_len) Handle embedded argv.
(arg_token, arg_mark, arg_type): Use new fields.
(cherry picked from commit 4ecf71f4afd15778cc8f0d10aaf4c344bf2b2b57)
Signed-off-by: Eric Blake <address@hidden>
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 25 +++++++++
src/input.c | 17 ++----
src/m4.h | 7 ++-
src/macro.c | 170 +++++++++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 167 insertions(+), 52 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 6578264..62c4ad1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-02-22 Eric Blake <address@hidden>
+
+ Stage 17: pass argv through quoted strings.
+ Allow the concatenation of $@ references with other text input
+ inside quoted contexts, which requires distinguishing between a
+ wrapper around many arguments vs. a reference serving as part of a
+ single argument. Also optimize based on whether argv contains
+ builtin tokens that might need flattening to the empty string.
+ Memory impact: noticeable improvement, due to O(n^2) to O(n)
+ reduction from total reuse of $@ references.
+ Speed impact: noticeable improvement, due to O(n^2) to O(n)
+ reduction in boxed recursion.
+ * src/input.c (append_quote_token): Allow an argv ref inside
+ quotes.
+ (init_argv_token): Populate new fields.
+ (push_macro): Ensure a macro is actually pushed.
+ * src/m4.h (struct token_chain): Add has_func member.
+ (struct token_data): Add wrapper and has_func members.
+ * src/macro.c (struct macro_arguments): Add flatten and has_func
+ members.
+ (expand_argument, collect_arguments, make_argv_ref_token)
+ (make_argv_ref): Populate new fields.
+ (arg_equal, arg_len) Handle embedded argv.
+ (arg_token, arg_mark, arg_type): Use new fields.
+
2008-02-21 Eric Blake <address@hidden>
Stage 16: cache quotes and improve arg_print.
diff --git a/src/input.c b/src/input.c
index bbd50f4..e2bf0aa 100644
--- a/src/input.c
+++ b/src/input.c
@@ -282,6 +282,7 @@ push_macro (builtin_func *func)
next = NULL;
}
+ assert (func);
i = (input_block *) obstack_alloc (current_input, sizeof *i);
i->type = INPUT_MACRO;
i->file = current_file;
@@ -1023,21 +1024,11 @@ append_quote_token (struct obstack *obs, token_data *td)
return;
}
- /* TODO preserve $@ through a quoted context. */
- if (src_chain->type == CHAIN_ARGV)
- {
- arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
- quote_cache (NULL, src_chain->quote_age,
- src_chain->u.u_a.quotes),
- src_chain->u.u_a.flatten, NULL, NULL, false);
- arg_adjust_refcount (src_chain->u.u_a.argv, false);
- return;
- }
-
if (TOKEN_DATA_TYPE (td) == TOKEN_VOID)
{
TOKEN_DATA_TYPE (td) = TOKEN_COMP;
td->u.u_c.chain = td->u.u_c.end = NULL;
+ td->u.u_c.wrapper = td->u.u_c.has_func = false;
}
assert (TOKEN_DATA_TYPE (td) == TOKEN_COMP);
make_text_link (obs, &td->u.u_c.chain, &td->u.u_c.end);
@@ -1047,6 +1038,8 @@ append_quote_token (struct obstack *obs, token_data *td)
else
td->u.u_c.chain = chain;
td->u.u_c.end = chain;
+ if (chain->type == CHAIN_ARGV && chain->u.u_a.has_func)
+ td->u.u_c.has_func = true;
chain->next = NULL;
}
@@ -1073,6 +1066,8 @@ init_argv_token (struct obstack *obs, token_data *td)
/* Clone the link, since the input will be discarded soon. */
chain = (token_chain *) obstack_copy (obs, src_chain, sizeof *chain);
td->u.u_c.chain = td->u.u_c.end = chain;
+ td->u.u_c.wrapper = true;
+ td->u.u_c.has_func = chain->u.u_a.has_func;
chain->next = NULL;
/* If the next character is not ',' or ')', then unlink the last
diff --git a/src/m4.h b/src/m4.h
index 0c2a8c8..54deb42 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -311,6 +311,7 @@ struct token_chain
bool_bitfield flatten : 1; /* True to treat builtins as text. */
bool_bitfield comma : 1; /* True when `,' is next input. */
bool_bitfield skip_last : 1; /* True if last argument omitted. */
+ bool_bitfield has_func : 1; /* True if argv includes func. */
const string_pair *quotes; /* NULL for $*, quotes for
address@hidden */
}
u_a;
@@ -353,8 +354,10 @@ struct token_data
placeholders. */
struct
{
- token_chain *chain; /* First link of the chain. */
- token_chain *end; /* Last link of the chain. */
+ token_chain *chain; /* First link of the chain. */
+ token_chain *end; /* Last link of the chain. */
+ bool_bitfield wrapper : 1; /* True if this is a $@ ref. */
+ bool_bitfield has_func : 1; /* True if chain includes func. */
}
u_c;
}
diff --git a/src/macro.c b/src/macro.c
index 8b7e303..c0a24c4 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -49,6 +49,10 @@ struct macro_arguments
/* False if all arguments belong to this argv, true if some of them
include references to another. */
bool_bitfield has_ref : 1;
+ /* True to flatten builtins contained in references. */
+ bool_bitfield flatten : 1;
+ /* True if any token contains builtins. */
+ bool_bitfield has_func : 1;
const char *argv0; /* The macro name being expanded. */
size_t argv0_len; /* Length of argv0. */
/* The value of quote_age used when parsing all arguments in this
@@ -388,9 +392,14 @@ expand_argument (struct obstack *obs, token_data *argp,
const char *caller)
}
if (TOKEN_DATA_TYPE (argp) != TOKEN_COMP)
{
- obstack_1grow (obs, '\0');
TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (argp) = (char *) obstack_finish (obs);
+ if (len)
+ {
+ obstack_1grow (obs, '\0');
+ TOKEN_DATA_TEXT (argp) = (char *) obstack_finish (obs);
+ }
+ else
+ TOKEN_DATA_TEXT (argp) = NULL;
TOKEN_DATA_LEN (argp) = len;
TOKEN_DATA_QUOTE_AGE (argp) = age;
}
@@ -428,14 +437,16 @@ expand_argument (struct obstack *obs, token_data *argp,
const char *caller)
warn_builtin_concat (caller, TOKEN_DATA_FUNC (argp));
TOKEN_DATA_TYPE (argp) = TOKEN_COMP;
argp->u.u_c.chain = td.u.u_c.chain;
- argp->u.u_c.end = td.u.u_c.end;
+ argp->u.u_c.wrapper = argp->u.u_c.has_func = false;
}
else
{
assert (argp->u.u_c.end);
argp->u.u_c.end->next = td.u.u_c.chain;
- argp->u.u_c.end = td.u.u_c.end;
}
+ argp->u.u_c.end = td.u.u_c.end;
+ if (td.u.u_c.has_func)
+ argp->u.u_c.has_func = true;
}
break;
@@ -462,6 +473,8 @@ expand_argument (struct obstack *obs, token_data *argp,
const char *caller)
&& td.u.u_c.chain->type == CHAIN_ARGV);
TOKEN_DATA_TYPE (argp) = TOKEN_COMP;
argp->u.u_c.chain = argp->u.u_c.end = td.u.u_c.chain;
+ argp->u.u_c.wrapper = true;
+ argp->u.u_c.has_func = td.u.u_c.has_func;
t = next_token (&td, NULL, NULL, false, caller);
if (argp->u.u_c.chain->u.u_a.skip_last)
assert (t == TOKEN_COMMA);
@@ -501,6 +514,8 @@ collect_arguments (symbol *sym, struct obstack *arguments,
args.inuse = false;
args.wrapper = false;
args.has_ref = false;
+ args.flatten = !groks_macro_args;
+ args.has_func = false;
args.argv0 = SYMBOL_NAME (sym);
args.argv0_len = strlen (args.argv0);
args.quote_age = quote_age ();
@@ -526,23 +541,37 @@ collect_arguments (symbol *sym, struct obstack *arguments,
obstack_ptr_grow (argv_stack, tdp);
args.arraylen++;
args.argc++;
- /* Be conservative - any change in quoting while collecting
- arguments, or any argument that consists of unsafe text,
- will require a rescan if $@ is reused. */
- if (TOKEN_DATA_TYPE (tdp) == TOKEN_TEXT
- && TOKEN_DATA_LEN (tdp) > 0
- && TOKEN_DATA_QUOTE_AGE (tdp) != args.quote_age)
- args.quote_age = 0;
- else if (TOKEN_DATA_TYPE (tdp) == TOKEN_COMP)
+ switch (TOKEN_DATA_TYPE (tdp))
{
+ case TOKEN_TEXT:
+ /* Be conservative - any change in quoting while
+ collecting arguments, or any argument that consists
+ of unsafe text, will require a rescan if $@ is
+ reused. */
+ if (TOKEN_DATA_LEN (tdp) > 0
+ && TOKEN_DATA_QUOTE_AGE (tdp) != args.quote_age)
+ args.quote_age = 0;
+ break;
+ case TOKEN_FUNC:
+ args.has_func = true;
+ break;
+ case TOKEN_COMP:
args.has_ref = true;
- if (tdp->u.u_c.chain->type == CHAIN_ARGV)
+ if (tdp->u.u_c.wrapper)
{
+ assert (tdp->u.u_c.chain->type == CHAIN_ARGV
+ && !tdp->u.u_c.chain->next);
args.argc += (tdp->u.u_c.chain->u.u_a.argv->argc
- tdp->u.u_c.chain->u.u_a.index
- tdp->u.u_c.chain->u.u_a.skip_last - 1);
args.wrapper = true;
}
+ if (tdp->u.u_c.has_func)
+ args.has_func = true;
+ break;
+ default:
+ assert (!"expand_argument");
+ abort ();
}
}
while (more_args);
@@ -551,6 +580,7 @@ collect_arguments (symbol *sym, struct obstack *arguments,
argv->argc = args.argc;
argv->wrapper = args.wrapper;
argv->has_ref = args.has_ref;
+ argv->has_func = args.has_func;
if (args.quote_age != quote_age ())
argv->quote_age = 0;
argv->arraylen = args.arraylen;
@@ -802,12 +832,10 @@ arg_token (macro_arguments *argv, unsigned int index, int
*level)
for (i = 0; i < argv->arraylen; i++)
{
token = argv->array[i];
- if (TOKEN_DATA_TYPE (token) == TOKEN_COMP
- && token->u.u_c.chain->type == CHAIN_ARGV)
+ if (TOKEN_DATA_TYPE (token) == TOKEN_COMP && token->u.u_c.wrapper)
{
token_chain *chain = token->u.u_c.chain;
- /* TODO - for now we support only a single-length $@ chain. */
- assert (!chain->next);
+ assert (!chain->next && chain->type == CHAIN_ARGV);
if (index <= (chain->u.u_a.argv->argc - chain->u.u_a.index
- chain->u.u_a.skip_last))
{
@@ -840,15 +868,13 @@ arg_mark (macro_arguments *argv)
argv->inuse = true;
if (argv->wrapper)
for (i = 0; i < argv->arraylen; i++)
- if (TOKEN_DATA_TYPE (argv->array[i]) == TOKEN_COMP)
+ if (TOKEN_DATA_TYPE (argv->array[i]) == TOKEN_COMP
+ && argv->array[i]->u.u_c.wrapper)
{
chain = argv->array[i]->u.u_c.chain;
- while (chain)
- {
- if (chain->type == CHAIN_ARGV && !chain->u.u_a.argv->inuse)
- arg_mark (chain->u.u_a.argv);
- chain = chain->next;
- }
+ assert (!chain->next && chain->type == CHAIN_ARGV);
+ if (!chain->u.u_a.argv->inuse)
+ arg_mark (chain->u.u_a.argv);
}
}
@@ -867,14 +893,16 @@ arg_type (macro_arguments *argv, unsigned int index)
token_data_type type;
token_data *token;
- if (index == 0 || index >= argv->argc)
+ if (argv->flatten || !argv->has_func || index == 0 || index >= argv->argc)
return TOKEN_TEXT;
token = arg_token (argv, index, NULL);
type = TOKEN_DATA_TYPE (token);
- /* When accessed via the arg_* interface, composite tokens are
- currently sequences of text only. */
- if (type == TOKEN_COMP)
+ if (type == TOKEN_COMP && !token->u.u_c.has_func)
type = TOKEN_TEXT;
+ if (type != TOKEN_TEXT)
+ assert (argv->has_func);
+ /* TODO support TOKEN_COMP meaning concatenation of builtins. */
+ assert (type != TOKEN_COMP);
return type;
}
@@ -943,6 +971,7 @@ arg_equal (macro_arguments *argv, unsigned int indexa,
unsigned int indexb)
token_chain tmpb;
token_chain *ca = &tmpa;
token_chain *cb = &tmpb;
+ struct obstack *obs = arg_scratch ();
/* Quick tests. */
if (ta == &empty_token || tb == &empty_token)
@@ -983,7 +1012,34 @@ arg_equal (macro_arguments *argv, unsigned int indexa,
unsigned int indexb)
/* Compare each link of the chain. */
while (ca && cb)
{
- /* TODO support comparison against $@ refs. */
+ if (ca->type == CHAIN_ARGV)
+ {
+ tmpa.next = ca->next;
+ tmpa.type = CHAIN_STR;
+ /* TODO support $@ with funcs. */
+ assert (!ca->u.u_a.has_func || argv->flatten || ca->u.u_a.flatten);
+ arg_print (obs, ca->u.u_a.argv, ca->u.u_a.index,
+ quote_cache (NULL, ca->quote_age, ca->u.u_a.quotes),
+ argv->flatten || ca->u.u_a.flatten, NULL, NULL, false);
+ tmpa.u.u_s.len = obstack_object_size (obs);
+ tmpa.u.u_s.str = (char *) obstack_finish (obs);
+ ca = &tmpa;
+ continue;
+ }
+ if (cb->type == CHAIN_ARGV)
+ {
+ tmpb.next = cb->next;
+ tmpb.type = CHAIN_STR;
+ /* TODO support $@ with funcs. */
+ assert (!cb->u.u_a.has_func || argv->flatten || cb->u.u_a.flatten);
+ arg_print (obs, cb->u.u_a.argv, cb->u.u_a.index,
+ quote_cache (NULL, cb->quote_age, cb->u.u_a.quotes),
+ argv->flatten || cb->u.u_a.flatten, NULL, NULL, false);
+ tmpb.u.u_s.len = obstack_object_size (obs);
+ tmpb.u.u_s.str = (char *) obstack_finish (obs);
+ cb = &tmpb;
+ continue;
+ }
assert (ca->type == CHAIN_STR && cb->type == CHAIN_STR);
if (ca->u.u_s.len == cb->u.u_s.len)
{
@@ -1056,14 +1112,42 @@ arg_len (macro_arguments *argv, unsigned int index)
assert ((token == &empty_token) == (TOKEN_DATA_LEN (token) == 0));
return TOKEN_DATA_LEN (token);
case TOKEN_COMP:
- /* TODO - concatenate multiple arguments? For now, we assume
- all elements are text. */
chain = token->u.u_c.chain;
len = 0;
while (chain)
{
- assert (chain->type == CHAIN_STR);
- len += chain->u.u_s.len;
+ unsigned int i;
+ unsigned int limit;
+ const string_pair *quotes;
+ switch (chain->type)
+ {
+ case CHAIN_STR:
+ len += chain->u.u_s.len;
+ break;
+ case CHAIN_ARGV:
+ i = chain->u.u_a.index;
+ limit = chain->u.u_a.argv->argc - i - chain->u.u_a.skip_last;
+ quotes = quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes);
+ assert (limit);
+ if (quotes)
+ len += (quotes->len1 + quotes->len2) * limit;
+ len += limit - 1;
+ while (limit--)
+ {
+ /* TODO handle builtin concatenation. */
+ if (TOKEN_DATA_TYPE (arg_token (chain->u.u_a.argv, i,
+ NULL)) == TOKEN_FUNC)
+ assert (argv->flatten);
+ else
+ len += arg_len (chain->u.u_a.argv, i);
+ i++;
+ }
+ break;
+ default:
+ assert (!"arg_len");
+ abort ();
+ }
chain = chain->next;
}
assert (len);
@@ -1202,10 +1286,11 @@ make_argv_ref_token (token_data *token, struct obstack
*obs, int level,
token_chain *chain;
assert (obstack_object_size (obs) == 0);
+ /* TODO support $@ refs when argv array is larger than 1. */
if (argv->wrapper && argv->arraylen == 1)
{
- /* TODO for now we support only a single-length $@ chain. */
- assert (TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP);
+ assert (TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP
+ && argv->array[0]->u.u_c.wrapper);
chain = argv->array[0]->u.u_c.chain;
assert (!chain->next && chain->type == CHAIN_ARGV
&& !chain->u.u_a.skip_last);
@@ -1218,12 +1303,15 @@ make_argv_ref_token (token_data *token, struct obstack
*obs, int level,
chain = (token_chain *) obstack_alloc (obs, sizeof *chain);
TOKEN_DATA_TYPE (token) = TOKEN_COMP;
token->u.u_c.chain = token->u.u_c.end = chain;
+ token->u.u_c.wrapper = true;
+ token->u.u_c.has_func = argv->has_func;
chain->next = NULL;
chain->type = CHAIN_ARGV;
chain->quote_age = argv->quote_age;
chain->u.u_a.argv = argv;
chain->u.u_a.index = index;
chain->u.u_a.flatten = flatten;
+ chain->u.u_a.has_func = argv->has_func;
chain->u.u_a.comma = false;
chain->u.u_a.skip_last = false;
chain->u.u_a.quotes = quote_cache (obs, chain->quote_age, quotes);
@@ -1258,6 +1346,8 @@ make_argv_ref (macro_arguments *argv, const char *argv0,
size_t argv0_len,
new_argv->arraylen = 0;
new_argv->wrapper = false;
new_argv->has_ref = false;
+ new_argv->flatten = false;
+ new_argv->has_func = false;
}
else
{
@@ -1267,6 +1357,8 @@ make_argv_ref (macro_arguments *argv, const char *argv0,
size_t argv0_len,
new_argv->array[0] = token;
new_argv->wrapper = true;
new_argv->has_ref = argv->has_ref;
+ new_argv->flatten = flatten;
+ new_argv->has_func = argv->has_func;
}
new_argv->argc = argv->argc - (index - 1);
new_argv->inuse = false;
@@ -1314,10 +1406,10 @@ push_arg_quote (struct obstack *obs, macro_arguments
*argv, unsigned int index,
obstack_grow (obs, quotes->str2, quotes->len2);
}
-/* Push series of comma-separated arguments from ARGV, which should
- all be text, onto the expansion stack OBS for rescanning. If SKIP,
- then don't push the first argument. If QUOTE, the rescan also
- includes quoting around each arg. */
+/* Push series of comma-separated arguments from ARGV, which can
+ include builtins, onto the expansion stack OBS for rescanning. If
+ SKIP, then don't push the first argument. If QUOTE, the rescan
+ also includes quoting around each arg. */
void
push_args (struct obstack *obs, macro_arguments *argv, bool skip, bool quote)
{
hooks/post-receive
--
GNU M4 source repository
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-59-g1080198,
Eric Blake <=