[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-58-gd59ecd1 |
Date: |
Thu, 21 Feb 2008 14:08:24 +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=d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f
The branch, branch-1_4 has been updated
via d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f (commit)
from 5ca3ef321b2a9328cab37481ebcbdd80c0789e15 (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 d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f
Author: Eric Blake <address@hidden>
Date: Tue Nov 13 06:55:27 2007 -0700
Stage 16: cache quotes and improve arg_print.
* src/m4.h (push_wrapup_init, push_wrapup_finish, quote_cache)
(func_print): New prototypes.
(arg_print): Adjust prototype.
* src/builtin.h (func_print): New function.
(define_user_macro): Slight cleanup.
(dump_args): Delete, no longer used.
(m4_errprint): Use arg_print.
(m4_m4wrap): Handle embedded NUL.
* src/debug.c (trace_pre): Use arg_print.
* src/input.c (cached_quote): New variable.
(push_wrapup): Split...
(push_wrapup_init, push_wrapup_finish): ...into these.
(input_print): Use arg_print.
(quote_cache): New function.
(pop_input, next_char_1, append_quote_token, set_quote_age):
Adjust users.
* src/macro.c (arg_text, make_argv_ref_token): Adjust users.
(arg_print): Add parameters.
* examples/null.m4: Test for NUL in m4wrap.
* examples/null.out: Update expected output.
* doc/m4.texinfo (Debug Levels): Test --arglength truncation.
(cherry picked from commit 44740d89961c48b712562dfc650dc0cb57898aa0)
Signed-off-by: Eric Blake <address@hidden>
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 28 +++++++++++
doc/m4.texinfo | 26 ++++++++++-
examples/null.m4 | Bin 5764 -> 5747 bytes
examples/null.out | Bin 400 -> 402 bytes
src/builtin.c | 91 +++++++++++++++++-------------------
src/debug.c | 38 ++-------------
src/input.c | 132 ++++++++++++++++++++++++++++++++++++++++------------
src/m4.h | 8 ++-
src/macro.c | 82 +++++++++++++++++++--------------
9 files changed, 254 insertions(+), 151 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0f4e496..6578264 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,33 @@
2008-02-21 Eric Blake <address@hidden>
+ Stage 16: cache quotes and improve arg_print.
+ Cache rather than always copying quotes when pushing $@ refs; in
+ particular, reconstruct single-byte quotes on the fly. Allow NUL
+ through m4wrap. Improve sharing of code that prints arguments.
+ Memory impact: slight improvement, due to cached quotes.
+ Speed impact: slight improvement, due to less copying.
+ * src/m4.h (push_wrapup_init, push_wrapup_finish, quote_cache)
+ (func_print): New prototypes.
+ (arg_print): Adjust prototype.
+ * src/builtin.h (func_print): New function.
+ (define_user_macro): Slight cleanup.
+ (dump_args): Delete, no longer used.
+ (m4_errprint): Use arg_print.
+ (m4_m4wrap): Handle embedded NUL.
+ * src/debug.c (trace_pre): Use arg_print.
+ * src/input.c (cached_quote): New variable.
+ (push_wrapup): Split...
+ (push_wrapup_init, push_wrapup_finish): ...into these.
+ (input_print): Use arg_print.
+ (quote_cache): New function.
+ (pop_input, next_char_1, append_quote_token, set_quote_age):
+ Adjust users.
+ * src/macro.c (arg_text, make_argv_ref_token): Adjust users.
+ (arg_print): Add parameters.
+ * examples/null.m4: Test for NUL in m4wrap.
+ * examples/null.out: Update expected output.
+ * doc/m4.texinfo (Debug Levels): Test --arglength truncation.
+
Fix out-of-bounds read for sanitized macro names, from 2008-02-06.
* src/m4.c (m4_verror_at_line): Properly terminate the string.
Reported by Ralf Wildenhues.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 56445c0..2a549dd 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -3466,7 +3466,8 @@ following:
In trace output, show the actual arguments that were collected before
invoking the macro. This applies to all macro calls if the @samp{t}
flag is used, otherwise only the macros covered by calls of
address@hidden
address@hidden Arguments are subject to length truncation specified by
+the command line option @option{--arglength} (or @option{-l}).
@item c
In trace output, show several trace lines for each macro call. A line
@@ -3477,7 +3478,9 @@ after the call has completed.
@item e
In trace output, show the expansion of each macro call, if it is not
void. This applies to all macro calls if the @samp{t} flag is used,
-otherwise only the macros covered by calls of @code{traceon}.
+otherwise only the macros covered by calls of @code{traceon}. The
+expansion is subject to length truncation specified by the command line
+option @option{--arglength} (or @option{-l}).
@item f
In debug and trace output, include the name of the current input file in
@@ -3557,6 +3560,25 @@ foo
@result{}FOO
@end example
+The following example demonstrates the behavior of length truncation,
+when specified on the command line. Note that each argument and the
+final result are individually truncated. Also, the special tokens for
+builtin functions are not truncated.
+
address@hidden options: -l6
address@hidden
+$ @kbd{m4 -d -l 6}
+define(`echo', `$@@')debugmode(`+t')
address@hidden
+echo(`1', `long string')
address@hidden: -1- echo(`1', `long s...') -> ``1',`l...'
address@hidden,long string
+indir(`echo', defn(`changequote'))
address@hidden: -2- defn(`change...')
address@hidden: -1- indir(`echo', <changequote>) -> ``''
address@hidden
address@hidden example
+
@node Debug Output
@section Saving debugging output
diff --git a/examples/null.m4 b/examples/null.m4
index 2632522..79f4715 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
index c42e03c..aca4b78 100644
Binary files a/examples/null.out and b/examples/null.out differ
diff --git a/src/builtin.c b/src/builtin.c
index d4a0fee..09322ea 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -198,6 +198,28 @@ find_builtin_by_name (const char *name)
return bp;
return bp + 1;
}
+
+/*------------------------------------------------------------------.
+| Print a representation of FUNC to OBS. If FLATTEN, output QUOTES |
+| around an empty string instead. |
+`------------------------------------------------------------------*/
+void
+func_print (struct obstack *obs, const builtin *func, bool flatten,
+ const string_pair *quotes)
+{
+ assert (func);
+ if (flatten && quotes)
+ {
+ obstack_grow (obs, quotes->str1, quotes->len1);
+ obstack_grow (obs, quotes->str2, quotes->len2);
+ }
+ else if (!flatten)
+ {
+ obstack_1grow (obs, '<');
+ obstack_grow (obs, func->name, strlen (func->name));
+ obstack_1grow (obs, '>');
+ }
+}
/*-------------------------------------------------------------------------.
| Install a builtin macro with name NAME, bound to the C function given in |
@@ -398,14 +420,15 @@ free_regex (void)
}
}
-/*-------------------------------------------------------------------------.
-| Define a predefined or user-defined macro, with name NAME, and expansion |
-| TEXT. MODE destinguishes between the "define" and the "pushdef" case. |
-| It is also used from main ().
|
-`-------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------.
+| Define a predefined or user-defined macro, with name NAME of |
+| length NAME_LEN, and expansion TEXT. MODE is SYMBOL_INSERT for |
+| "define" or SYMBOL_PUSHDEF for "pushdef". This function is also |
+| used from main (). |
+`-----------------------------------------------------------------*/
void
-define_user_macro (const char *name, size_t len, const char *text,
+define_user_macro (const char *name, size_t name_len, const char *text,
symbol_lookup mode)
{
symbol *s;
@@ -422,24 +445,23 @@ define_user_macro (const char *name, size_t len, const
char *text,
if (macro_sequence_inuse && text)
{
regoff_t offset = 0;
- len = strlen (defn);
+ struct re_registers *regs = ¯o_sequence_regs;
+ size_t len = strlen (defn);
while (offset < len
&& (offset = re_search (¯o_sequence_buf, defn, len, offset,
- len - offset, ¯o_sequence_regs)) >= 0)
+ len - offset, regs)) >= 0)
{
/* Skip empty matches. */
- if (macro_sequence_regs.start[0] == macro_sequence_regs.end[0])
+ if (regs->start[0] == regs->end[0])
offset++;
else
{
- char tmp;
- offset = macro_sequence_regs.end[0];
- tmp = defn[offset];
- defn[offset] = '\0';
- m4_warn (0, NULL, _("definition of `%s' contains sequence `%s'"),
- name, defn + macro_sequence_regs.start[0]);
- defn[offset] = tmp;
+ offset = regs->end[0];
+ m4_warn (0, NULL,
+ _("definition of `%s' contains sequence `%.*s'"),
+ name, regs->end[0] - regs->start[0],
+ defn + regs->start[0]);
}
}
if (offset == -2)
@@ -599,34 +621,6 @@ shipout_int (struct obstack *obs, int val)
obstack_grow (obs, s, strlen (s));
}
-/*------------------------------------------------------------------.
-| Print arguments from the table ARGV to obstack OBS, starting with |
-| START, separated by SEP, and quoted by the current quotes if |
-| QUOTED is true. |
-`------------------------------------------------------------------*/
-
-static void
-dump_args (struct obstack *obs, int start, macro_arguments *argv,
- const char *sep, bool quoted)
-{
- unsigned int i;
- bool dump_sep = false;
- size_t len = strlen (sep);
- unsigned int argc = arg_argc (argv);
-
- for (i = start; i < argc; i++)
- {
- if (dump_sep)
- obstack_grow (obs, sep, len);
- else
- dump_sep = true;
- if (quoted)
- obstack_grow (obs, curr_quote.str1, curr_quote.len1);
- obstack_grow (obs, ARG (i), ARG_LEN (i));
- if (quoted)
- obstack_grow (obs, curr_quote.str2, curr_quote.len2);
- }
-}
/* The rest of this file is code for builtins and expansion of user
defined macros. All the functions for builtins have a prototype as:
@@ -1518,7 +1512,7 @@ m4_errprint (struct obstack *obs, int argc,
macro_arguments *argv)
if (bad_argc (ARG (0), argc, 1, -1))
return;
- dump_args (obs, 1, argv, " ", false);
+ arg_print (obs, argv, 1, NULL, true, " ", NULL, false);
debug_flush_files ();
len = obstack_object_size (obs);
/* The close_stdin module makes it safe to skip checking the return
@@ -1599,12 +1593,13 @@ m4_m4wrap (struct obstack *obs, int argc,
macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, -1))
return;
+ obs = push_wrapup_init ();
if (no_gnu_extensions)
obstack_grow (obs, ARG (1), ARG_LEN (1));
else
- dump_args (obs, 1, argv, " ", false);
- obstack_1grow (obs, '\0');
- push_wrapup ((char *) obstack_finish (obs));
+ /* TODO - allow builtins, rather than always flattening. */
+ arg_print (obs, argv, 1, NULL, true, " ", NULL, false);
+ push_wrapup_finish ();
}
/* Enable tracing of all specified macros, or all, if none is specified.
diff --git a/src/debug.c b/src/debug.c
index d6b2ddc..737ee52 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -359,44 +359,16 @@ trace_prepre (const char *name, int id)
void
trace_pre (const char *name, int id, macro_arguments *argv)
{
- int i;
- const builtin *bp;
- int argc = arg_argc (argv);
-
trace_header (id);
trace_format ("%s", name);
- if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
+ if (arg_argc (argv) > 1 && (debug_level & DEBUG_TRACE_ARGS))
{
+ int len = max_debug_argument_length;
trace_format ("(");
-
- for (i = 1; i < argc; i++)
- {
- if (i != 1)
- trace_format (", ");
-
- switch (arg_type (argv, i))
- {
- case TOKEN_TEXT:
- trace_format ("%l%S%r", ARG (i));
- break;
-
- case TOKEN_FUNC:
- bp = find_builtin_by_addr (arg_func (argv, i));
- if (bp == NULL)
- {
- assert (!"trace_pre");
- abort ();
- }
- trace_format ("<%s>", bp->name);
- break;
-
- default:
- assert (!"trace_pre");
- abort ();
- }
-
- }
+ arg_print (&trace, argv, 1,
+ (debug_level & DEBUG_TRACE_QUOTE) ? &curr_quote : NULL,
+ false, ", ", &len, true);
trace_format (")");
}
diff --git a/src/input.c b/src/input.c
index 5c3b345..bbd50f4 100644
--- a/src/input.c
+++ b/src/input.c
@@ -42,14 +42,14 @@
loops (e.g. "define(`f',`m4wrap(`f')')f"), without memory leaks.
Pushing new input on the input stack is done by push_file (),
- push_string (), push_wrapup () (for wrapup text), and push_macro ()
- (for macro definitions). Because macro expansion needs direct
- access to the current input obstack (for optimization), push_string
- () is split in two functions, push_string_init (), which returns a
- pointer to the current input stack, and push_string_finish (),
- which returns a pointer to the final text. The input_block *next
- is used to manage the coordination between the different push
- routines.
+ push_string (), push_wrapup_init/push_wrapup_finish () (for wrapup
+ text), and push_macro () (for macro definitions). Because macro
+ expansion needs direct access to the current input obstack (for
+ optimization), push_string () is split in two functions,
+ push_string_init (), which returns a pointer to the current input
+ stack, and push_string_finish (), which returns a pointer to the
+ final text. The input_block *next is used to manage the
+ coordination between the different push routines.
The current file and line number are stored in two global
variables, for use by the error handling functions in m4.c. Macro
@@ -185,6 +185,9 @@ static struct re_registers regs;
context. */
static unsigned int current_quote_age;
+/* Cache a quote pair. See quote_cache. */
+static string_pair *cached_quote;
+
static bool pop_input (bool);
static void set_quote_age (void);
@@ -500,17 +503,14 @@ push_string_finish (void)
return ret;
}
-/*------------------------------------------------------------------.
-| The function push_wrapup () pushes a string on the wrapup stack. |
-| When the normal input stack gets empty, the wrapup stack will |
-| become the input stack, and push_string () and push_file () will |
-| operate on wrapup_stack. Push_wrapup should be done as |
-| push_string (), but this will suffice, as long as arguments to |
-| m4_m4wrap () are moderate in size. |
-`------------------------------------------------------------------*/
+/*--------------------------------------------------------------.
+| The function push_wrapup_init () returns an obstack ready for |
+| direct expansion of wrapup text, and should be followed by |
+| push_wrapup_finish (). |
+`--------------------------------------------------------------*/
-void
-push_wrapup (const char *s)
+struct obstack *
+push_wrapup_init (void)
{
input_block *i;
i = (input_block *) obstack_alloc (wrapup_stack, sizeof *i);
@@ -518,9 +518,28 @@ push_wrapup (const char *s)
i->type = INPUT_STRING;
i->file = current_file;
i->line = current_line;
- i->u.u_s.len = strlen (s);
- i->u.u_s.str = (char *) obstack_copy (wrapup_stack, s, i->u.u_s.len);
wsp = i;
+ return wrapup_stack;
+}
+
+/*---------------------------------------------------------------.
+| After pushing wrapup text, push_wrapup_finish () completes the |
+| bookkeeping. |
+`---------------------------------------------------------------*/
+void
+push_wrapup_finish (void)
+{
+ 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);
+ }
}
@@ -607,6 +626,7 @@ pop_input (bool cleanup)
abort ();
}
obstack_free (current_input, isp);
+ cached_quote = NULL;
next = NULL; /* might be set in push_string_init () */
isp = tmp;
@@ -674,13 +694,7 @@ input_print (struct obstack *obs, const input_block *input)
obstack_1grow (obs, '>');
break;
case INPUT_MACRO:
- {
- const builtin *bp = find_builtin_by_addr (input->u.func);
- assert (bp);
- obstack_1grow (obs, '<');
- obstack_grow (obs, bp->name, strlen (bp->name));
- obstack_1grow (obs, '>');
- }
+ func_print (obs, find_builtin_by_addr (input->u.func), false, NULL);
break;
case INPUT_CHAIN:
chain = input->u.u_c.chain;
@@ -696,7 +710,9 @@ input_print (struct obstack *obs, const input_block *input)
case CHAIN_ARGV:
assert (!chain->u.u_a.comma);
if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
- chain->u.u_a.quotes, &maxlen))
+ quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes),
+ chain->u.u_a.flatten, NULL, &maxlen, false))
return;
break;
default:
@@ -783,7 +799,9 @@ peek_input (bool allow_argv)
argument from argv. */
push_string_init ();
push_arg_quote (current_input, chain->u.u_a.argv,
- chain->u.u_a.index, chain->u.u_a.quotes);
+ chain->u.u_a.index,
+ quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes));
chain->u.u_a.index++;
chain->u.u_a.comma = true;
push_string_finish ();
@@ -911,7 +929,9 @@ next_char_1 (bool allow_quote)
argument from argv. */
push_string_init ();
push_arg_quote (current_input, chain->u.u_a.argv,
- chain->u.u_a.index, chain->u.u_a.quotes);
+ chain->u.u_a.index,
+ quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes));
chain->u.u_a.index++;
chain->u.u_a.comma = true;
push_string_finish ();
@@ -1007,7 +1027,9 @@ append_quote_token (struct obstack *obs, token_data *td)
if (src_chain->type == CHAIN_ARGV)
{
arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
- src_chain->u.u_a.quotes, NULL);
+ 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;
}
@@ -1366,6 +1388,7 @@ set_quote_age (void)
| (*curr_quote.str2 & 0xff));
else
current_quote_age = 0;
+ cached_quote = NULL;
}
/* Return the current quote age. Each non-trivial changequote alters
@@ -1391,6 +1414,53 @@ safe_quotes (void)
{
return current_quote_age != 0;
}
+
+/* Interface for caching frequently used quote pairs, using AGE for
+ optimization. If QUOTES is NULL, don't use quoting. If OBS is
+ non-NULL, AGE should be the current quote age, and QUOTES should be
+ &curr_quote; the return value will be a cached quote pair, where
+ the pointer is valid at least as long as OBS is not reset, but
+ whose contents are only guaranteed until the next changequote or
+ quote_cache. Otherwise, OBS is NULL, AGE should be the same as
+ before, and QUOTES should be a previously returned cache value;
+ used to refresh the contents of the result. */
+const string_pair *
+quote_cache (struct obstack *obs, unsigned int age, const string_pair *quotes)
+{
+ static char lquote[2];
+ static char rquote[2];
+ static string_pair simple = {lquote, 1, rquote, 1};
+
+ /* Implementation - if AGE is non-zero, then the implementation of
+ set_quote_age guarantees that we can recreate the return value on
+ the fly; so we use static storage, and the contents must be used
+ immediately. If AGE is zero, then we must copy QUOTES onto OBS
+ (since changequote will invalidate the original), but we might as
+ well cache that copy (in case the current expansion contains more
+ than one instance of $@). */
+ if (!quotes)
+ return NULL;
+ if (age)
+ {
+ *lquote = (age >> 8) & 0xff;
+ *rquote = age & 0xff;
+ return &simple;
+ }
+ if (!obs)
+ return quotes;
+ assert (next && quotes == &curr_quote);
+ if (!cached_quote)
+ {
+ assert (obs == current_input && obstack_object_size (obs) == 0);
+ cached_quote = (string_pair *) obstack_copy (obs, quotes,
+ sizeof *quotes);
+ cached_quote->str1 = (char *) obstack_copy0 (obs, quotes->str1,
+ quotes->len1);
+ cached_quote->str2 = (char *) obstack_copy0 (obs, quotes->str2,
+ quotes->len2);
+ }
+ return cached_quote;
+}
/*--------------------------------------------------------------------.
diff --git a/src/m4.h b/src/m4.h
index e1da7a7..0c2a8c8 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -386,7 +386,8 @@ void push_macro (builtin_func *);
struct obstack *push_string_init (void);
bool push_token (token_data *, int, bool);
const input_block *push_string_finish (void);
-void push_wrapup (const char *);
+struct obstack *push_wrapup_init (void);
+void push_wrapup_finish (void);
bool pop_wrapup (void);
void input_print (struct obstack *, const input_block *);
@@ -410,6 +411,8 @@ void set_word_regexp (const char *, const char *);
#endif
unsigned int quote_age (void);
bool safe_quotes (void);
+const string_pair *quote_cache (struct obstack *, unsigned int,
+ const string_pair *);
/* File: output.c --- output functions. */
extern int current_diversion;
@@ -494,7 +497,7 @@ size_t arg_len (macro_arguments *, unsigned int);
builtin_func *arg_func (macro_arguments *, unsigned int);
struct obstack *arg_scratch (void);
bool arg_print (struct obstack *, macro_arguments *, unsigned int,
- const string_pair *, int *);
+ const string_pair *, bool, const char *, int *, bool);
macro_arguments *make_argv_ref (macro_arguments *, const char *, size_t,
bool, bool);
void push_arg (struct obstack *, macro_arguments *, unsigned int);
@@ -553,6 +556,7 @@ const char *ntoa (int32_t, int);
const builtin *find_builtin_by_addr (builtin_func *);
const builtin *find_builtin_by_name (const char *);
+void func_print (struct obstack *, const builtin *, bool, const string_pair *);
/* File: path.c --- path search for include files. */
diff --git a/src/macro.c b/src/macro.c
index 8b85cf6..8b7e303 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -911,7 +911,9 @@ arg_text (macro_arguments *argv, unsigned int index)
break;
case CHAIN_ARGV:
arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
- chain->u.u_a.quotes, NULL);
+ quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes),
+ chain->u.u_a.flatten, NULL, NULL, false);
break;
default:
assert (!"arg_text");
@@ -1097,50 +1099,70 @@ arg_scratch (void)
/* Dump a representation of ARGV to the obstack OBS, starting with
argument INDEX. If QUOTES is non-NULL, each argument is displayed
- with those quotes. If MAX_LEN is non-NULL, truncate the output
- after *MAX_LEN bytes are output and return true; otherwise, return
- false, and reduce *MAX_LEN by the number of bytes output. */
+ with those quotes. If FLATTEN, builtins are ignored. Separate
+ arguments with SEP, which defaults to a comma. If MAX_LEN is
+ non-NULL, truncate the output after *MAX_LEN bytes are output and
+ return true; otherwise, return false, and reduce *MAX_LEN by the
+ number of bytes output. If QUOTE_EACH, the truncation length is
+ reset for each argument, quotes do not count against length, and
+ all arguments are printed; otherwise, quotes count against the
+ length and trailing arguments may be discarded. */
bool
arg_print (struct obstack *obs, macro_arguments *argv, unsigned int index,
- const string_pair *quotes, int *max_len)
+ const string_pair *quotes, bool flatten, const char *sep,
+ int *max_len, bool quote_each)
{
int len = max_len ? *max_len : INT_MAX;
unsigned int i;
token_data *token;
token_chain *chain;
- bool comma = false;
-
+ bool use_sep = false;
+ bool done;
+ size_t sep_len;
+ size_t *plen = quote_each ? NULL : &len;
+
+ if (!sep)
+ sep = ",";
+ sep_len = strlen (sep);
for (i = index; i < argv->argc; i++)
{
- if (comma && obstack_print (obs, ",", 1, &len))
+ if (quote_each && max_len)
+ len = *max_len;
+ if (use_sep && obstack_print (obs, sep, sep_len, plen))
return true;
- else
- comma = true;
+ use_sep = true;
token = arg_token (argv, i, NULL);
- if (quotes && obstack_print (obs, quotes->str1, quotes->len1, &len))
- return true;
switch (TOKEN_DATA_TYPE (token))
{
case TOKEN_TEXT:
+ if (quotes && obstack_print (obs, quotes->str1, quotes->len1, plen))
+ return true;
if (obstack_print (obs, TOKEN_DATA_TEXT (token),
- TOKEN_DATA_LEN (token), &len))
+ TOKEN_DATA_LEN (token), &len) && !quote_each)
+ return true;
+ if (quotes && obstack_print (obs, quotes->str2, quotes->len2, plen))
return true;
break;
case TOKEN_COMP:
+ if (quotes && obstack_print (obs, quotes->str1, quotes->len1, plen))
+ return true;
chain = token->u.u_c.chain;
- while (chain)
+ done = false;
+ while (chain && !done)
{
switch (chain->type)
{
case CHAIN_STR:
if (obstack_print (obs, chain->u.u_s.str, chain->u.u_s.len,
&len))
- return true;
+ done = true;
break;
case CHAIN_ARGV:
if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
- chain->u.u_a.quotes, &len))
- return true;
+ quote_cache (NULL, chain->quote_age,
+ chain->u.u_a.quotes),
+ flatten, NULL, &len, false))
+ done = true;
break;
default:
assert (!"arg_print");
@@ -1148,16 +1170,19 @@ arg_print (struct obstack *obs, macro_arguments *argv,
unsigned int index,
}
chain = chain->next;
}
+ if (done && !quote_each)
+ return true;
+ if (quotes && obstack_print (obs, quotes->str2, quotes->len2, plen))
+ return true;
break;
case TOKEN_FUNC:
- /* TODO - support func. */
+ func_print (obs, find_builtin_by_addr (TOKEN_DATA_FUNC (token)),
+ flatten, quotes);
+ break;
default:
assert (!"arg_print");
abort ();
}
- if (quotes && obstack_print (obs, quotes->str2, quotes->len2,
- &len))
- return true;
}
if (max_len)
*max_len = len;
@@ -1201,20 +1226,7 @@ make_argv_ref_token (token_data *token, struct obstack
*obs, int level,
chain->u.u_a.flatten = flatten;
chain->u.u_a.comma = false;
chain->u.u_a.skip_last = false;
- if (quotes)
- {
- /* Clone the quotes into the obstack, since a subsequent
- changequote may take effect before the $@ ref is
- rescanned. */
- /* TODO - optimize when quote_age is nonzero. */
- string_pair *tmp = (string_pair *) obstack_copy (obs, quotes,
- sizeof *quotes);
- tmp->str1 = (char *) obstack_copy0 (obs, quotes->str1, quotes->len1);
- tmp->str2 = (char *) obstack_copy0 (obs, quotes->str2, quotes->len2);
- chain->u.u_a.quotes = tmp;
- }
- else
- chain->u.u_a.quotes = NULL;
+ chain->u.u_a.quotes = quote_cache (obs, chain->quote_age, quotes);
return token;
}
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-58-gd59ecd1,
Eric Blake <=