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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> ----------------------------------------------------------------------- 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 <[EMAIL PROTECTED]> + 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 [EMAIL PROTECTED] [EMAIL PROTECTED] 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. + [EMAIL PROTECTED] options: -l6 [EMAIL PROTECTED] +$ @kbd{m4 -d -l 6} +define(`echo', `$@@')debugmode(`+t') [EMAIL PROTECTED] +echo(`1', `long string') [EMAIL PROTECTED]: -1- echo(`1', `long s...') -> ``1',`l...' [EMAIL PROTECTED],long string +indir(`echo', defn(`changequote')) [EMAIL PROTECTED]: -2- defn(`change...') [EMAIL PROTECTED]: -1- indir(`echo', <changequote>) -> ``'' [EMAIL PROTECTED] [EMAIL PROTECTED] 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
