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_4, updated. branch-cvs-r


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-24-g9db4aab
Date: Fri, 30 Nov 2007 05:06:23 +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=9db4aab8ae052e044e1e5b024421d75e91f45b92

The branch, branch-1_4 has been updated
       via  9db4aab8ae052e044e1e5b024421d75e91f45b92 (commit)
      from  07108982f9559379e136462c08509777ddeaaec0 (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 9db4aab8ae052e044e1e5b024421d75e91f45b92
Author: Eric Blake <address@hidden>
Date:   Fri Oct 19 21:45:38 2007 -0600

    Stage 4: route indir, builtin through ref; make argv opaque.
    
    * src/m4.h (obstack_regrow): Borrow definition from head.
    (struct token_chain): Add flatten and len members.
    (arg_equal, arg_empty, make_argv_ref): New prototypes.
    (struct macro_arguments): Move...
    * src/macro.c (struct macro_arguments): ...here, making it
    opaque.  Add has_ref member.
    (empty_token): New placeholder, for optimizing comparison with
    empty string.
    (collect_arguments): Change signature, and populate new fields.
    (expand_macro): Alter handling of obstacks.
    (arg_token): New helper method.
    (arg_equal, arg_empty, make_argv_ref): New methods.
    (arg_type, arg_text, arg_len, arg_func): Use new methods.
    * src/builtin.c (m4_ifelse, m4_builtin, m4_indir, m4_eval):
    Likewise.
    * src/format.c (format): Likewise.
    
    (cherry picked from commit ab7d5ea40dd30e38cdafdfa69e868390ff6f72ab)
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog     |   18 +++
 src/builtin.c |   88 +++------------
 src/format.c  |    2 +-
 src/m4.h      |   37 +++----
 src/macro.c   |  326 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 5 files changed, 317 insertions(+), 154 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7cd6fc8..0662337 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2007-11-29  Eric Blake  <address@hidden>
 
+       Stage 4: route indir, builtin through ref; make argv opaque.
+       * src/m4.h (obstack_regrow): Borrow definition from head.
+       (struct token_chain): Add flatten and len members.
+       (arg_equal, arg_empty, make_argv_ref): New prototypes.
+       (struct macro_arguments): Move...
+       * src/macro.c (struct macro_arguments): ...here, making it
+       opaque.  Add has_ref member.
+       (empty_token): New placeholder, for optimizing comparison with
+       empty string.
+       (collect_arguments): Change signature, and populate new fields.
+       (expand_macro): Alter handling of obstacks.
+       (arg_token): New helper method.
+       (arg_equal, arg_empty, make_argv_ref): New methods.
+       (arg_type, arg_text, arg_len, arg_func): Use new methods.
+       * src/builtin.c (m4_ifelse, m4_builtin, m4_indir, m4_eval):
+       Likewise.
+       * src/format.c (format): Likewise.
+
        Stage 3: cache length, rather than computing it.
        * src/input.c (next_token): Grab length from obstack rather than
        calling strlen.
diff --git a/src/builtin.c b/src/builtin.c
index e719cdd..b4053f1 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -758,16 +758,10 @@ m4_ifdef (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_ifelse (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *result;
-  const char *me;
+  const char *me = ARG (0);
   int index;
-  size_t len = 0;
-
-  if (argc == 2)
-    return;
 
-  me = ARG (0);
-  if (bad_argc (me, argc, 3, -1))
+  if (argc == 2 || bad_argc (me, argc, 3, -1))
     return;
   else if (argc % 3 == 0)
     /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments.  */
@@ -776,17 +770,13 @@ m4_ifelse (struct obstack *obs, int argc, macro_arguments 
*argv)
   index = 1;
   argc--;
 
-  result = NULL;
-  while (result == NULL)
-
-    if (arg_len (argv, index) == arg_len (argv, index + 1)
-       && strcmp (ARG (index), ARG (index + 1)) == 0)
-      {
-       result = ARG (index + 2);
-       len = arg_len (argv, index + 2);
-      }
-
-    else
+  while (true)
+    {
+      if (arg_equal (argv, index, index + 1))
+       {
+         obstack_grow (obs, ARG (index + 2), arg_len (argv, index + 2));
+         return;
+       }
       switch (argc)
        {
        case 3:
@@ -794,16 +784,14 @@ m4_ifelse (struct obstack *obs, int argc, macro_arguments 
*argv)
 
        case 4:
        case 5:
-         result = ARG (index + 3);
-         len = arg_len (argv, index + 3);
-         break;
+         obstack_grow (obs, ARG (index + 3), arg_len (argv, index + 3));
+         return;
 
        default:
          argc -= 3;
          index += 3;
        }
-
-  obstack_grow (obs, result, len);
+    }
 }
 
 /*---------------------------------------------------------------------.
@@ -944,29 +932,9 @@ m4_builtin (struct obstack *obs, int argc, macro_arguments 
*argv)
     m4_warn (0, me, _("undefined builtin `%s'"), name);
   else
     {
-      int i;
-      /* TODO make use of $@ reference, instead of copying argv.  */
-      /* TODO make accessor in macro.c that performs this
-        construction, so that argv can be opaque type.  */
-      macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array)
-                                          + ((argc - 2)
-                                             * sizeof (token_data *)));
-      new_argv->argc = argc - 1;
-      new_argv->inuse = false;
-      new_argv->argv0 = name;
-      new_argv->argv0_len = arg_len (argv, 1);
-      new_argv->arraylen = argc - 2;
-      memcpy (&new_argv->array[0], &argv->array[1],
-             (argc - 2) * sizeof (token_data *));
-      if (!bp->groks_macro_args)
-       for (i = 2; i < argc; i++)
-         if (arg_type (argv, i) != TOKEN_TEXT)
-           {
-             TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT;
-             TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) "";
-           }
+      macro_arguments *new_argv = make_argv_ref (argv, name, arg_len (argv, 1),
+                                                true, !bp->groks_macro_args);
       bp->func (obs, argc - 1, new_argv);
-      free (new_argv);
     }
 }
 
@@ -998,29 +966,9 @@ m4_indir (struct obstack *obs, int argc, macro_arguments 
*argv)
     m4_warn (0, me, _("undefined macro `%s'"), name);
   else
     {
-      int i;
-      /* TODO make use of $@ reference, instead of copying argv.  */
-      /* TODO make accessor in macro.c that performs this
-        construction, so that argv can be opaque type.  */
-      macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array)
-                                          + ((argc - 2)
-                                             * sizeof (token_data *)));
-      new_argv->argc = argc - 1;
-      new_argv->inuse = false;
-      new_argv->argv0 = name;
-      new_argv->argv0_len = arg_len (argv, 1);
-      new_argv->arraylen = argc - 2;
-      memcpy (&new_argv->array[0], &argv->array[1],
-             (argc - 2) * sizeof (token_data *));
-      if (!SYMBOL_MACRO_ARGS (s))
-       for (i = 2; i < argc; i++)
-         if (arg_type (argv, i) != TOKEN_TEXT)
-           {
-             TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT;
-             TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) "";
-           }
+      macro_arguments *new_argv = make_argv_ref (argv, name, arg_len (argv, 1),
+                                                true, !SYMBOL_MACRO_ARGS (s));
       call_macro (s, argc - 1, new_argv, obs);
-      free (new_argv);
     }
 }
 
@@ -1191,7 +1139,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments 
*argv)
   if (bad_argc (me, argc, 1, 3))
     return;
 
-  if (*ARG (2) && !numeric_arg (me, ARG (2), &radix))
+  if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), &radix))
     return;
 
   if (radix < 1 || radix > 36)
@@ -1208,7 +1156,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments 
*argv)
       return;
     }
 
-  if (!*ARG (1))
+  if (arg_empty (argv, 1))
     m4_warn (0, me, _("empty string treated as 0"));
   else if (evaluate (me, ARG (1), &value))
     return;
diff --git a/src/format.c b/src/format.c
index 7fc8fb1..20b3e28 100644
--- a/src/format.c
+++ b/src/format.c
@@ -51,7 +51,7 @@
 void
 format (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = argv->argv0;
+  const char *me = arg_text (argv, 0);
   const char *f;                       /* format control string */
   const char *fmt;                     /* position within f */
   char fstart[] = "%'+- 0#*.*hhd";     /* current format spec */
diff --git a/src/m4.h b/src/m4.h
index 3a6acc3..ac81998 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -87,7 +87,15 @@ typedef struct string STRING;
 #define obstack_chunk_alloc    xmalloc
 #define obstack_chunk_free     free
 
-/* Those must come first.  */
+/* glibc's obstack left out the ability to suspend and resume growth
+   of an object on the stack.  Reopen OBJECT (previously returned by
+   obstack_alloc or obstack_finish) with SIZE for additional growth,
+   freeing all objects that occur later in the stack.  */
+#define obstack_regrow(OBS, OBJECT, SIZE)                \
+  (obstack_free (OBS, (char *) (OBJECT) + (SIZE)),       \
+   (OBS)->object_base = (char *) (OBJECT))
+
+/* These must come first.  */
 typedef struct token_data token_data;
 typedef struct macro_arguments macro_arguments;
 typedef void builtin_func (struct obstack *, int, macro_arguments *);
@@ -272,8 +280,10 @@ struct token_chain
 {
   token_chain *next;   /* Pointer to next link of chain.  */
   char *str;           /* NUL-terminated string if text, else NULL.  */
+  size_t len;          /* Length of str, else 0.  */
   macro_arguments *argv;/* Reference to earlier address@hidden  */
   unsigned int index;  /* Argument index within argv.  */
+  bool flatten;                /* True to treat builtins as text.  */
 };
 
 /* The content of a token or macro argument.  */
@@ -303,27 +313,6 @@ struct token_data
   u;
 };
 
-/* TODO - make this struct opaque, and move definition to macro.c.  */
-/* Opaque structure describing all arguments to a macro, including the
-   macro name at index 0.  */
-struct macro_arguments
-{
-  /* Number of arguments owned by this object, may be larger than
-     arraylen since the array can refer to multiple arguments via a
-     single $@ reference.  */
-  unsigned int argc;
-  /* False unless the macro expansion refers to $@, determines whether
-     this object can be freed at end of macro expansion or must wait
-     until next byte read from file.  */
-  bool inuse;
-  const char *argv0; /* The macro name being expanded.  */
-  size_t argv0_len; /* Length of argv0.  */
-  size_t arraylen; /* True length of allocated elements in array.  */
-  /* Used as a variable-length array, storing information about each
-     argument.  */
-  token_data *array[FLEXIBLE_ARRAY_MEMBER];
-};
-
 #define TOKEN_DATA_TYPE(Td)            ((Td)->type)
 #define TOKEN_DATA_LEN(Td)             ((Td)->u.u_t.len)
 #define TOKEN_DATA_TEXT(Td)            ((Td)->u.u_t.text)
@@ -442,8 +431,12 @@ void call_macro (symbol *, int, macro_arguments *, struct 
obstack *);
 unsigned int arg_argc (macro_arguments *);
 token_data_type arg_type (macro_arguments *, unsigned int);
 const char *arg_text (macro_arguments *, unsigned int);
+bool arg_equal (macro_arguments *, unsigned int, unsigned int);
+bool arg_empty (macro_arguments *, unsigned int);
 size_t arg_len (macro_arguments *, unsigned int);
 builtin_func *arg_func (macro_arguments *, unsigned int);
+macro_arguments *make_argv_ref (macro_arguments *, const char *, size_t,
+                               bool, bool);
 
 
 /* File: builtin.c  --- builtins.  */
diff --git a/src/macro.c b/src/macro.c
index 320727d..e257485 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -24,6 +24,29 @@
 
 #include "m4.h"
 
+/* Opaque structure describing all arguments to a macro, including the
+   macro name at index 0.  */
+struct macro_arguments
+{
+  /* Number of arguments owned by this object, may be larger than
+     arraylen since the array can refer to multiple arguments via a
+     single $@ reference.  */
+  unsigned int argc;
+  /* False unless the macro expansion refers to $@, determines whether
+     this object can be freed at end of macro expansion or must wait
+     until next byte read from file.  */
+  bool_bitfield inuse : 1;
+  /* False if all arguments are just text or func, true if this argv
+     refers to another one.  */
+  bool_bitfield has_ref : 1;
+  const char *argv0; /* The macro name being expanded.  */
+  size_t argv0_len; /* Length of argv0.  */
+  size_t arraylen; /* True length of allocated elements in array.  */
+  /* Used as a variable-length array, storing information about each
+     argument.  */
+  token_data *array[FLEXIBLE_ARRAY_MEMBER];
+};
+
 static void expand_macro (symbol *);
 static void expand_token (struct obstack *, token_type, token_data *, int);
 
@@ -35,24 +58,24 @@ static int macro_call_id = 0;
 
 /* The shared stack of collected arguments for macro calls; as each
    argument is collected, it is finished and its location stored in
-   argv_stack.  Normally, this stack can be used simultaneously by
-   multiple macro calls; the exception is when an outer macro has
-   generated some text, then calls a nested macro, in which case the
-   nested macro must use a local stack to leave the unfinished text
-   alone.  Too bad obstack.h does not provide an easy way to reopen a
-   finished object for further growth, but in practice this does not
-   hurt us too much.  */
+   argv_stack.  This stack can be used simultaneously by multiple
+   macro calls, using obstack_regrow to handle partial objects
+   embedded in the stack.  */
 static struct obstack argc_stack;
 
 /* The shared stack of pointers to collected arguments for macro
-   calls.  This object is never finished; we exploit the fact that
-   obstack_blank is documented to take a negative size to reduce the
-   size again.  */
+   calls.  This stack can be used simultaneously by multiple macro
+   calls, using obstack_regrow to handle partial objects embedded in
+   the stack.  */
 static struct obstack argv_stack;
 
-/*----------------------------------------------------------------------.
-| This function read all input, and expands each token, one at a time.  |
-`----------------------------------------------------------------------*/
+/* The empty string token.  */
+static token_data empty_token;
+
+/*----------------------------------------------------------------.
+| This function reads all input, and expands each token, one at a |
+| time.                                                           |
+`----------------------------------------------------------------*/
 
 void
 expand_input (void)
@@ -64,6 +87,13 @@ expand_input (void)
   obstack_init (&argc_stack);
   obstack_init (&argv_stack);
 
+  TOKEN_DATA_TYPE (&empty_token) = TOKEN_TEXT;
+  TOKEN_DATA_TEXT (&empty_token) = "";
+  TOKEN_DATA_LEN (&empty_token) = 0;
+#ifdef ENABLE_CHANGEWORD
+  TOKEN_DATA_ORIG_TEXT (&empty_token) = "";
+#endif
+
   while ((t = next_token (&td, &line, NULL)) != TOKEN_EOF)
     expand_token ((struct obstack *) NULL, t, &td, line);
 
@@ -237,12 +267,11 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
 /*-------------------------------------------------------------------------.
 | Collect all the arguments to a call of the macro SYM.  The arguments are |
 | stored on the obstack ARGUMENTS and a table of pointers to the arguments |
-| on the obstack ARGPTR.                                                  |
+| on the obstack argv_stack.                                              |
 `-------------------------------------------------------------------------*/
 
 static macro_arguments *
-collect_arguments (symbol *sym, struct obstack *argptr, unsigned int argv_base,
-                  struct obstack *arguments)
+collect_arguments (symbol *sym, struct obstack *arguments)
 {
   token_data td;
   token_data *tdp;
@@ -253,10 +282,11 @@ collect_arguments (symbol *sym, struct obstack *argptr, 
unsigned int argv_base,
 
   args.argc = 1;
   args.inuse = false;
+  args.has_ref = false;
   args.argv0 = SYMBOL_NAME (sym);
   args.argv0_len = strlen (args.argv0);
   args.arraylen = 0;
-  obstack_grow (argptr, &args, offsetof (macro_arguments, array));
+  obstack_grow (&argv_stack, &args, offsetof (macro_arguments, array));
 
   if (peek_token () == TOKEN_OPEN)
     {
@@ -265,20 +295,18 @@ collect_arguments (symbol *sym, struct obstack *argptr, 
unsigned int argv_base,
        {
          more_args = expand_argument (arguments, &td, SYMBOL_NAME (sym));
 
-         if (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC)
-           {
-             TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
-             TOKEN_DATA_TEXT (&td) = (char *) "";
-             TOKEN_DATA_LEN (&td) = 0;
-           }
-         tdp = (token_data *) obstack_copy (arguments, &td, sizeof td);
-         obstack_ptr_grow (argptr, tdp);
+         if ((TOKEN_DATA_TYPE (&td) == TOKEN_TEXT && !TOKEN_DATA_LEN (&td))
+             || (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC))
+           tdp = &empty_token;
+         else
+           tdp = (token_data *) obstack_copy (arguments, &td, sizeof td);
+         obstack_ptr_grow (&argv_stack, tdp);
          args.arraylen++;
          args.argc++;
        }
       while (more_args);
     }
-  argv = (macro_arguments *) ((char *) obstack_base (argptr) + argv_base);
+  argv = (macro_arguments *) obstack_finish (&argv_stack);
   argv->argc = args.argc;
   argv->arraylen = args.arraylen;
   return argv;
@@ -327,11 +355,11 @@ call_macro (symbol *sym, int argc, macro_arguments *argv,
 static void
 expand_macro (symbol *sym)
 {
-  struct obstack arguments;    /* Alternate obstack if argc_stack is busy.  */
-  unsigned int argv_base;      /* Size of argv_stack on entry.  */
-  void *argc_start;            /* Start of argc_stack, else NULL if unsafe.  */
+  void *argc_base = NULL;      /* Base of argc_stack on entry.  */
+  void *argv_base = NULL;      /* Base of argv_stack on entry.  */
+  unsigned int argc_size;      /* Size of argc_stack on entry.  */
+  unsigned int argv_size;      /* Size of argv_stack on entry.  */
   macro_arguments *argv;
-  int argc;
   struct obstack *expansion;
   const char *expanded;
   bool traced;
@@ -360,24 +388,16 @@ expand_macro (symbol *sym)
 
   traced = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
 
-  argv_base = obstack_object_size (&argv_stack);
-  if (obstack_object_size (&argc_stack) > 0)
-    {
-      /* We cannot use argc_stack if this is a nested invocation, and an
-        outer invocation has an unfinished argument being
-        collected.  */
-      obstack_init (&arguments);
-      argc_start = NULL;
-    }
-  else
-    argc_start = obstack_finish (&argc_stack);
+  argc_size = obstack_object_size (&argc_stack);
+  argv_size = obstack_object_size (&argv_stack);
+  argc_base = obstack_finish (&argc_stack);
+  if (0 < argv_size)
+    argv_base = obstack_finish (&argv_stack);
 
   if (traced && (debug_level & DEBUG_TRACE_CALL))
     trace_prepre (SYMBOL_NAME (sym), my_call_id);
 
-  argv = collect_arguments (sym, &argv_stack, argv_base,
-                           argc_start ? &argc_stack : &arguments);
-  argc = argv->argc;
+  argv = collect_arguments (sym, &argc_stack);
 
   loc_close_file = current_file;
   loc_close_line = current_line;
@@ -385,14 +405,14 @@ expand_macro (symbol *sym)
   current_line = loc_open_line;
 
   if (traced)
-    trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv);
+    trace_pre (SYMBOL_NAME (sym), my_call_id, argv->argc, argv);
 
   expansion = push_string_init ();
-  call_macro (sym, argc, argv, expansion);
+  call_macro (sym, argv->argc, argv, expansion);
   expanded = push_string_finish ();
 
   if (traced)
-    trace_post (SYMBOL_NAME (sym), my_call_id, argc, argv, expanded);
+    trace_post (SYMBOL_NAME (sym), my_call_id, argv->argc, argv, expanded);
 
   current_file = loc_close_file;
   current_line = loc_close_line;
@@ -404,11 +424,50 @@ expand_macro (symbol *sym)
     free_symbol (sym);
 
   /* TODO pay attention to argv->inuse, in case someone is depending on 
address@hidden  */
-  if (argc_start)
-    obstack_free (&argc_stack, argc_start);
+  if (0 < argc_size)
+    obstack_regrow (&argc_stack, argc_base, argc_size);
+  else
+    obstack_free (&argc_stack, argc_base);
+  if (0 < argv_size)
+    obstack_regrow (&argv_stack, argv_base, argv_size);
   else
-    obstack_free (&arguments, NULL);
-  obstack_blank (&argv_stack, argv_base - obstack_object_size (&argv_stack));
+    obstack_free (&argv_stack, argv);
+}
+
+/* Given ARGV, return the token_data that contains argument INDEX;
+   INDEX must be > 0, < argv->argc.  */
+static token_data *
+arg_token (macro_arguments *argv, unsigned int index)
+{
+  unsigned int i;
+  token_data *token;
+
+  assert (index && index < argv->argc);
+  if (!argv->has_ref)
+    return argv->array[index - 1];
+  /* Must cycle through all tokens, until we find index, since a ref
+     may occupy multiple indices.  */
+  for (i = 0; i < argv->arraylen; i++)
+    {
+      token = argv->array[i];
+      if (TOKEN_DATA_TYPE (token) == TOKEN_COMP)
+       {
+         token_chain *chain = token->u.chain;
+         /* TODO - for now we support only a single-length $@ chain.  */
+         assert (!chain->next && !chain->str);
+         if (index < chain->argv->argc - (chain->index - 1))
+           {
+             token = arg_token (chain->argv, chain->index - 1 + index);
+             if (chain->flatten && TOKEN_DATA_TYPE (token) == TOKEN_FUNC)
+               token = &empty_token;
+             break;
+           }
+         index -= chain->argv->argc - chain->index;
+       }
+      else if (--index == 0)
+       break;
+    }
+  return token;
 }
 
 
@@ -424,9 +483,15 @@ arg_argc (macro_arguments *argv)
 token_data_type
 arg_type (macro_arguments *argv, unsigned int index)
 {
+  token_data_type type;
+  token_data *token;
+
   if (index == 0 || index >= argv->argc)
     return TOKEN_TEXT;
-  return TOKEN_DATA_TYPE (argv->array[index - 1]);
+  token = arg_token (argv, index);
+  type = TOKEN_DATA_TYPE (token);
+  assert (type != TOKEN_COMP);
+  return type;
 }
 
 /* Given ARGV, return the text at argument INDEX, or NULL if the
@@ -435,13 +500,59 @@ arg_type (macro_arguments *argv, unsigned int index)
 const char *
 arg_text (macro_arguments *argv, unsigned int index)
 {
+  token_data *token;
+
   if (index == 0)
     return argv->argv0;
   if (index >= argv->argc)
     return "";
-  if (TOKEN_DATA_TYPE (argv->array[index - 1]) != TOKEN_TEXT)
-    return NULL;
-  return TOKEN_DATA_TEXT (argv->array[index - 1]);
+  token = arg_token (argv, index);
+  switch (TOKEN_DATA_TYPE (token))
+    {
+    case TOKEN_TEXT:
+      return TOKEN_DATA_TEXT (token);
+    case TOKEN_FUNC:
+      return NULL;
+    case TOKEN_COMP:
+      /* TODO - how to concatenate multiple arguments?  For now, we expect
+        only one element in the chain, and arg_token dereferences it.  */
+    default:
+      break;
+    }
+  assert (!"arg_text");
+  abort ();
+}
+
+/* Given ARGV, compare text arguments INDEXA and INDEXB for equality.
+   Both indices must be non-zero and less than argc.  Return true if
+   the arguments contain the same contents; often more efficient than
+   strcmp (arg_text (argv, indexa), arg_text (argv, indexb)) == 0.  */
+bool
+arg_equal (macro_arguments *argv, unsigned int indexa, unsigned int indexb)
+{
+  token_data *ta = arg_token (argv, indexa);
+  token_data *tb = arg_token (argv, indexb);
+
+  if (ta == &empty_token || tb == &empty_token)
+    return ta == tb;
+  /* TODO - allow builtin tokens in the comparison?  */
+  assert (TOKEN_DATA_TYPE (ta) == TOKEN_TEXT
+         && TOKEN_DATA_TYPE (tb) == TOKEN_TEXT);
+  return (TOKEN_DATA_LEN (ta) == TOKEN_DATA_LEN (tb)
+         && strcmp (TOKEN_DATA_TEXT (ta), TOKEN_DATA_TEXT (tb)) == 0);
+}
+
+/* Given ARGV, return true if argument INDEX is the empty string.
+   This gives the same result as comparing arg_len against 0, but is
+   often faster.  */
+bool
+arg_empty (macro_arguments *argv, unsigned int index)
+{
+  if (index == 0)
+    return argv->argv0_len == 0;
+  if (index >= argv->argc)
+    return true;
+  return arg_token (argv, index) == &empty_token;
 }
 
 /* Given ARGV, return the length of argument INDEX, or SIZE_MAX if the
@@ -449,13 +560,28 @@ arg_text (macro_arguments *argv, unsigned int index)
 size_t
 arg_len (macro_arguments *argv, unsigned int index)
 {
+  token_data *token;
+
   if (index == 0)
     return argv->argv0_len;
   if (index >= argv->argc)
     return 0;
-  if (TOKEN_DATA_TYPE (argv->array[index - 1]) != TOKEN_TEXT)
-    return SIZE_MAX;
-  return TOKEN_DATA_LEN (argv->array[index - 1]);
+  token = arg_token (argv, index);
+  switch (TOKEN_DATA_TYPE (token))
+    {
+    case TOKEN_TEXT:
+      assert ((token == &empty_token) == (TOKEN_DATA_LEN (token) == 0));
+      return TOKEN_DATA_LEN (token);
+    case TOKEN_FUNC:
+      return SIZE_MAX;
+    case TOKEN_COMP:
+      /* TODO - how to concatenate multiple arguments?  For now, we expect
+        only one element in the chain, and arg_token dereferences it.  */
+    default:
+      break;
+    }
+  assert (!"arg_len");
+  abort ();
 }
 
 /* Given ARGV, return the builtin function referenced by argument
@@ -464,8 +590,86 @@ arg_len (macro_arguments *argv, unsigned int index)
 builtin_func *
 arg_func (macro_arguments *argv, unsigned int index)
 {
-  if (index == 0 || index >= argv->argc
-      || TOKEN_DATA_TYPE (argv->array[index - 1]) != TOKEN_FUNC)
+  token_data *token;
+
+  if (index == 0 || index >= argv->argc)
     return NULL;
-  return TOKEN_DATA_FUNC (argv->array[index - 1]);
+  token = arg_token (argv, index);
+  switch (TOKEN_DATA_TYPE (token))
+    {
+    case TOKEN_FUNC:
+      return TOKEN_DATA_FUNC (token);
+    case TOKEN_TEXT:
+      return NULL;
+    case TOKEN_COMP:
+      /* TODO - how to concatenate multiple arguments?  For now, we expect
+        only one element in the chain.  */
+    default:
+      break;
+    }
+  assert(!"arg_func");
+  abort ();
+}
+
+/* Create a new argument object using the same obstack as ARGV; thus,
+   the new object will automatically be freed when the original is
+   freed.  Explicitly set the macro name (argv[0]) from ARGV0 with
+   length ARGV0_LEN.  If SKIP, set argv[1] of the new object to
+   argv[2] of the old, otherwise the objects share all arguments.  If
+   FLATTEN, any non-text in ARGV is flattened to an empty string when
+   referenced through the new object.  */
+macro_arguments *
+make_argv_ref (macro_arguments *argv, const char *argv0, size_t argv0_len,
+              bool skip, bool flatten)
+{
+  macro_arguments *new_argv;
+  token_data *token;
+  token_chain *chain;
+  unsigned int index = skip ? 2 : 1;
+
+  assert (obstack_object_size (&argv_stack) == 0);
+  /* When making a reference through a reference, point to the
+     original if possible.  */
+  if (argv->has_ref)
+    {
+      /* TODO - for now we support only a single-length $@ chain.  */
+      assert (argv->arraylen == 1
+             && TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP);
+      chain = argv->array[0]->u.chain;
+      assert (!chain->next && !chain->str);
+      argv = chain->argv;
+      index += chain->index - 1;
+    }
+  if (argv->argc <= index)
+    {
+      new_argv = (macro_arguments *)
+       obstack_alloc (&argv_stack, offsetof (macro_arguments, array));
+      new_argv->arraylen = 0;
+      new_argv->has_ref = false;
+    }
+  else
+    {
+      new_argv = (macro_arguments *)
+       obstack_alloc (&argv_stack,
+                      offsetof (macro_arguments, array) + sizeof token);
+      token = (token_data *) obstack_alloc (&argv_stack, sizeof *token);
+      chain = (token_chain *) obstack_alloc (&argv_stack, sizeof *chain);
+      new_argv->arraylen = 1;
+      new_argv->array[0] = token;
+      new_argv->has_ref = true;
+      TOKEN_DATA_TYPE (token) = TOKEN_COMP;
+      token->u.chain = chain;
+      chain->next = NULL;
+      chain->str = NULL;
+      chain->len = 0;
+      chain->argv = argv;
+      chain->index = index;
+      chain->flatten = flatten;
+    }
+  /* TODO - should argv->inuse be set?  */
+  new_argv->argc = argv->argc - (index - 1);
+  new_argv->inuse = false;
+  new_argv->argv0 = argv0;
+  new_argv->argv0_len = argv0_len;
+  return new_argv;
 }


hooks/post-receive
--
GNU M4 source repository




reply via email to

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