Docs: options after "run" of ${run } may not have space. Bug 2932
[exim.git] / src / src / expand.c
index 050f01297e89df8155d38d8ce17bb88eefeecad8..9f80439cbae87b0db0cebcd626885b7f074e9122 100644 (file)
@@ -2,10 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 
 /* Functions for handling string expansion. */
 
 #include "exim.h"
 
+#ifdef MACRO_PREDEF
+# include "macro_predef.h"
+#endif
+
 typedef unsigned esi_flags;
 #define ESI_NOFLAGS            0
 #define ESI_BRACE_ENDS         BIT(0)  /* expansion should stop at } */
 #define ESI_HONOR_DOLLAR       BIT(1)  /* $ is meaningfull */
 #define ESI_SKIPPING           BIT(2)  /* value will not be needed */
 
+#ifdef STAND_ALONE
+# ifndef SUPPORT_CRYPTEQ
+#  define SUPPORT_CRYPTEQ
+# endif
+#else
+
 /* Recursively called function */
 
 static uschar *expand_string_internal(const uschar *, esi_flags, const uschar **, BOOL *, BOOL *);
 static int_eximarith_t expanded_string_integer(const uschar *, BOOL);
 
-#ifdef STAND_ALONE
-# ifndef SUPPORT_CRYPTEQ
-#  define SUPPORT_CRYPTEQ
-# endif
-#endif
+#endif /*!STAND_ALONE*/
 
 #ifdef LOOKUP_LDAP
 # include "lookups/ldap.h"
@@ -231,6 +237,7 @@ static uschar *op_table_main[] = {
   US"expand",
   US"h",
   US"hash",
+  US"headerwrap",
   US"hex2b64",
   US"hexquote",
   US"ipv6denorm",
@@ -278,6 +285,7 @@ enum {
   EOP_EXPAND,
   EOP_H,
   EOP_HASH,
+  EOP_HEADERWRAP,
   EOP_HEX2B64,
   EOP_HEXQUOTE,
   EOP_IPV6DENORM,
@@ -472,8 +480,8 @@ typedef struct {
   int  *length;
 } alblock;
 
-static uschar * fn_recipients(void);
 typedef uschar * stringptr_fn_t(void);
+static uschar * fn_recipients(void);
 static uschar * fn_queue_size(void);
 
 /* This table must be kept in alphabetical order. */
@@ -679,7 +687,7 @@ static var_entry var_table[] = {
   { "qualify_domain",      vtype_stringptr,   &qualify_domain_sender },
   { "qualify_recipient",   vtype_stringptr,   &qualify_domain_recipient },
   { "queue_name",          vtype_stringptr,   &queue_name },
-  { "queue_size",          vtype_string_func, &fn_queue_size },
+  { "queue_size",          vtype_string_func, (void *) &fn_queue_size },
   { "rcpt_count",          vtype_int,         &rcpt_count },
   { "rcpt_defer_count",    vtype_int,         &rcpt_defer_count },
   { "rcpt_fail_count",     vtype_int,         &rcpt_fail_count },
@@ -711,6 +719,7 @@ static var_entry var_table[] = {
   { "sender_fullhost",     vtype_stringptr,   &sender_fullhost },
   { "sender_helo_dnssec",  vtype_bool,        &sender_helo_dnssec },
   { "sender_helo_name",    vtype_stringptr,   &sender_helo_name },
+  { "sender_helo_verified",vtype_string_func, (void *) &sender_helo_verified_boolstr },
   { "sender_host_address", vtype_stringptr,   &sender_host_address },
   { "sender_host_authenticated",vtype_stringptr, &sender_host_authenticated },
   { "sender_host_dnssec",  vtype_bool,        &sender_host_dnssec },
@@ -830,7 +839,75 @@ static var_entry var_table[] = {
   { "warnmsg_recipients",  vtype_stringptr,   &warnmsg_recipients }
 };
 
-static int var_table_size = nelem(var_table);
+#ifdef MACRO_PREDEF
+
+/* dummies */
+uschar * fn_arc_domains(void) {return NULL;}
+uschar * fn_hdrs_added(void) {return NULL;}
+uschar * fn_queue_size(void) {return NULL;}
+uschar * fn_recipients(void) {return NULL;}
+uschar * sender_helo_verified_boolstr(void) {return NULL;}
+uschar * smtp_cmd_hist(void) {return NULL;}
+
+
+
+static void
+expansion_items(void)
+{
+uschar buf[64];
+for (int i = 0; i < nelem(item_table); i++)
+  {
+  spf(buf, sizeof(buf), CUS"_EXP_ITEM_%T", item_table[i]);
+  builtin_macro_create(buf);
+  }
+}
+static void
+expansion_operators(void)
+{
+uschar buf[64];
+for (int i = 0; i < nelem(op_table_underscore); i++)
+  {
+  spf(buf, sizeof(buf), CUS"_EXP_OP_%T", op_table_underscore[i]);
+  builtin_macro_create(buf);
+  }
+for (int i = 0; i < nelem(op_table_main); i++)
+  {
+  spf(buf, sizeof(buf), CUS"_EXP_OP_%T", op_table_main[i]);
+  builtin_macro_create(buf);
+  }
+}
+static void
+expansion_conditions(void)
+{
+uschar buf[64];
+for (int i = 0; i < nelem(cond_table); i++)
+  {
+  spf(buf, sizeof(buf), CUS"_EXP_COND_%T", cond_table[i]);
+  builtin_macro_create(buf);
+  }
+}
+static void
+expansion_variables(void)
+{
+uschar buf[64];
+for (int i = 0; i < nelem(var_table); i++)
+  {
+  spf(buf, sizeof(buf), CUS"_EXP_VAR_%T", var_table[i].name);
+  builtin_macro_create(buf);
+  }
+}
+
+void
+expansions(void)
+{
+expansion_items();
+expansion_operators();
+expansion_conditions();
+expansion_variables();
+}
+
+#else  /*!MACRO_PREDEF*/
+
 static uschar var_buffer[256];
 static BOOL malformed_header;
 
@@ -1203,7 +1280,7 @@ static var_entry *
 find_var_ent(uschar * name)
 {
 int first = 0;
-int last = var_table_size;
+int last = nelem(var_table);
 
 while (last > first)
   {
@@ -1592,12 +1669,13 @@ Returns:        NULL if the header does not exist, else a pointer to a new
 */
 
 static uschar *
-find_header(uschar *name, int *newsize, unsigned flags, const uschar *charset)
+find_header(uschar * name, int * newsize, unsigned flags, const uschar * charset)
 {
 BOOL found = !name;
 int len = name ? Ustrlen(name) : 0;
 BOOL comma = FALSE;
 gstring * g = NULL;
+uschar * rawhdr;
 
 for (header_line * h = header_list; h; h = h->next)
   if (h->type != htype_old && h->text)  /* NULL => Received: placeholder */
@@ -1660,8 +1738,9 @@ if (!g) return US"";
 /* That's all we do for raw header expansion. */
 
 *newsize = g->size;
+rawhdr = string_from_gstring(g);
 if (flags & FH_WANT_RAW)
-  return string_from_gstring(g);
+  return rawhdr;
 
 /* Otherwise do RFC 2047 decoding, translating the charset if requested.
 The rfc2047_decode2() function can return an error with decoded data if the
@@ -1669,12 +1748,12 @@ charset translation fails. If decoding fails, it returns NULL. */
 
 else
   {
-  uschar * error, * decoded = rfc2047_decode2(string_from_gstring(g),
+  uschar * error, * decoded = rfc2047_decode2(rawhdr,
     check_rfc2047_length, charset, '?', NULL, newsize, &error);
   if (error)
     DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n"
-      "    input was: %s\n", error, g->s);
-  return decoded ? decoded : string_from_gstring(g);
+      "    input was: %s\n", error, rawhdr);
+  return decoded ? decoded : rawhdr;
   }
 }
 
@@ -1739,7 +1818,7 @@ for (int i = 0; i < recipients_count; i++)
   s = recipients_list[i].address;
   g = string_append2_listele_n(g, US", ", s, Ustrlen(s));
   }
-return g ? g->s : NULL;
+return string_from_gstring(g);
 }
 
 
@@ -4658,6 +4737,7 @@ while (*s)
     reset in the middle of the buffer will make it inaccessible. */
 
     len = Ustrlen(value);
+    DEBUG(D_expand) debug_expansion_interim(US"value", value, len, !!(flags & ESI_SKIPPING));
     if (!yield && newsize != 0)
       {
       yield = g;
@@ -4671,12 +4751,15 @@ while (*s)
     continue;
     }
 
-  if (isdigit(*s))
+  if (isdigit(*s))             /* A $<n> variable */
     {
     int n;
     s = read_cnumber(&n, s);
     if (n >= 0 && n <= expand_nmax)
+      {
+      DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], !!(flags & ESI_SKIPPING));
       yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
+      }
     continue;
     }
 
@@ -4701,7 +4784,10 @@ while (*s)
       goto EXPAND_FAILED;
       }
     if (n >= 0 && n <= expand_nmax)
+      {
+      DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], !!(flags & ESI_SKIPPING));
       yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
+      }
     continue;
     }
 
@@ -4722,7 +4808,7 @@ while (*s)
   skipping, but "break" otherwise so we get debug output for the item
   expansion. */
   {
-  int start = gstring_length(yield);
+  int expansion_start = gstring_length(yield);
   switch(item_type)
     {
     /* Call an ACL from an expansion.  We feed data in via $acl_arg1 - $acl_arg9.
@@ -4778,15 +4864,15 @@ while (*s)
 
       switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, flags, TRUE, name, &resetok, NULL))
         {
+       case -1: continue;      /* If skipping, we don't actually do anything */
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         case 3: goto EXPAND_FAILED;
         }
-      /*XXX no skipping-optimisation? */
 
       yield = string_append(yield, 3,
                        US"Authentication-Results: ", sub_arg[0], US"; none");
-      yield->ptr -= 6;
+      yield->ptr -= 6;                 /* ignore tha ": none" for now */
 
       yield = authres_local(yield, sub_arg[0]);
       yield = authres_iprev(yield);
@@ -4869,7 +4955,6 @@ while (*s)
         case 2:
         case 3: goto EXPAND_FAILED;
         }
-      /*XXX no skipping-optimisation? */
 
       if (!sub_arg[1])                 /* One argument */
        {
@@ -5364,15 +5449,12 @@ while (*s)
 
       switch(read_subs(sub_arg, 2, 1, &s, flags, TRUE, name, &resetok, NULL))
         {
+       case -1: continue;      /* If skipping, we don't actually do anything */
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         case 3: goto EXPAND_FAILED;
         }
 
-      /* If skipping, we don't actually do anything */
-
-      if (flags & ESI_SKIPPING) continue;
-
       /* Open the file and read it */
 
       if (!(f = Ufopen(sub_arg[0], "rb")))
@@ -5539,7 +5621,7 @@ while (*s)
       const uschar * arg, ** argv;
       BOOL late_expand = TRUE;
 
-      if ((expand_forbid & RDO_RUN) != 0)
+      if (expand_forbid & RDO_RUN)
         {
         expand_string_message = US"running a command is not permitted";
         goto EXPAND_FAILED;
@@ -5548,7 +5630,6 @@ while (*s)
       /* Handle options to the "run" */
 
       while (*s == ',')
-       {
        if (Ustrncmp(++s, "preexpand", 9) == 0)
          { late_expand = FALSE; s += 9; }
        else
@@ -5559,7 +5640,6 @@ while (*s)
                                                  (int)(t-s), s);
          goto EXPAND_FAILED;
          }
-       }
       Uskip_whitespace(&s);
 
       if (*s != '{')                                   /*}*/
@@ -5570,13 +5650,20 @@ while (*s)
       s++;
 
       if (late_expand)         /* this is the default case */
-       {                                               /*{*/
-       int n = Ustrcspn(s, "}");
+       {
+       int n;
+       const uschar * t;
+       /* Locate the end of the args */
+       (void) expand_string_internal(s,
+         ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | ESI_SKIPPING, &t, NULL, NULL);
+       n = t - s;
        arg = flags & ESI_SKIPPING ? NULL : string_copyn(s, n);
        s += n;
        }
       else
        {
+       DEBUG(D_expand)
+         debug_printf_indent("args string for ${run} expand before split\n");
        if (!(arg = expand_string_internal(s,
                ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL)))
          goto EXPAND_FAILED;
@@ -5700,7 +5787,7 @@ while (*s)
 
       if (o2m >= 0) for (; oldptr < yield->ptr; oldptr++)
         {
-        uschar *m = Ustrrchr(sub[1], yield->s[oldptr]);
+        uschar * m = Ustrrchr(sub[1], yield->s[oldptr]);
         if (m)
           {
           int o = m - sub[1];
@@ -6245,6 +6332,7 @@ while (*s)
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
       /* Read the field & list arguments */
+      /*XXX Could we use read_subs here (and get better efficiency for skipping)? */
 
       for (int i = 0; i < 2; i++)
         {
@@ -7021,7 +7109,7 @@ while (*s)
        it was for good reason */
 
        if (quoted) yield = string_catn(yield, US"\"", 1);
-       yield = string_catn(yield, g->s, g->ptr);
+       yield = gstring_append(yield, g);
        if (quoted) yield = string_catn(yield, US"\"", 1);
 
        /* @$original_domain */
@@ -7040,10 +7128,11 @@ while (*s)
     }  /* EITEM_* switch */
     /*NOTREACHED*/
 
-  DEBUG(D_expand)
-    if (yield && (start > 0 || *s))    /* only if not the sole expansion of the line */
+  DEBUG(D_expand)              /* only if not the sole expansion of the line */
+    if (yield && (expansion_start > 0 || *s))
       debug_expansion_interim(US"item-res",
-                             yield->s + start, yield->ptr - start, !!(flags & ESI_SKIPPING));
+         yield->s + expansion_start, yield->ptr - expansion_start,
+         !!(flags & ESI_SKIPPING));
   continue;
 
 NOT_ITEM: ;
@@ -7079,6 +7168,7 @@ NOT_ITEM: ;
 
     /* Deal specially with operators that might take a certificate variable
     as we do not want to do the usual expansion. For most, expand the string.*/
+
     switch(c)
       {
 #ifndef DISABLE_TLS
@@ -7127,16 +7217,16 @@ NOT_ITEM: ;
     to the main loop top. */
 
      {
-     int start = yield->ptr;
+     unsigned expansion_start = gstring_length(yield);
      switch(c)
       {
       case EOP_BASE32:
        {
-       uschar *t;
+       uschar * t;
        unsigned long int n = Ustrtoul(sub, &t, 10);
        gstring * g = NULL;
 
-       if (*t != 0)
+       if (*t)
          {
          expand_string_message = string_sprintf("argument for base32 "
            "operator is \"%s\", which is not a decimal number", sub);
@@ -7172,7 +7262,7 @@ NOT_ITEM: ;
        {
        uschar *t;
        unsigned long int n = Ustrtoul(sub, &t, 10);
-       if (*t != 0)
+       if (*t)
          {
          expand_string_message = string_sprintf("argument for base62 "
            "operator is \"%s\", which is not a decimal number", sub);
@@ -7188,7 +7278,7 @@ NOT_ITEM: ;
        {
        uschar *tt = sub;
        unsigned long int n = 0;
-       while (*tt != 0)
+       while (*tt)
          {
          uschar *t = Ustrchr(base62_chars, *tt++);
          if (!t)
@@ -7338,6 +7428,29 @@ NOT_ITEM: ;
        goto EXPAND_FAILED;
 #endif
 
+      /* Line-wrap a string as if it is a header line */
+
+      case EOP_HEADERWRAP:
+       {
+       unsigned col = 80, lim = 998;
+       uschar * s;
+
+       if (arg)
+         {
+         const uschar * list = arg;
+         int sep = '_';
+         if ((s = string_nextinlist(&list, &sep, NULL, 0)))
+           {
+           col = atoi(CS s);
+           if ((s = string_nextinlist(&list, &sep, NULL, 0)))
+             lim = atoi(CS s);
+           }
+         }
+         if ((s =  wrap_header(sub, col, lim, US"\t", 8)))
+           yield = string_cat(yield, s);
+       }
+       break;
+
       /* Convert hex encoding to base64 encoding */
 
       case EOP_HEX2B64:
@@ -7745,16 +7858,19 @@ NOT_ITEM: ;
 
        case EOP_UTF8CLEAN:
          {
-         int seq_len = 0, index = 0;
-         int bytes_left = 0;
+         int seq_len = 0, index = 0, bytes_left = 0, complete;
          long codepoint = -1;
-         int complete;
          uschar seq_buff[4];                   /* accumulate utf-8 here */
 
          /* Manually track tainting, as we deal in individual chars below */
 
-         if (!yield->s || !yield->ptr)
+         if (!yield)
+           yield = string_get_tainted(Ustrlen(sub), sub);
+         else if (!yield->s || !yield->ptr)
+           {
            yield->s = store_get(yield->size = Ustrlen(sub), sub);
+           gstring_reset(yield);
+           }
          else if (is_incompatible(yield->s, sub))
            gstring_rebuffer(yield, sub);
 
@@ -7880,7 +7996,7 @@ NOT_ITEM: ;
            goto EXPAND_FAILED;
            }
          yield = string_cat(yield, s);
-         DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s);
+         DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", string_from_gstring(yield));
          break;
          }
 
@@ -8189,8 +8305,9 @@ NOT_ITEM: ;
 
        DEBUG(D_expand)
        {
-       const uschar * s = yield->s + start;
-       int i = yield->ptr - start;
+       const uschar * res = string_from_gstring(yield);
+       const uschar * s = res + expansion_start;
+       int i = gstring_length(yield) - expansion_start;
        BOOL tainted = is_tainted(s);
 
        DEBUG(D_noutf8)
@@ -8199,7 +8316,7 @@ NOT_ITEM: ;
          if (tainted)
            {
            debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
-           debug_print_taint(yield->s);
+           debug_print_taint(res);
            }
          }
        else
@@ -8212,7 +8329,7 @@ NOT_ITEM: ;
            debug_printf_indent("%s",
              flags & ESI_SKIPPING
              ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
-           debug_print_taint(yield->s);
+           debug_print_taint(res);
            }
          }
        }
@@ -8287,58 +8404,62 @@ if (flags & ESI_BRACE_ENDS && !*s)
 added to the string. If so, set up an empty string. Add a terminating zero. If
 left != NULL, return a pointer to the terminator. */
 
-if (!yield)
-  yield = string_get(1);
-(void) string_from_gstring(yield);
-if (left) *left = s;
+ {
+  uschar * res;
 
-/* Any stacking store that was used above the final string is no longer needed.
-In many cases the final string will be the first one that was got and so there
-will be optimal store usage. */
+  if (!yield)
+    yield = string_get(1);
+  res = string_from_gstring(yield);
+  if (left) *left = s;
 
-if (resetok) gstring_release_unused(yield);
-else if (resetok_p) *resetok_p = FALSE;
+  /* Any stacking store that was used above the final string is no longer needed.
+  In many cases the final string will be the first one that was got and so there
+  will be optimal store usage. */
 
-DEBUG(D_expand)
-  {
-  BOOL tainted = is_tainted(yield->s);
-  DEBUG(D_noutf8)
+  if (resetok) gstring_release_unused(yield);
+  else if (resetok_p) *resetok_p = FALSE;
+
+  DEBUG(D_expand)
     {
-    debug_printf_indent("|--expanding: %.*s\n", (int)(s - string), string);
-    debug_printf_indent("%sresult: %s\n",
-      flags & ESI_SKIPPING ? "|-----" : "\\_____", yield->s);
-    if (tainted)
+    BOOL tainted = is_tainted(res);
+    DEBUG(D_noutf8)
       {
-      debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
-      debug_print_taint(yield->s);
+      debug_printf_indent("|--expanding: %.*s\n", (int)(s - string), string);
+      debug_printf_indent("%sresult: %s\n",
+       flags & ESI_SKIPPING ? "|-----" : "\\_____", res);
+      if (tainted)
+       {
+       debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
+       debug_print_taint(res);
+       }
+      if (flags & ESI_SKIPPING)
+       debug_printf_indent("\\___skipping: result is not used\n");
       }
-    if (flags & ESI_SKIPPING)
-      debug_printf_indent("\\___skipping: result is not used\n");
-    }
-  else
-    {
-    debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
-      "expanding: %.*s\n",
-      (int)(s - string), string);
-    debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
-      "result: %s\n",
-      flags & ESI_SKIPPING ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
-      yield->s);
-    if (tainted)
+    else
       {
-      debug_printf_indent("%s",
-       flags & ESI_SKIPPING
-       ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
-      debug_print_taint(yield->s);
+      debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
+       "expanding: %.*s\n",
+       (int)(s - string), string);
+      debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
+       "result: %s\n",
+       flags & ESI_SKIPPING ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
+       res);
+      if (tainted)
+       {
+       debug_printf_indent("%s",
+         flags & ESI_SKIPPING
+         ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
+       debug_print_taint(res);
+       }
+      if (flags & ESI_SKIPPING)
+       debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
+         "skipping: result is not used\n");
       }
-    if (flags & ESI_SKIPPING)
-      debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
-       "skipping: result is not used\n");
     }
-  }
-if (textonly_p) *textonly_p = textonly;
-expand_level--;
-return yield->s;
+  if (textonly_p) *textonly_p = textonly;
+  expand_level--;
+  return res;
+ }
 
 /* This is the failure exit: easiest to program with a goto. We still need
 to update the pointer to the terminator, for cases of nested calls with "fail".
@@ -8727,7 +8848,7 @@ for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i])
 #endif
 
 /* check known-name variables */
-for (var_entry * v = var_table; v < var_table + var_table_size; v++)
+for (var_entry * v = var_table; v < var_table + nelem(var_table); v++)
   if (v->type == vtype_stringptr)
     assert_variable_notin(US v->name, *(USS v->value), &e);
 
@@ -8861,8 +8982,9 @@ search_tidyup();
 return 0;
 }
 
-#endif
+#endif /*STAND_ALONE*/
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of expand.c */