m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU M4 source repository branch, branch-1.6, updated. v1.4.10b-26-


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1.6, updated. v1.4.10b-26-g6b67f52
Date: Tue, 15 Apr 2008 04:28:30 +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=6b67f52903f191b8e0b9c295182a8e6504fb4f96

The branch, branch-1.6 has been updated
       via  6b67f52903f191b8e0b9c295182a8e6504fb4f96 (commit)
      from  fb04a26fa6ac38cbe5517372b1a984af0c851876 (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 6b67f52903f191b8e0b9c295182a8e6504fb4f96
Author: Eric Blake <address@hidden>
Date:   Thu Dec 6 13:33:40 2007 -0700

    Stage 21: $@ concatenates builtins, m4wrap takes builtins.
    
    * src/m4.h (append_macro): New prototype.
    (push_macro, push_wrapup_init, arg_print, func_print): Alter
    prototypes.
    * src/input.c (INPUT_MACRO): Delete, covered by INPUT_CHAIN.
    (INPUT_EOF): New input block type, for efficiency.
    (struct input_block): Remove u.func member.
    (input_eof): New input sentinel.
    (append_macro): New function.
    (push_macro, push_wrapup_init): Add parameter.
    (push_token): Support builtin tokens.
    (init_macro_token): Always use chain for builtin tokens.
    (push_string_init, pop_input, pop_wrapup, input_print)
    (peek_input, next_char, next_char_1, input_init): Adjust callers.
    * src/macro.c (arg_equal, wrap_args): Handle builtin tokens.
    (arg_print): Add parameter.
    (collect_arguments, arg_type, arg_text): Adjust callers.
    * src/builtin.c (m4_m4wrap): Handle builtin tokens.
    (func_print): Add parameter.
    (m4_defn): Allow pushing builtin alongside other text.
    (m4_errprint): Adjust caller.
    * src/debug.c (trace_pre): Likewise.
    * doc/m4.texinfo (Defn, Ifelse, Debug Levels): Update tests to new
    behavior.
    (M4wrap): New test.
    
    (cherry picked from commit 32d4bf4d447e0e252c809897b795b57b3bfd74de)
    
    Signed-off-by: Eric Blake <address@hidden>

-----------------------------------------------------------------------

Summary of changes:
 .cvsignore     |    2 +-
 .gitignore     |    2 +-
 ChangeLog      |   35 ++++++++++
 doc/m4.texinfo |   84 +++++++++++++----------
 src/builtin.c  |   26 ++++---
 src/debug.c    |    2 +-
 src/input.c    |  203 +++++++++++++++++++++++++++-----------------------------
 src/m4.h       |   12 ++-
 src/macro.c    |   86 +++++++++++++-----------
 9 files changed, 253 insertions(+), 199 deletions(-)

diff --git a/.cvsignore b/.cvsignore
index 8fc44d6..493776c 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -17,6 +17,7 @@ configure.lineno
 COPYING
 depcomp
 gendocs.sh
+GNUmakefile
 gnupload
 INSTALL
 install-sh
@@ -30,4 +31,3 @@ stamp-h
 stamp-h1
 stamp-h.in
 tests
-GNUmakefile
diff --git a/.gitignore b/.gitignore
index b581eac..fae2fd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ COPYING
 CVS
 depcomp
 gendocs.sh
+GNUmakefile
 gnupload
 INSTALL
 install-sh
@@ -34,4 +35,3 @@ stamp-h
 stamp-h1
 stamp-h.in
 tests
-GNUmakefile
diff --git a/ChangeLog b/ChangeLog
index 8501d11..a9fc7f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2008-04-14  Eric Blake  <address@hidden>
+
+       Stage 21: $@ concatenates builtins, m4wrap takes builtins.
+       Create a new input block type, which always fails with CHAR_EOF,
+       so that remaining input routines no longer have to check for NULL
+       input block.  Improve arg_print to handle builtin tokens when
+       printing to a known chain, rather than always flattening builtins,
+       allowing m4wrap and $@ references to handle embedded builtins.
+       Memory impact: none.
+       Speed impact: noticeable improvement, from fewer conditionals.
+       * src/m4.h (append_macro): New prototype.
+       (push_macro, push_wrapup_init, arg_print, func_print): Alter
+       prototypes.
+       * src/input.c (INPUT_MACRO): Delete, covered by INPUT_CHAIN.
+       (INPUT_EOF): New input block type, for efficiency.
+       (struct input_block): Remove u.func member.
+       (input_eof): New input sentinel.
+       (append_macro): New function.
+       (push_macro, push_wrapup_init): Add parameter.
+       (push_token): Support builtin tokens.
+       (init_macro_token): Always use chain for builtin tokens.
+       (push_string_init, pop_input, pop_wrapup, input_print)
+       (peek_input, next_char, next_char_1, input_init): Adjust callers.
+       * src/macro.c (arg_equal, wrap_args): Handle builtin tokens.
+       (arg_print): Add parameter.
+       (collect_arguments, arg_type, arg_text): Adjust callers.
+       * src/builtin.c (m4_m4wrap): Handle builtin tokens.
+       (func_print): Add parameter.
+       (m4_defn): Allow pushing builtin alongside other text.
+       (m4_errprint): Adjust caller.
+       * src/debug.c (trace_pre): Likewise.
+       * doc/m4.texinfo (Defn, Ifelse, Debug Levels): Update tests to new
+       behavior.
+       (M4wrap): New test.
+
 2008-04-11  Eric Blake  <address@hidden>
 
        Ensure --program-prefix doesn't regress.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 4a523c6..52fc77b 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -2281,10 +2281,11 @@ bar
 @result{}0
 @end example
 
-Also note that @code{defn} with multiple arguments can only join text
-macros, not builtins.  Likewise, when collecting macro arguments, a
-builtin token is preserved only when it occurs in isolation.  A future
-version of @acronym{GNU} M4 may lift these restrictions.
+Also note that as of M4 1.6, @code{defn} with multiple arguments can
+join text with builtin tokens.  However, when collecting macro
+arguments, a builtin token is preserved only when it occurs in
+isolation.  A future version of @acronym{GNU} M4 may lift this
+restriction.
 
 @example
 $ @kbd{m4 -d}
@@ -2293,13 +2294,12 @@ define(`a', `A')define(`AA', `b')
 traceon(`defn', `define')
 @result{}
 defn(`a', `divnum', `a')
address@hidden:stdin:3: Warning: defn: cannot concatenate builtin `divnum'
address@hidden: -1- defn(`a', `divnum', `a') -> ``A'`A''
address@hidden: -1- defn(`a', `divnum', `a') -> ``A'<divnum>`A''
 @result{}AA
 define(`mydivnum', defn(`divnum', `divnum'))mydivnum
address@hidden:stdin:4: Warning: defn: cannot concatenate builtin `divnum'
address@hidden:stdin:4: Warning: defn: cannot concatenate builtin `divnum'
address@hidden: -2- defn(`divnum', `divnum')
address@hidden: -2- defn(`divnum', `divnum') -> `<divnum><divnum>'
address@hidden:stdin:4: Warning: define: cannot concatenate builtin `divnum'
address@hidden:stdin:4: Warning: define: cannot concatenate builtin `divnum'
 @error{}m4trace: -1- define(`mydivnum', `')
 @result{}
 traceoff(`defn', `define')
@@ -2317,10 +2317,10 @@ define(`mydivnum', `a'defn(`divnum'))mydivnum
 define(`q', ``$@@'')
 @result{}
 define(`foo', q(`a', defn(`divnum')))foo
address@hidden:stdin:10: Warning: define: cannot quote builtin
address@hidden,
address@hidden:stdin:10: Warning: define: cannot concatenate builtins
address@hidden
 ifdef(`foo', `yes', `no')
address@hidden
address@hidden
 @end example
 
 @node Pushdef
@@ -2860,8 +2860,8 @@ ifelse(`-01234567890123456789', `-'e(long)`-', `yes', 
`no')
 @result{}no
 @end example
 
address@hidden It would be nice to pass builtin tokens through m4wrap, as well
address@hidden as allowing concatenation of builtins in ifelse and user macros.
address@hidden It would be nice to allow concatenation of builtins without
address@hidden using $@ handling.
 @example
 define(`e', `$@@')define(`q', ``$@@'')define(`u', `$*')
 @result{}
@@ -2881,33 +2881,25 @@ cmp(`q(defn(`defn'))', `q(`<defn>')')-fixme
 cmp(`q(defn(`defn'))', ``'')-fixme
 @error{}m4:stdin:7: Warning: ifelse: cannot quote builtin
 @result{}no-fixme
-cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', defn(`d'))')-fixme
address@hidden:stdin:8: Warning: ifelse: cannot quote builtin
address@hidden:stdin:8: Warning: ifelse: cannot quote builtin
address@hidden
-cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', `<defn>')')-fixme
address@hidden:stdin:9: Warning: ifelse: cannot quote builtin
address@hidden
-cmp(`q(`1', `2', defn(`defn'))', ```1',`2',<defn>'')-fixme
address@hidden:stdin:10: Warning: ifelse: cannot quote builtin
address@hidden
-cmp(`q(`1', `2', defn(`defn'))', ```1',`2',`''')-fixme
address@hidden:stdin:11: Warning: ifelse: cannot quote builtin
address@hidden
+cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', defn(`d'))')
address@hidden
+cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', `<defn>')')
address@hidden
+cmp(`q(`1', `2', defn(`defn'))', ```1',`2',<defn>'')
address@hidden
+cmp(`q(`1', `2', defn(`defn'))', ```1',`2',`''')
address@hidden
 define(`cat', `$1`'ifelse(`$#', `1', `', `$0(shift($@@))')')
 @result{}
-cat(`define(`foo',', defn(`divnum'), `)foo')-fixme
address@hidden:stdin:13: Warning: ifelse: cannot quote builtin
address@hidden
-cat(e(`define(`bar',', defn(`divnum'), `)bar'))-fixme
address@hidden:stdin:14: Warning: ifelse: cannot quote builtin
address@hidden
-m4wrap(`u('q(`cat(`define(`baz','', defn(`divnum'), ``)baz')')`)-fixme
+cat(`define(`foo',', defn(`divnum'), `)foo')
address@hidden
+cat(e(`define(`bar',', defn(`divnum'), `)bar'))
address@hidden
+m4wrap(`u('q(`cat(`define(`baz','', defn(`divnum'), ``)baz')')`)
 ')
address@hidden:stdin:15: Warning: m4wrap: cannot quote builtin
 @result{}
 ^D
address@hidden
address@hidden
 @end example
 @end ignore
 
@@ -3811,7 +3803,7 @@ echo(`1', `long string')
 @error{}m4trace: -1- echo(`1', `long s...') -> ``1',`l...'
 @result{}1,long string
 indir(`echo', defn(`changequote'))
address@hidden: -2- defn(`change...')
address@hidden: -2- defn(`change...') -> `<changequote>'
 @error{}m4trace: -1- indir(`echo', <changequote>) -> ``<changequote>''
 @result{}
 @end example
@@ -4723,6 +4715,24 @@ m4wrap(`m4wrap(`)')len(abc')
 @error{}m4:stdin:1: len: end of file in argument list
 @end example
 
+As of M4 1.6, @code{m4wrap} transparently handles builtin tokens
+generated by @code{defn} (@pxref{Defn}).  However, for portability, it
+is better to defer the evaluation of @code{defn} along with the rest of
+the wrapped text, as is done for @code{foo} in the example below, rather
+than computing the builtin token up front, as is done for @code{bar}.
+
address@hidden
+m4wrap(`define(`foo', defn(`divnum'))foo
+')
address@hidden
+m4wrap(`define(`bar', ')m4wrap(defn(`divnum'))m4wrap(`)bar
+')
address@hidden
+^D
address@hidden
address@hidden
address@hidden example
+
 @node File Inclusion
 @chapter File inclusion
 
diff --git a/src/builtin.c b/src/builtin.c
index e9856a8..07d2ce0 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -123,7 +123,7 @@ builtin_tab[] =
   { "indir",           true,   true,   true,   m4_indir },
   { "len",             false,  false,  true,   m4_len },
   { "m4exit",          false,  false,  false,  m4_m4exit },
-  { "m4wrap",          false,  false,  true,   m4_m4wrap },
+  { "m4wrap",          false,  true,   true,   m4_m4wrap },
   { "maketemp",                false,  false,  true,   m4_maketemp },
   { "mkstemp",         false,  false,  true,   m4_mkstemp },
   { "patsubst",                true,   false,  true,   m4_patsubst },
@@ -204,19 +204,25 @@ find_builtin_by_name (const char *name)
 
 /*------------------------------------------------------------------.
 | Print a representation of FUNC to OBS.  If FLATTEN, output QUOTES |
-| around an empty string instead.                                   |
+| around an empty string instead; else if CHAIN, append the builtin |
+| to the chain; otherwise print the name of FUNC.                   |
 `------------------------------------------------------------------*/
 void
 func_print (struct obstack *obs, const builtin *func, bool flatten,
-           const string_pair *quotes)
+           token_chain **chain, const string_pair *quotes)
 {
   assert (func);
-  if (flatten && quotes)
+  if (flatten)
     {
-      obstack_grow (obs, quotes->str1, quotes->len1);
-      obstack_grow (obs, quotes->str2, quotes->len2);
+      if (quotes)
+       {
+         obstack_grow (obs, quotes->str1, quotes->len1);
+         obstack_grow (obs, quotes->str2, quotes->len2);
+       }
     }
-  else if (!flatten)
+  else if (chain)
+    append_macro (obs, func->func, NULL, chain);
+  else
     {
       obstack_1grow (obs, '<');
       obstack_grow (obs, func->name, strlen (func->name));
@@ -1022,10 +1028,8 @@ m4_defn (struct obstack *obs, int argc, macro_arguments 
*argv)
            m4_warn (0, me,
                     _("builtin `%s' requested by frozen file not found"),
                     ARG (i));
-         else if (argc != 2)
-           m4_warn (0, me, _("cannot concatenate builtin `%s'"), ARG (i));
          else
-           push_macro (b);
+           push_macro (obs, b);
          break;
 
        default:
@@ -1548,7 +1552,7 @@ m4_errprint (struct obstack *obs, int argc, 
macro_arguments *argv)
 
   if (bad_argc (ARG (0), argc, 1, -1))
     return;
-  arg_print (obs, argv, 1, NULL, true, " ", NULL, false);
+  arg_print (obs, argv, 1, NULL, true, NULL, " ", NULL, false);
   debug_flush_files ();
   len = obstack_object_size (obs);
   /* The close_stdin module makes it safe to skip checking the return
diff --git a/src/debug.c b/src/debug.c
index 46e1306..fde6c49 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -368,7 +368,7 @@ trace_pre (const char *name, int id, macro_arguments *argv)
       trace_format ("(");
       arg_print (&trace, argv, 1,
                 (debug_level & DEBUG_TRACE_QUOTE) ? &curr_quote : NULL,
-                false, ", ", &len, true);
+                false, NULL, ", ", &len, true);
       trace_format (")");
     }
 
diff --git a/src/input.c b/src/input.c
index 86db704..3a913b7 100644
--- a/src/input.c
+++ b/src/input.c
@@ -72,10 +72,10 @@
 /* Type of an input block.  */
 enum input_type
 {
-  INPUT_STRING,                /* String resulting from macro expansion.  */
-  INPUT_FILE,          /* File from command line or include.  */
-  INPUT_MACRO,         /* Builtin resulting from defn.  */
-  INPUT_CHAIN          /* FIFO chain of separate strings and $@ refs.  */
+  INPUT_STRING,        /* String resulting from macro expansion.  */
+  INPUT_FILE,  /* File from command line or include.  */
+  INPUT_CHAIN, /* FIFO chain of separate strings, builtins, and $@ refs.  */
+  INPUT_EOF    /* Placeholder at bottom of input stack.  */
 };
 
 typedef enum input_type input_type;
@@ -103,7 +103,6 @@ struct input_block
          bool_bitfield advance : 1; /* Track previous start_of_input_line.  */
        }
        u_f;    /* INPUT_FILE */
-      builtin_func *func;      /* INPUT_MACRO */
       struct
        {
          token_chain *chain;   /* Current link in chain.  */
@@ -136,15 +135,19 @@ static struct obstack *current_input;
 /* Bottom of token_stack, for obstack_free.  */
 static void *token_bottom;
 
-/* Pointer to top of current_input.  */
+/* Pointer to top of current_input, never NULL.  */
 static input_block *isp;
 
-/* Pointer to top of wrapup_stack.  */
+/* Pointer to top of wrapup_stack, never NULL.  */
 static input_block *wsp;
 
-/* Aux. for handling split push_string ().  */
+/* Auxiliary for handling split push_string (), NULL if not pushing
+   text for rescanning.  */
 static input_block *next;
 
+/* Marker at the end of the input stack.  */
+static input_block input_eof = { NULL, INPUT_EOF, "", 0 };
+
 /* Flag for next_char () to increment current_line.  */
 static bool start_of_input_line;
 
@@ -265,33 +268,50 @@ push_file (FILE *fp, const char *title, bool close)
   isp = i;
 }
 
-/*-----------------------------------------------------------------.
-| push_macro () pushes the builtin macro FUNC on the input stack.  |
-| If next is non-NULL, this push invalidates a call to             |
-| push_string_init (), whose storage is consequently released.     |
-`-----------------------------------------------------------------*/
-
+/*------------------------------------------------------------------.
+| Given an obstack OBS, capture any unfinished text as a link, then |
+| append the builtin FUNC as the next link in the chain that starts |
+| at *START and ends at *END.  START may be NULL if *END is         |
+| non-NULL.                                                         |
+`------------------------------------------------------------------*/
 void
-push_macro (builtin_func *func)
+append_macro (struct obstack *obs, builtin_func *func, token_chain **start,
+             token_chain **end)
 {
-  input_block *i;
-
-  if (next != NULL)
-    {
-      obstack_free (current_input, next);
-      next = NULL;
-    }
+  token_chain *chain;
 
   assert (func);
-  i = (input_block *) obstack_alloc (current_input, sizeof *i);
-  i->type = INPUT_MACRO;
-  i->file = current_file;
-  i->line = current_line;
-  input_change = true;
+  make_text_link (obs, start, end);
+  chain = (token_chain *) obstack_alloc (obs, sizeof *chain);
+  if (*end)
+    (*end)->next = chain;
+  else
+    *start = chain;
+  *end = chain;
+  chain->next = NULL;
+  chain->type = CHAIN_FUNC;
+  chain->quote_age = 0;
+  chain->u.func = func;
+}
 
-  i->u.func = func;
-  i->prev = isp;
-  isp = i;
+/*------------------------------------------------------------------.
+| push_macro () pushes the builtin FUNC onto the obstack OBS, which |
+| is either the input or wrapup stack.                              |
+`------------------------------------------------------------------*/
+
+void
+push_macro (struct obstack *obs, builtin_func *func)
+{
+  input_block *block = (obs == current_input ? next : wsp);
+  assert (block);
+  if (block->type == INPUT_STRING)
+    {
+      block->type = INPUT_CHAIN;
+      block->u.u_c.chain = block->u.u_c.end = NULL;
+    }
+  else
+    assert (block->type == INPUT_CHAIN);
+  append_macro (obs, func, &block->u.u_c.chain, &block->u.u_c.end);
 }
 
 /*--------------------------------------------------------------.
@@ -304,7 +324,7 @@ push_string_init (void)
 {
   /* Free any memory occupied by completely parsed strings.  */
   assert (next == NULL);
-  while (isp && pop_input (false));
+  while (pop_input (false));
 
   /* Reserve the next location on the obstack.  */
   next = (input_block *) obstack_alloc (current_input, sizeof *next);
@@ -361,7 +381,18 @@ push_token (token_data *token, int level, bool inuse)
          return false;
        }
     }
-  else if (TOKEN_DATA_TYPE (token) != TOKEN_FUNC)
+  else if (TOKEN_DATA_TYPE (token) == TOKEN_FUNC)
+    {
+      if (next->type == INPUT_STRING)
+       {
+         next->type = INPUT_CHAIN;
+         next->u.u_c.chain = next->u.u_c.end = NULL;
+       }
+      append_macro (current_input, TOKEN_DATA_FUNC (token), &next->u.u_c.chain,
+                   &next->u.u_c.end);
+      return false;
+    }
+  else
     {
       /* For composite tokens, if argv is already in use, creating
         additional references for long text segments is more
@@ -407,23 +438,15 @@ push_token (token_data *token, int level, bool inuse)
       adjust_refcount (level, true);
       inuse = true;
     }
-  else if (TOKEN_DATA_TYPE (token) == TOKEN_FUNC)
-    {
-      chain = (token_chain *) obstack_alloc (current_input, sizeof *chain);
-      if (next->u.u_c.end)
-       next->u.u_c.end->next = chain;
-      else
-       next->u.u_c.chain = chain;
-      next->u.u_c.end = chain;
-      chain->next = NULL;
-      chain->type = CHAIN_FUNC;
-      chain->quote_age = 0;
-      chain->u.func = TOKEN_DATA_FUNC (token);
-    }
   while (src_chain)
     {
-      /* TODO support func concatenation.  */
-      assert (src_chain->type != CHAIN_FUNC);
+      if (src_chain->type == CHAIN_FUNC)
+       {
+         append_macro (current_input, src_chain->u.func, &next->u.u_c.chain,
+                       &next->u.u_c.end);
+         src_chain = src_chain->next;
+         continue;
+       }
       if (level == -1)
        {
          /* Nothing to copy, since link already lives on obstack.  */
@@ -526,13 +549,13 @@ push_string_finish (void)
 `--------------------------------------------------------------*/
 
 struct obstack *
-push_wrapup_init (void)
+push_wrapup_init (token_chain ***end)
 {
   input_block *i;
   token_chain *chain;
 
   assert (obstack_object_size (wrapup_stack) == 0);
-  if (wsp)
+  if (wsp != &input_eof)
     {
       i = wsp;
       assert (i->type == INPUT_CHAIN && i->u.u_c.end
@@ -559,6 +582,7 @@ push_wrapup_init (void)
   chain->quote_age = 0;
   chain->u.u_l.file = current_file;
   chain->u.u_l.line = current_line;
+  *end = &i->u.u_c.end;
   return wrapup_stack;
 }
 
@@ -596,12 +620,6 @@ pop_input (bool cleanup)
        return false;
       break;
 
-    case INPUT_MACRO:
-      assert (!isp->u.func || !cleanup);
-      if (isp->u.func)
-       return false;
-      break;
-
     case INPUT_CHAIN:
       chain = isp->u.u_c.chain;
       assert (!chain || !cleanup);
@@ -658,6 +676,9 @@ pop_input (bool cleanup)
       output_current_line = -1;
       break;
 
+    case INPUT_EOF:
+      return false;
+
     default:
       assert (!"pop_input");
       abort ();
@@ -684,7 +705,7 @@ pop_wrapup (void)
   obstack_free (current_input, NULL);
   free (current_input);
 
-  if (wsp == NULL)
+  if (wsp == &input_eof)
     {
       /* End of the program.  Free all memory even though we are about
         to exit, since it makes leak detection easier.  */
@@ -703,7 +724,7 @@ pop_wrapup (void)
   obstack_init (wrapup_stack);
 
   isp = wsp;
-  wsp = NULL;
+  wsp = &input_eof;
   input_change = true;
 
   return true;
@@ -730,9 +751,6 @@ input_print (struct obstack *obs, const input_block *input)
       obstack_grow (obs, input->file, strlen (input->file));
       obstack_1grow (obs, '>');
       break;
-    case INPUT_MACRO:
-      func_print (obs, find_builtin_by_addr (input->u.func), false, NULL);
-      break;
     case INPUT_CHAIN:
       chain = input->u.u_c.chain;
       while (chain)
@@ -746,14 +764,14 @@ input_print (struct obstack *obs, const input_block 
*input)
              break;
            case CHAIN_FUNC:
              func_print (obs, find_builtin_by_addr (chain->u.func), false,
-                         NULL);
+                         NULL, NULL);
              break;
            case CHAIN_ARGV:
              assert (!chain->u.u_a.comma);
              if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
                             quote_cache (NULL, chain->quote_age,
                                          chain->u.u_a.quotes),
-                            chain->u.u_a.flatten, NULL, &maxlen, false))
+                            chain->u.u_a.flatten, NULL, NULL, &maxlen, false))
                return;
              break;
            default:
@@ -789,9 +807,7 @@ peek_input (bool allow_argv)
 
   while (1)
     {
-      if (block == NULL)
-       return CHAR_EOF;
-
+      assert (block);
       switch (block->type)
        {
        case INPUT_STRING:
@@ -809,11 +825,6 @@ peek_input (bool allow_argv)
          block->u.u_f.end = true;
          break;
 
-       case INPUT_MACRO:
-         if (block->u.func)
-           return CHAR_MACRO;
-         break;
-
        case INPUT_CHAIN:
          chain = block->u.u_c.chain;
          while (chain)
@@ -863,6 +874,9 @@ peek_input (bool allow_argv)
            }
          break;
 
+       case INPUT_EOF:
+         return CHAR_EOF;
+
        default:
          assert (!"peek_input");
          abort ();
@@ -887,7 +901,7 @@ peek_input (bool allow_argv)
 `-------------------------------------------------------------------*/
 
 #define next_char(AQ, AA)                                              \
-  (isp && isp->type == INPUT_STRING && isp->u.u_s.len && !input_change \
+  (isp->type == INPUT_STRING && isp->u.u_s.len && !input_change                
\
    ? (isp->u.u_s.len--, to_uchar (*isp->u.u_s.str++))                  \
    : next_char_1 (AQ, AA))
 
@@ -899,13 +913,7 @@ next_char_1 (bool allow_quote, bool allow_argv)
 
   while (1)
     {
-      if (isp == NULL)
-       {
-         current_file = "";
-         current_line = 0;
-         return CHAR_EOF;
-       }
-
+      assert (isp);
       if (input_change)
        {
          current_file = isp->file;
@@ -940,11 +948,6 @@ next_char_1 (bool allow_quote, bool allow_argv)
            }
          break;
 
-       case INPUT_MACRO:
-         if (isp->u.func)
-           return CHAR_MACRO;
-         break;
-
        case INPUT_CHAIN:
          chain = isp->u.u_c.chain;
          while (chain)
@@ -1013,6 +1016,9 @@ next_char_1 (bool allow_quote, bool allow_argv)
            }
          break;
 
+       case INPUT_EOF:
+         return CHAR_EOF;
+
        default:
          assert (!"next_char_1");
          abort ();
@@ -1064,28 +1070,15 @@ init_macro_token (token_data *td)
 {
   token_chain *chain;
 
-  if (isp->type == INPUT_MACRO)
+  assert (isp->type == INPUT_CHAIN);
+  chain = isp->u.u_c.chain;
+  assert (!chain->quote_age && chain->type == CHAIN_FUNC && chain->u.func);
+  if (td)
     {
-      assert (isp->u.func);
-      if (td)
-       {
-         TOKEN_DATA_TYPE (td) = TOKEN_FUNC;
-         TOKEN_DATA_FUNC (td) = isp->u.func;
-       }
-      isp->u.func = NULL;
-    }
-  else
-    {
-      assert (isp->type == INPUT_CHAIN);
-      chain = isp->u.u_c.chain;
-      assert (!chain->quote_age && chain->type == CHAIN_FUNC && chain->u.func);
-      if (td)
-       {
-         TOKEN_DATA_TYPE (td) = TOKEN_FUNC;
-         TOKEN_DATA_FUNC (td) = chain->u.func;
-       }
-      chain->u.func = NULL;
+      TOKEN_DATA_TYPE (td) = TOKEN_FUNC;
+      TOKEN_DATA_FUNC (td) = chain->u.func;
     }
+  chain->u.func = NULL;
 }
 
 /*-------------------------------------------------------------------.
@@ -1282,8 +1275,8 @@ input_init (void)
   obstack_init (&token_stack);
   token_bottom = obstack_finish (&token_stack);
 
-  isp = NULL;
-  wsp = NULL;
+  isp = &input_eof;
+  wsp = &input_eof;
   next = NULL;
 
   start_of_input_line = false;
diff --git a/src/m4.h b/src/m4.h
index 54dd9da..3e1fdbb 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -393,11 +393,13 @@ void skip_line (const char *);
 /* push back input */
 void make_text_link (struct obstack *, token_chain **, token_chain **);
 void push_file (FILE *, const char *, bool);
-void push_macro (builtin_func *);
+void append_macro (struct obstack *, builtin_func *, token_chain **,
+                  token_chain **);
+void push_macro (struct obstack *, builtin_func *);
 struct obstack *push_string_init (void);
 bool push_token (token_data *, int, bool);
 const input_block *push_string_finish (void);
-struct obstack *push_wrapup_init (void);
+struct obstack *push_wrapup_init (token_chain ***);
 void push_wrapup_finish (void);
 bool pop_wrapup (void);
 void input_print (struct obstack *, const input_block *);
@@ -509,7 +511,8 @@ 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 *, bool, const char *, size_t *, bool);
+               const string_pair *, bool, token_chain **, const char *,
+               size_t *, bool);
 macro_arguments *make_argv_ref (macro_arguments *, const char *, size_t,
                                bool, bool);
 void push_arg (struct obstack *, macro_arguments *, unsigned int);
@@ -569,7 +572,8 @@ 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 *);
+void func_print (struct obstack *, const builtin *, bool, token_chain **,
+                const string_pair *);
 
 /* File: path.c  --- path search for include files.  */
 
diff --git a/src/macro.c b/src/macro.c
index 6a6a90c..c435644 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -582,8 +582,7 @@ collect_arguments (symbol *sym, struct obstack *arguments,
   argv->wrapper = args.wrapper;
   argv->has_ref = args.has_ref;
   argv->has_func = args.has_func;
-  /* TODO allow funcs without crippling quote age.  */
-  if (args.quote_age != quote_age () || args.has_func)
+  if (args.quote_age != quote_age ())
     argv->quote_age = 0;
   argv->arraylen = args.arraylen;
   return argv;
@@ -910,8 +909,6 @@ arg_type (macro_arguments *argv, unsigned int index)
     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;
 }
 
@@ -936,7 +933,6 @@ arg_text (macro_arguments *argv, unsigned int index)
     case TOKEN_TEXT:
       return TOKEN_DATA_TEXT (token);
     case TOKEN_COMP:
-      /* TODO - concatenate functions.  */
       chain = token->u.u_c.chain;
       obs = arg_scratch ();
       while (chain)
@@ -952,7 +948,7 @@ arg_text (macro_arguments *argv, unsigned int index)
                         quote_cache (NULL, chain->quote_age,
                                      chain->u.u_a.quotes),
                         argv->flatten || chain->u.u_a.flatten, NULL, NULL,
-                        false);
+                        NULL, false);
              break;
            default:
              assert (!"arg_text");
@@ -983,6 +979,7 @@ arg_equal (macro_arguments *argv, unsigned int indexa, 
unsigned int indexb)
   token_chain tmpb;
   token_chain *ca = &tmpa;
   token_chain *cb = &tmpb;
+  token_chain *chain;
   struct obstack *obs = arg_scratch ();
 
   /* Quick tests.  */
@@ -1041,30 +1038,34 @@ arg_equal (macro_arguments *argv, unsigned int indexa, 
unsigned int indexb)
     {
       if (ca->type == CHAIN_ARGV)
        {
-         tmpa.next = ca->next;
+         tmpa.next = NULL;
          tmpa.type = CHAIN_STR;
-         /* TODO support $@ with funcs.  */
-         assert (!ca->u.u_a.has_func || argv->flatten || ca->u.u_a.flatten);
+         tmpa.u.u_s.str = NULL;
+         tmpa.u.u_s.len = 0;
+         chain = &tmpa;
          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;
+                    argv->flatten || ca->u.u_a.flatten, &chain, NULL, NULL,
+                    false);
+         assert (obstack_object_size (obs) == 0 && chain != &tmpa);
+         chain->next = ca->next;
+         ca = tmpa.next;
          continue;
        }
       if (cb->type == CHAIN_ARGV)
        {
-         tmpb.next = cb->next;
+         tmpb.next = NULL;
          tmpb.type = CHAIN_STR;
-         /* TODO support $@ with funcs.  */
-         assert (!cb->u.u_a.has_func || argv->flatten || cb->u.u_a.flatten);
+         tmpb.u.u_s.str = NULL;
+         tmpb.u.u_s.len = 0;
+         chain = &tmpb;
          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;
+                    argv->flatten || cb->u.u_a.flatten, &chain, NULL, NULL,
+                    false);
+         assert (obstack_object_size (obs) == 0 && chain != &tmpb);
+         chain->next = cb->next;
+         cb = tmpb.next;
          continue;
        }
       if (ca->type == CHAIN_FUNC)
@@ -1223,18 +1224,21 @@ 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 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.  */
+   with those quotes.  If FLATTEN, builtins are converted to empty
+   quotes; if CHAINP, *CHAINP is updated with macro tokens; otherwise,
+   builtins are represented by their name.  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.  MAX_LEN and CHAINP may not both be
+   specified.  */
 bool
 arg_print (struct obstack *obs, macro_arguments *argv, unsigned int index,
-          const string_pair *quotes, bool flatten, const char *sep,
-          size_t *max_len, bool quote_each)
+          const string_pair *quotes, bool flatten, token_chain **chainp,
+          const char *sep, size_t *max_len, bool quote_each)
 {
   size_t len = max_len ? *max_len : INT_MAX;
   unsigned int i;
@@ -1245,6 +1249,8 @@ arg_print (struct obstack *obs, macro_arguments *argv, 
unsigned int index,
   size_t sep_len;
   size_t *plen = quote_each ? NULL : &len;
 
+  if (chainp)
+    assert (!max_len && *chainp);
   if (!sep)
     sep = ",";
   sep_len = strlen (sep);
@@ -1287,13 +1293,13 @@ arg_print (struct obstack *obs, macro_arguments *argv, 
unsigned int index,
                  break;
                case CHAIN_FUNC:
                  func_print (obs, find_builtin_by_addr (chain->u.func),
-                             flatten, quotes);
+                             flatten, chainp, quotes);
                  break;
                case CHAIN_ARGV:
                  if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
                                 quote_cache (NULL, chain->quote_age,
                                              chain->u.u_a.quotes),
-                                flatten, NULL, &len, false))
+                                flatten, chainp, NULL, &len, false))
                    done = true;
                  break;
                default:
@@ -1310,7 +1316,7 @@ arg_print (struct obstack *obs, macro_arguments *argv, 
unsigned int index,
          break;
        case TOKEN_FUNC:
          func_print (obs, find_builtin_by_addr (TOKEN_DATA_FUNC (token)),
-                     flatten, quotes);
+                     flatten, chainp, quotes);
          break;
        default:
          assert (!"arg_print");
@@ -1319,6 +1325,8 @@ arg_print (struct obstack *obs, macro_arguments *argv, 
unsigned int index,
     }
   if (max_len)
     *max_len = len;
+  else if (chainp)
+    make_text_link (obs, NULL, chainp);
   return false;
 }
 
@@ -1524,11 +1532,12 @@ wrap_args (macro_arguments *argv)
   struct obstack *obs;
   token_data *token;
   token_chain *chain;
+  token_chain **end;
 
   if ((argv->argc == 2 || no_gnu_extensions) && arg_empty (argv, 1))
     return;
 
-  obs = push_wrapup_init ();
+  obs = push_wrapup_init (&end);
   for (i = 1; i < (no_gnu_extensions ? 2 : argv->argc); i++)
     {
       if (i != 1)
@@ -1540,8 +1549,8 @@ wrap_args (macro_arguments *argv)
          obstack_grow (obs, TOKEN_DATA_TEXT (token), TOKEN_DATA_LEN (token));
          break;
        case TOKEN_FUNC:
-         /* TODO allow builtins through m4wrap.  */
-         assert (false);
+         append_macro (obs, TOKEN_DATA_FUNC (token), NULL, end);
+         break;
        case TOKEN_COMP:
          chain = token->u.u_c.chain;
          while (chain)
@@ -1552,14 +1561,13 @@ wrap_args (macro_arguments *argv)
                  obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
                  break;
                case CHAIN_FUNC:
-                 /* TODO allow builtins through m4wrap.  */
-                 assert (false);
+                 append_macro (obs, chain->u.func, NULL, end);
                  break;
                case CHAIN_ARGV:
                  arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
                             quote_cache (NULL, chain->quote_age,
                                          chain->u.u_a.quotes),
-                            chain->u.u_a.flatten, NULL, NULL, false);
+                            chain->u.u_a.flatten, end, NULL, NULL, false);
                  break;
                default:
                  assert (!"wrap_args");


hooks/post-receive
--
GNU M4 source repository




reply via email to

[Prev in Thread] Current Thread [Next in Thread]