m4-commit
[Top][All Lists]
Advanced

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

[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-24-


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-24-g6128996
Date: Fri, 30 Nov 2007 05:06:27 +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=6128996ce3111b5fe1f7d879e11af37c44ee3a92

The branch, master has been updated
       via  6128996ce3111b5fe1f7d879e11af37c44ee3a92 (commit)
      from  17a806c25764db643660d374bc6263a7e42d93ab (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 6128996ce3111b5fe1f7d879e11af37c44ee3a92
Author: Eric Blake <address@hidden>
Date:   Thu Nov 29 21:26:22 2007 -0700

    Stage 4: route indir, builtin through ref; make argv opaque.
    
    * m4/system_.h (obstack_regrow): Fix precedence.
    * m4/m4module.h (m4_arg_equal, m4_arg_empty, m4_make_argv_ref):
    New prototypes.
    (struct m4_macro_args): Move...
    * m4/m4private.h (struct m4_macro_args): ...here, making it opaque
    to modules.  Add has_ref member.
    (bool_bitfield): New helper typedef.
    (struct m4_symbol_chain): Add flatten and len members.
    * m4/macro.c (empty_symbol): New placeholder, for optimizing
    comparison with empty string.
    (m4_macro_expand_input): Initialize it.
    (collect_arguments): Alter signature, and populate new fields.
    (trace_pre, trace_post): Remove redundant parameter.
    (expand_macro): Alter handling of obstacks.
    (m4_arg_symbol): Account for wrapped argv.
    (m4_arg_equal, m4_arg_empty, m4_make_argv_ref): New methods.
    (m4_arg_text, m4_arg_len, m4_arg_func): Use new methods.
    * modules/m4.c (ifelse, syscmd): Likewise.
    * modules/evalparse.c (m4_evaluate): Likewise.
    (undefine, popdef, m4_dump_symbols): Optimize.
    * modules/gnu.c (builtin, indir, esyscmd, debugfile): Use new
    methods.
    (changesyntax, regexp): Optimize.
    * m4/output.c (diversion_storage): Use typedef.
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog           |   26 ++++++
 m4/m4module.h       |   25 +----
 m4/m4private.h      |   56 +++++++++---
 m4/macro.c          |  246 ++++++++++++++++++++++++++++++++++++++++-----------
 m4/output.c         |    2 +-
 m4/system_.h        |    6 +-
 modules/evalparse.c |    3 +-
 modules/gnu.c       |   62 ++++---------
 modules/m4.c        |   38 ++++----
 9 files changed, 312 insertions(+), 152 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 695720d..55ee2ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,31 @@
 2007-11-29  Eric Blake  <address@hidden>
 
+       Stage 4: route indir, builtin through ref; make argv opaque.
+       * m4/system_.h (obstack_regrow): Fix precedence.
+       * m4/m4module.h (m4_arg_equal, m4_arg_empty, m4_make_argv_ref):
+       New prototypes.
+       (struct m4_macro_args): Move...
+       * m4/m4private.h (struct m4_macro_args): ...here, making it opaque
+       to modules.  Add has_ref member.
+       (bool_bitfield): New helper typedef.
+       (struct m4_symbol_chain): Add flatten and len members.
+       * m4/macro.c (empty_symbol): New placeholder, for optimizing
+       comparison with empty string.
+       (m4_macro_expand_input): Initialize it.
+       (collect_arguments): Alter signature, and populate new fields.
+       (trace_pre, trace_post): Remove redundant parameter.
+       (expand_macro): Alter handling of obstacks.
+       (m4_arg_symbol): Account for wrapped argv.
+       (m4_arg_equal, m4_arg_empty, m4_make_argv_ref): New methods.
+       (m4_arg_text, m4_arg_len, m4_arg_func): Use new methods.
+       * modules/m4.c (ifelse, syscmd): Likewise.
+       * modules/evalparse.c (m4_evaluate): Likewise.
+       (undefine, popdef, m4_dump_symbols): Optimize.
+       * modules/gnu.c (builtin, indir, esyscmd, debugfile): Use new
+       methods.
+       (changesyntax, regexp): Optimize.
+       * m4/output.c (diversion_storage): Use typedef.
+
        Stage 3b: cache length, rather than computing it, in modules.
        * m4/hash.c (m4_hash_remove): Avoid double free on remove
        failure.
diff --git a/m4/m4module.h b/m4/m4module.h
index 7ffaffd..8f3f590 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -77,26 +77,6 @@ struct m4_macro
   const char *value;
 };
 
-/* FIXME - make this struct opaque.  */
-struct m4_macro_args
-{
-  /* One more than the highest actual argument.  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 all references have been rescanned.  */
-  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.  */
-  m4_symbol_value *array[FLEXIBLE_ARRAY_MEMBER];
-};
-
-
 #define M4BUILTIN(name)                                                        
\
   static void CONC (builtin_, name)                                    \
    (m4 *context, m4_obstack *obs, unsigned int argc, m4_macro_args *argv);
@@ -320,8 +300,13 @@ extern m4_symbol_value *m4_arg_symbol      (m4_macro_args 
*, unsigned int);
 extern bool    m4_is_arg_text          (m4_macro_args *, unsigned int);
 extern bool    m4_is_arg_func          (m4_macro_args *, unsigned int);
 extern const char *m4_arg_text         (m4_macro_args *, unsigned int);
+extern bool    m4_arg_equal            (m4_macro_args *, unsigned int,
+                                         unsigned int);
+extern bool    m4_arg_empty            (m4_macro_args *, unsigned int);
 extern size_t  m4_arg_len              (m4_macro_args *, unsigned int);
 extern m4_builtin_func *m4_arg_func    (m4_macro_args *, unsigned int);
+extern m4_macro_args *m4_make_argv_ref (m4_macro_args *, const char *, size_t,
+                                         bool, bool);
 
 
 /* --- RUNTIME DEBUGGING --- */
diff --git a/m4/m4private.h b/m4/m4private.h
index 84e7157..8e23e00 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -41,6 +41,15 @@ typedef enum {
 #define BIT_SET(flags, bit)    ((flags) |= (bit))
 #define BIT_RESET(flags, bit)  ((flags) &= ~(bit))
 
+/* Gnulib's stdbool doesn't work with bool bitfields.  For nicer
+   debugging, use bool when we know it works, but use the more
+   portable unsigned int elsewhere.  */
+#if __GNUC__ > 2
+typedef bool bool_bitfield;
+#else
+typedef unsigned int bool_bitfield;
+#endif /* !__GNUC__ */
+
 
 /* --- CONTEXT MANAGEMENT --- */
 
@@ -176,17 +185,19 @@ typedef struct m4_symbol_chain m4_symbol_chain;
 
 struct m4_symbol
 {
-  bool         traced;
-  m4_symbol_value *    value;
+  bool traced;                 /* True if this symbol is traced.  */
+  m4_symbol_value *value;      /* Linked list of pushdef'd values.  */
 };
 
 /* Composite symbols are built of a linked list of chain objects.  */
 struct m4_symbol_chain
 {
   m4_symbol_chain *next;/* Pointer to next link of chain.  */
-  char *str;           /* NUL-terminated string if text, else NULL.  */
+  char *str;           /* NUL-terminated string if text, or NULL.  */
+  size_t len;          /* Length of str, or 0.  */
   m4_macro_args *argv; /* Reference to earlier address@hidden  */
-  unsigned int index;  /* Index within argv to start reading from.  */
+  unsigned int index;  /* Argument index within argv.  */
+  bool flatten;                /* True to treat builtins as text.  */
 };
 
 /* A symbol value is used both for values associated with a macro
@@ -215,6 +226,29 @@ struct m4_symbol_value
   } u;
 };
 
+/* Structure describing all arguments to a macro, including the macro
+   name at index 0.  */
+struct m4_macro_args
+{
+  /* One more than the highest actual argument.  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 all references have been rescanned.  */
+  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.  */
+  m4_symbol_value *array[FLEXIBLE_ARRAY_MEMBER];
+};
+
 #define VALUE_NEXT(T)          ((T)->next)
 #define VALUE_MODULE(T)                ((T)->module)
 #define VALUE_FLAGS(T)         ((T)->flags)
@@ -223,13 +257,13 @@ struct m4_symbol_value
 #define VALUE_MAX_ARGS(T)      ((T)->max_args)
 #define VALUE_PENDING(T)       ((T)->pending_expansions)
 
-#define SYMBOL_NEXT(S)         (VALUE_NEXT          ((S)->value))
-#define SYMBOL_MODULE(S)       (VALUE_MODULE        ((S)->value))
-#define SYMBOL_FLAGS(S)                (VALUE_FLAGS         ((S)->value))
-#define SYMBOL_ARG_SIGNATURE(S)        (VALUE_ARG_SIGNATURE ((S)->value))
-#define SYMBOL_MIN_ARGS(S)     (VALUE_MIN_ARGS      ((S)->value))
-#define SYMBOL_MAX_ARGS(S)     (VALUE_MAX_ARGS      ((S)->value))
-#define SYMBOL_PENDING(S)      (VALUE_PENDING       ((S)->value))
+#define SYMBOL_NEXT(S)         (VALUE_NEXT             ((S)->value))
+#define SYMBOL_MODULE(S)       (VALUE_MODULE           ((S)->value))
+#define SYMBOL_FLAGS(S)                (VALUE_FLAGS            ((S)->value))
+#define SYMBOL_ARG_SIGNATURE(S)        (VALUE_ARG_SIGNATURE    ((S)->value))
+#define SYMBOL_MIN_ARGS(S)     (VALUE_MIN_ARGS         ((S)->value))
+#define SYMBOL_MAX_ARGS(S)     (VALUE_MAX_ARGS         ((S)->value))
+#define SYMBOL_PENDING(S)      (VALUE_PENDING          ((S)->value))
 
 /* Fast macro versions of symbol table accessor functions,
    that also have an identically named function exported in m4module.h.  */
diff --git a/m4/macro.c b/m4/macro.c
index 5769f99..25fc7e7 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -30,8 +30,7 @@
 #include "intprops.h"
 
 static m4_macro_args *collect_arguments (m4 *, const char *, size_t,
-                                        m4_symbol *, m4_obstack *,
-                                        unsigned int, m4_obstack *);
+                                        m4_symbol *, m4_obstack *);
 static void    expand_macro      (m4 *, const char *, size_t, m4_symbol *);
 static void    expand_token      (m4 *, m4_obstack *, m4__token_type,
                                  m4_symbol_value *, int);
@@ -42,9 +41,9 @@ static void    process_macro   (m4 *, m4_symbol_value *, 
m4_obstack *, int,
 
 static void    trace_prepre     (m4 *, const char *, size_t,
                                  m4_symbol_value *);
-static void    trace_pre        (m4 *, const char *, size_t, m4_macro_args *);
-static void    trace_post       (m4 *, const char *, size_t,
-                                 m4_macro_args *, m4_input_block *, bool);
+static void    trace_pre        (m4 *, size_t, m4_macro_args *);
+static void    trace_post       (m4 *, size_t, m4_macro_args *,
+                                 m4_input_block *, bool);
 
 static void    trace_format     (m4 *, const char *, ...)
   M4_GNUC_PRINTF (2, 3);
@@ -63,13 +62,17 @@ static size_t macro_call_id = 0;
    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;
+static m4_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.  */
-static struct obstack argv_stack;
+static m4_obstack argv_stack;
+
+/* A placeholder symbol value representing the empty string, used to
+   optimize checks for emptiness.  */
+static m4_symbol_value empty_symbol;
 
 /* This function reads all input, and expands each token, one at a time.  */
 void
@@ -82,6 +85,8 @@ m4_macro_expand_input (m4 *context)
   obstack_init (&argc_stack);
   obstack_init (&argv_stack);
 
+  m4_set_symbol_value_text (&empty_symbol, "", 0);
+
   while ((type = m4__next_token (context, &token, &line, NULL))
         != M4_TOKEN_EOF)
     expand_token (context, (m4_obstack *) NULL, type, &token, line);
@@ -251,7 +256,8 @@ expand_argument (m4 *context, m4_obstack *obs, 
m4_symbol_value *argp,
 static void
 expand_macro (m4 *context, const char *name, size_t len, m4_symbol *symbol)
 {
-  char *argc_base = NULL;      /* Base of argc_stack on entry.  */
+  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.  */
   m4_macro_args *argv;
@@ -296,17 +302,14 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
 
   argc_size = obstack_object_size (&argc_stack);
   argv_size = obstack_object_size (&argv_stack);
-  if (0 < argc_size)
-    argc_base = obstack_finish (&argc_stack);
+  argc_base = obstack_finish (&argc_stack);
+  if (0 < argv_size)
+    argv_base = obstack_finish (&argv_stack);
 
   if (traced && m4_is_debug_bit (context, M4_DEBUG_TRACE_CALL))
     trace_prepre (context, name, my_call_id, value);
 
-  argv = collect_arguments (context, name, len, symbol, &argv_stack,
-                           argv_size, &argc_stack);
-  /* Calling collect_arguments invalidated name, but we copied it as
-     argv[0].  */
-  name = argv->argv0;
+  argv = collect_arguments (context, name, len, symbol, &argc_stack);
 
   loc_close_file = m4_get_current_file (context);
   loc_close_line = m4_get_current_line (context);
@@ -314,14 +317,14 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
   m4_set_current_line (context, loc_open_line);
 
   if (traced)
-    trace_pre (context, name, my_call_id, argv);
+    trace_pre (context, my_call_id, argv);
 
   expansion = m4_push_string_init (context);
   m4_macro_call (context, value, expansion, argv->argc, argv);
   expanded = m4_push_string_finish ();
 
   if (traced)
-    trace_post (context, name, my_call_id, argv, expanded, trace_expansion);
+    trace_post (context, my_call_id, argv, expanded, trace_expansion);
 
   m4_set_current_file (context, loc_close_file);
   m4_set_current_line (context, loc_close_line);
@@ -335,20 +338,21 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
   if (0 < argc_size)
     obstack_regrow (&argc_stack, argc_base, argc_size);
   else
-    obstack_free (&argc_stack, (void *) name);
-  obstack_blank (&argv_stack, argv_size - obstack_object_size (&argv_stack));
+    obstack_free (&argc_stack, argc_base);
+  if (0 < argv_size)
+    obstack_regrow (&argv_stack, argv_base, argv_size);
+  else
+    obstack_free (&argv_stack, argv);
 }
 
 /* Collect all the arguments to a call of the macro SYMBOL (called
    NAME, with length LEN).  The arguments are stored on the obstack
    ARGUMENTS and a table of pointers to the arguments on the obstack
-   ARGPTR.  ARGPTR is an incomplete object, currently occupying
-   ARGV_BASE bytes.  Return the object describing all of the macro
+   argv_stack.  Return the object describing all of the macro
    arguments.  */
 static m4_macro_args *
 collect_arguments (m4 *context, const char *name, size_t len,
-                  m4_symbol *symbol, m4_obstack *argptr,
-                  unsigned int argv_base, m4_obstack *arguments)
+                  m4_symbol *symbol, m4_obstack *arguments)
 {
   m4_symbol_value token;
   m4_symbol_value *tokenp;
@@ -361,10 +365,13 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
 
   args.argc = 1;
   args.inuse = false;
+  args.has_ref = false;
+  /* FIXME - add accessor to symtab that returns name from the hash
+     table, so we don't have to copy it here.  */
   args.argv0 = (char *) obstack_copy0 (arguments, name, len);
   args.argv0_len = len;
   args.arraylen = 0;
-  obstack_grow (argptr, &args, offsetof (m4_macro_args, array));
+  obstack_grow (&argv_stack, &args, offsetof (m4_macro_args, array));
   name = args.argv0;
 
   if (m4__next_token_is_open (context))
@@ -374,20 +381,20 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
        {
          more_args = expand_argument (context, arguments, &token, name);
 
-         if (!groks_macro_args && m4_is_symbol_value_func (&token))
-           {
-             VALUE_MODULE (&token) = NULL;
-             m4_set_symbol_value_text (&token, "", 0);
-           }
-         tokenp = (m4_symbol_value *) obstack_copy (arguments, &token,
-                                                    sizeof token);
-         obstack_ptr_grow (argptr, tokenp);
+         if ((m4_is_symbol_value_text (&token)
+              && !m4_get_symbol_value_len (&token))
+             || (!groks_macro_args && m4_is_symbol_value_func (&token)))
+           tokenp = &empty_symbol;
+         else
+           tokenp = (m4_symbol_value *) obstack_copy (arguments, &token,
+                                                      sizeof *tokenp);
+         obstack_ptr_grow (&argv_stack, tokenp);
          args.arraylen++;
          args.argc++;
        }
       while (more_args);
     }
-  argv = (m4_macro_args *) ((char *) obstack_base (argptr) + argv_base);
+  argv = (m4_macro_args *) obstack_finish (&argv_stack);
   argv->argc = args.argc;
   argv->arraylen = args.arraylen;
   return argv;
@@ -536,11 +543,11 @@ process_macro (m4 *context, m4_symbol_value *value, 
m4_obstack *obs,
 
 
 
-/* The rest of this file contains the functions for macro tracing output.
-   All tracing output for a macro call is collected on an obstack TRACE,
-   and printed whenever the line is complete.  This prevents tracing
-   output from interfering with other debug messages generated by the
-   various builtins.  */
+/* The next portion of this file contains the functions for macro
+   tracing output.  All tracing output for a macro call is collected
+   on an obstack TRACE, and printed whenever the line is complete.
+   This prevents tracing output from interfering with other debug
+   messages generated by the various builtins.  */
 
 /* Tracing output is formatted here, by a simplified printf-to-obstack
    function trace_format ().  Understands only %s, %d, %zu (size_t
@@ -653,13 +660,13 @@ trace_prepre (m4 *context, const char *name, size_t id, 
m4_symbol_value *value)
 /* Format the parts of a trace line, that can be made before the macro is
    actually expanded.  Used from expand_macro ().  */
 static void
-trace_pre (m4 *context, const char *name, size_t id, m4_macro_args *argv)
+trace_pre (m4 *context, size_t id, m4_macro_args *argv)
 {
   unsigned int i;
   unsigned int argc = m4_arg_argc (argv);
 
   trace_header (context, id);
-  trace_format (context, "%s", name);
+  trace_format (context, "%s", M4ARG (0));
 
   if (1 < argc && m4_is_debug_bit (context, M4_DEBUG_TRACE_ARGS))
     {
@@ -686,9 +693,8 @@ trace_pre (m4 *context, const char *name, size_t id, 
m4_macro_args *argv)
 /* Format the final part of a trace line and print it all.  Used from
    expand_macro ().  */
 static void
-trace_post (m4 *context, const char *name, size_t id,
-           m4_macro_args *argv, m4_input_block *expanded,
-           bool trace_expansion)
+trace_post (m4 *context, size_t id, m4_macro_args *argv,
+           m4_input_block *expanded, bool trace_expansion)
 {
   if (trace_expansion)
     {
@@ -703,12 +709,43 @@ trace_post (m4 *context, const char *name, size_t id,
 /* Accessors into m4_macro_args.  */
 
 /* Given ARGV, return the symbol value at the specified INDEX, which
-   must be non-zero and less than argc.  */
+   must be non-zero.  */
 m4_symbol_value *
 m4_arg_symbol (m4_macro_args *argv, unsigned int index)
 {
-  assert (index && index < argv->argc);
-  return argv->array[index - 1];
+  unsigned int i;
+  m4_symbol_value *value;
+
+  assert (index);
+  if (argv->argc <= index)
+    return &empty_symbol;
+
+  if (!argv->has_ref)
+    return argv->array[index - 1];
+  /* Must cycle through all array slots until we find index, since
+     wrappers can contain multiple arguments.  */
+  for (i = 0; i < argv->arraylen; i++)
+    {
+      value = argv->array[i];
+      if (value->type == M4_SYMBOL_COMP)
+       {
+         m4_symbol_chain *chain = value->u.chain;
+         /* TODO - for now we support only a single $@ chain.  */
+         assert (!chain->next && !chain->str);
+         if (index < chain->argv->argc - (chain->index - 1))
+           {
+             value = m4_arg_symbol (chain->argv, chain->index - 1 + index);
+             if (chain->flatten && m4_is_symbol_value_func (value))
+               value = &empty_symbol;
+             break;
+           }
+         index -= chain->argv->argc - chain->index;
+       }
+      else if (--index == 0)
+       break;
+    }
+  assert (value->type != M4_SYMBOL_COMP);
+  return value;
 }
 
 /* Given ARGV, return true if argument INDEX is text.  Index 0 is
@@ -737,13 +774,45 @@ m4_is_arg_func (m4_macro_args *argv, unsigned int index)
 const char *
 m4_arg_text (m4_macro_args *argv, unsigned int index)
 {
+  m4_symbol_value *value;
+
   if (index == 0)
     return argv->argv0;
   if (argv->argc <= index)
     return "";
-  if (!m4_is_symbol_value_text (argv->array[index - 1]))
+  value = m4_arg_symbol (argv, index);
+  if (!m4_is_symbol_value_text (value))
     return NULL;
-  return m4_get_symbol_value_text (argv->array[index - 1]);
+  return m4_get_symbol_value_text (value);
+}
+
+/* Given ARGV, compare text arguments INDEXA and INDEXB for equality.
+   Both indices must be non-zero.  Return true if the arguments
+   contain the same contents; often more efficient than
+   !strcmp (m4_arg_text (argv, indexa), m4_arg_text (argv, indexb)).  */
+bool
+m4_arg_equal (m4_macro_args *argv, unsigned int indexa, unsigned int indexb)
+{
+  m4_symbol_value *sa = m4_arg_symbol (argv, indexa);
+  m4_symbol_value *sb = m4_arg_symbol (argv, indexb);
+
+  if (sa == &empty_symbol || sb == &empty_symbol)
+    return sa == sb;
+  /* TODO - allow builtin tokens in the comparison?  */
+  assert (m4_is_symbol_value_text (sa) && m4_is_symbol_value_text (sb));
+  return (m4_get_symbol_value_len (sa) == m4_get_symbol_value_len (sb)
+         && strcmp (m4_get_symbol_value_text (sa),
+                    m4_get_symbol_value_text (sb)) == 0);
+}
+
+/* Given ARGV, return true if argument INDEX is the empty string.
+   This gives the same result as comparing m4_arg_len against 0, but
+   is often faster.  */
+bool
+m4_arg_empty (m4_macro_args *argv, unsigned int index)
+{
+  return (index ? m4_arg_symbol (argv, index) == &empty_symbol
+         : !argv->argv0_len);
 }
 
 /* Given ARGV, return the length of argument INDEX, or SIZE_MAX if the
@@ -751,13 +820,16 @@ m4_arg_text (m4_macro_args *argv, unsigned int index)
 size_t
 m4_arg_len (m4_macro_args *argv, unsigned int index)
 {
+  m4_symbol_value *value;
+
   if (index == 0)
     return argv->argv0_len;
   if (argv->argc <= index)
     return 0;
-  if (!m4_is_symbol_value_text (argv->array[index - 1]))
+  value = m4_arg_symbol (argv, index);
+  if (!m4_is_symbol_value_text (value))
     return SIZE_MAX;
-  return m4_get_symbol_value_len (argv->array[index - 1]);
+  return m4_get_symbol_value_len (value);
 }
 
 /* Given ARGV, return the builtin function referenced by argument
@@ -766,10 +838,78 @@ m4_arg_len (m4_macro_args *argv, unsigned int index)
 m4_builtin_func *
 m4_arg_func (m4_macro_args *argv, unsigned int index)
 {
-  if (index == 0 || argv->argc <= index
-      || !m4_is_symbol_value_func (argv->array[index - 1]))
+  m4_symbol_value *value;
+
+  if (index == 0 || argv->argc <= index)
+    return NULL;
+  value = m4_arg_symbol (argv, index);
+  if (!m4_is_symbol_value_func (value))
     return NULL;
-  return m4_get_symbol_value_func (argv->array[index - 1]);
+  return m4_get_symbol_value_func (value);
+}
+
+/* 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 builtins in ARGV are flattened to an empty string when
+   referenced through the new object.  */
+m4_macro_args *
+m4_make_argv_ref (m4_macro_args *argv, const char *argv0, size_t argv0_len,
+                 bool skip, bool flatten)
+{
+  m4_macro_args *new_argv;
+  m4_symbol_value *value;
+  m4_symbol_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 && argv->array[0]->type == M4_SYMBOL_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 = (m4_macro_args *) obstack_alloc (&argv_stack,
+                                                 offsetof (m4_macro_args,
+                                                           array));
+      new_argv->arraylen = 0;
+      new_argv->has_ref = false;
+    }
+  else
+    {
+      new_argv = (m4_macro_args *) obstack_alloc (&argv_stack,
+                                                 (offsetof (m4_macro_args,
+                                                            array)
+                                                  + sizeof value));
+      value = (m4_symbol_value *) obstack_alloc (&argv_stack, sizeof *value);
+      chain = (m4_symbol_chain *) obstack_alloc (&argv_stack, sizeof *chain);
+      new_argv->arraylen = 1;
+      new_argv->array[0] = value;
+      new_argv->has_ref = true;
+      value->type = M4_SYMBOL_COMP;
+      value->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;
 }
 
 /* Define these last, so that earlier uses can benefit from the macros
diff --git a/m4/output.c b/m4/output.c
index ed2a451..8089073 100644
--- a/m4/output.c
+++ b/m4/output.c
@@ -83,7 +83,7 @@ static m4_diversion div0;
 static m4_diversion *free_list;
 
 /* Obstack from which diversion storage is allocated.  */
-static struct obstack diversion_storage;
+static m4_obstack diversion_storage;
 
 /* Total size of all in-memory buffer sizes.  */
 static size_t total_buffer_size;
diff --git a/m4/system_.h b/m4/system_.h
index e014d75..64ca73c 100644
--- a/m4/system_.h
+++ b/m4/system_.h
@@ -53,9 +53,9 @@
    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))
+#define obstack_regrow(OBS, OBJECT, SIZE)              \
+  (obstack_free (OBS, (char *) (OBJECT) + (SIZE)),     \
+   (OBS)->object_base = (char *) (OBJECT))
 
 /* In addition to EXIT_SUCCESS and EXIT_FAILURE, m4 can fail with version
    mismatch when trying to load a frozen file produced by a newer m4 than
diff --git a/modules/evalparse.c b/modules/evalparse.c
index e21a081..39b0d41 100644
--- a/modules/evalparse.c
+++ b/modules/evalparse.c
@@ -896,7 +896,8 @@ m4_evaluate (m4 *context, m4_obstack *obs, unsigned int 
argc,
   eval_token   et;
   eval_error   err     = NO_ERROR;
 
-  if (*M4ARG (2) && !m4_numeric_arg (context, me, M4ARG (2), &radix))
+  if (!m4_arg_empty (argv, 2)
+      && !m4_numeric_arg (context, me, M4ARG (2), &radix))
     return;
 
   if (radix < 1 || radix > 36)
diff --git a/modules/gnu.c b/modules/gnu.c
index bc34692..3c772c5 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -444,26 +444,11 @@ M4BUILTIN_HANDLER (builtin)
                            bp->min_args, bp->max_args,
                            (bp->flags & M4_BUILTIN_SIDE_EFFECT) != 0))
            {
-             unsigned int i;
-             /* TODO - make use of $@ reference.  */
-             /* TODO - add accessor that performs this construction.  */
              m4_macro_args *new_argv;
-             new_argv = xmalloc (offsetof (m4_macro_args, array)
-                                 + ((argc - 2) * sizeof (m4_symbol_value *)));
-             new_argv->argc = argc - 1;
-             new_argv->inuse = false;
-             new_argv->argv0 = name;
-             new_argv->argv0_len = m4_arg_len (argv, 1);
-             new_argv->arraylen = argc - 2;
-             memcpy (&new_argv->array[0], &argv->array[1],
-                     (argc - 2) * sizeof (m4_symbol_value *));
-             if ((bp->flags & M4_BUILTIN_GROKS_MACRO) == 0)
-               for (i = 2; i < argc; i++)
-                 if (!m4_is_arg_text (argv, i))
-                   m4_set_symbol_value_text (m4_arg_symbol (new_argv, i - 1),
-                                             "", 0);
+             bool flatten = (bp->flags & M4_BUILTIN_GROKS_MACRO) == 0;
+             new_argv = m4_make_argv_ref (argv, name, m4_arg_len (argv, 1),
+                                          true, flatten);
              bp->func (context, obs, argc - 1, new_argv);
-             free (new_argv);
            }
          free (value);
        }
@@ -508,6 +493,7 @@ M4BUILTIN_HANDLER (changeresyntax)
  **/
 M4BUILTIN_HANDLER (changesyntax)
 {
+  const char *me = M4ARG (0);
   M4_MODULE_IMPORT (m4, m4_expand_ranges);
 
   if (m4_expand_ranges)
@@ -533,7 +519,7 @@ M4BUILTIN_HANDLER (changesyntax)
            }
          if (m4_set_syntax (M4SYNTAX, key, action,
                             key ? m4_expand_ranges (spec, obs) : "") < 0)
-           m4_warn (context, 0, M4ARG (0), _("undefined syntax code: `%c'"),
+           m4_warn (context, 0, me, _("undefined syntax code: `%c'"),
                     key);
        }
     }
@@ -554,7 +540,7 @@ M4BUILTIN_HANDLER (debugfile)
 
   if (argc == 1)
     m4_debug_set_output (context, me, NULL);
-  else if (m4_get_safer_opt (context) && *M4ARG (1))
+  else if (m4_get_safer_opt (context) && !m4_arg_empty (argv, 1))
     m4_error (context, 0, 0, me, _("disabled by --safer"));
   else if (!m4_debug_set_output (context, me, M4ARG (1)))
     m4_error (context, 0, errno, me, _("cannot set debug file `%s'"),
@@ -613,6 +599,7 @@ M4BUILTIN_HANDLER (debugmode)
 
 M4BUILTIN_HANDLER (esyscmd)
 {
+  const char *me = M4ARG (0);
   M4_MODULE_IMPORT (m4, m4_set_sysval);
   M4_MODULE_IMPORT (m4, m4_sysval_flush);
 
@@ -623,12 +610,12 @@ M4BUILTIN_HANDLER (esyscmd)
 
       if (m4_get_safer_opt (context))
        {
-         m4_error (context, 0, 0, M4ARG (0), _("disabled by --safer"));
+         m4_error (context, 0, 0, me, _("disabled by --safer"));
          return;
        }
 
       /* Optimize the empty command.  */
-      if (*M4ARG (1) == '\0')
+      if (m4_arg_empty (argv, 1))
        {
          m4_set_sysval (0);
          return;
@@ -639,14 +626,14 @@ M4BUILTIN_HANDLER (esyscmd)
       pin = popen (M4ARG (1), "r");
       if (pin == NULL)
        {
-         m4_error (context, 0, errno, M4ARG (0),
+         m4_error (context, 0, errno, me,
                    _("cannot open pipe to command `%s'"), M4ARG (1));
          m4_set_sysval (-1);
        }
       else
        {
          while ((ch = getc (pin)) != EOF)
-           obstack_1grow (obs, (char) ch);
+           obstack_1grow (obs, ch);
          m4_set_sysval (pclose (pin));
        }
     }
@@ -690,27 +677,12 @@ M4BUILTIN_HANDLER (indir)
        m4_warn (context, 0, me, _("undefined macro `%s'"), name);
       else
        {
-         unsigned int i;
-         /* TODO - make use of $@ reference.  */
-         /* TODO - add accessor that performs this construction.  */
          m4_macro_args *new_argv;
-         new_argv = xmalloc (offsetof (m4_macro_args, array)
-                             + ((argc - 2) * sizeof (m4_symbol_value *)));
-         new_argv->argc = argc - 1;
-         new_argv->inuse = false;
-         new_argv->argv0 = name;
-         new_argv->argv0_len = m4_arg_len (argv, 1);
-         new_argv->arraylen = argc - 2;
-         memcpy (&new_argv->array[0], &argv->array[1],
-                 (argc - 2) * sizeof (m4_symbol_value *));
-         if (!m4_symbol_groks_macro (symbol))
-           for (i = 2; i < argc; i++)
-             if (!m4_is_arg_text (argv, i))
-               m4_set_symbol_value_text (m4_arg_symbol (new_argv, i - 1),
-                                         "", 0);
+         bool flatten = !m4_symbol_groks_macro (symbol);
+         new_argv = m4_make_argv_ref (argv, name, m4_arg_len (argv, 1), true,
+                                      flatten);
          m4_macro_call (context, m4_get_symbol_value (symbol), obs,
                         argc - 1, new_argv);
-         free (new_argv);
        }
     }
 }
@@ -793,6 +765,7 @@ M4BUILTIN_HANDLER (patsubst)
 M4BUILTIN_HANDLER (regexp)
 {
   const char *me;              /* name of this macro */
+  const char *victim;          /* string to search */
   const char *pattern;         /* regular expression */
   const char *replace;         /* optional replacement string */
   m4_pattern_buffer *buf;      /* compiled regular expression */
@@ -845,8 +818,9 @@ M4BUILTIN_HANDLER (regexp)
   if (!buf)
     return;
 
+  victim = M4ARG (1);
   len = m4_arg_len (argv, 1);
-  startpos = regexp_search (buf, M4ARG (1), len, 0, len, replace == NULL);
+  startpos = regexp_search (buf, victim, len, 0, len, replace == NULL);
 
   if (startpos == -2)
     {
@@ -858,7 +832,7 @@ M4BUILTIN_HANDLER (regexp)
   if (replace == NULL)
     m4_shipout_int (obs, startpos);
   else if (startpos >= 0)
-    substitute (context, obs, me, M4ARG (1), replace, buf);
+    substitute (context, obs, me, victim, replace, buf);
 }
 
 
diff --git a/modules/m4.c b/modules/m4.c
index 827fabb..f9d65ed 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -178,13 +178,14 @@ M4BUILTIN_HANDLER (define)
 
 M4BUILTIN_HANDLER (undefine)
 {
+  const char *me = M4ARG (0);
   unsigned int i;
   for (i = 1; i < argc; i++)
     {
       const char *name = M4ARG (i);
 
       if (!m4_symbol_lookup (M4SYMTAB, name))
-       m4_warn (context, 0, M4ARG (0), _("undefined macro `%s'"), name);
+       m4_warn (context, 0, me, _("undefined macro `%s'"), name);
       else
        m4_symbol_delete (M4SYMTAB, name);
     }
@@ -209,13 +210,14 @@ M4BUILTIN_HANDLER (pushdef)
 
 M4BUILTIN_HANDLER (popdef)
 {
+  const char *me = M4ARG (0);
   unsigned int i;
   for (i = 1; i < argc; i++)
     {
       const char *name = M4ARG (i);
 
       if (!m4_symbol_lookup (M4SYMTAB, name))
-       m4_warn (context, 0, M4ARG (0), _("undefined macro `%s'"), name);
+       m4_warn (context, 0, me, _("undefined macro `%s'"), name);
       else
        m4_symbol_popdef (M4SYMTAB, name);
     }
@@ -240,10 +242,7 @@ M4BUILTIN_HANDLER (ifelse)
 
   /* The valid ranges of argc for ifelse is discontinuous, we cannot
      rely on the regular mechanisms.  */
-  if (argc == 2)
-    return;
-
-  if (m4_bad_argc (context, argc, me, 3, -1, false))
+  if (argc == 2 || m4_bad_argc (context, argc, me, 3, -1, false))
     return;
   else if (argc % 3 == 0)
     /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments.  */
@@ -254,7 +253,7 @@ M4BUILTIN_HANDLER (ifelse)
 
   while (1)
     {
-      if (strcmp (M4ARG (index), M4ARG (index + 1)) == 0)
+      if (m4_arg_equal (argv, index, index + 1))
        {
          obstack_grow (obs, M4ARG (index + 2), m4_arg_len (argv, index + 2));
          return;
@@ -317,6 +316,7 @@ void
 m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, unsigned int argc,
                 m4_macro_args *argv, bool complain)
 {
+  const char *me = M4ARG (0);
   assert (obstack_object_size (data->obs) == 0);
   data->size = obstack_room (data->obs) / sizeof (const char *);
 
@@ -329,12 +329,12 @@ m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, 
unsigned int argc,
 
       for (i = 1; i < argc; i++)
        {
-         symbol = m4_symbol_lookup (M4SYMTAB, M4ARG (i));
+         const char *name = M4ARG (i);
+         symbol = m4_symbol_lookup (M4SYMTAB, name);
          if (symbol != NULL)
-           dump_symbol_CB (NULL, M4ARG (i), symbol, data);
+           dump_symbol_CB (NULL, name, symbol, data);
          else if (complain)
-           m4_warn (context, 0, M4ARG (0), _("undefined macro `%s'"),
-                    M4ARG (i));
+           m4_warn (context, 0, me, _("undefined macro `%s'"), name);
        }
     }
 
@@ -508,14 +508,14 @@ m4_sysval_flush (m4 *context, bool report)
 
 M4BUILTIN_HANDLER (syscmd)
 {
-   if (m4_get_safer_opt (context))
-   {
-     m4_error (context, 0, 0, M4ARG (0), _("disabled by --safer"));
-     return;
-   }
-
-   /* Optimize the empty command.  */
-  if (*M4ARG (1) == '\0')
+  if (m4_get_safer_opt (context))
+    {
+      m4_error (context, 0, 0, M4ARG (0), _("disabled by --safer"));
+      return;
+    }
+
+  /* Optimize the empty command.  */
+  if (m4_arg_empty (argv, 1))
     {
       m4_set_sysval (0);
       return;


hooks/post-receive
--
GNU M4 source repository




reply via email to

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