Macros: speedup expansion processing
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 14 Feb 2018 14:08:08 +0000 (14:08 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 14 Feb 2018 14:08:08 +0000 (14:08 +0000)
doc/doc-txt/ChangeLog
src/src/exim.c
src/src/globals.c
src/src/globals.h
src/src/readconf.c

index 6dd768c8a7492b4bb559bdbb6b945694e32c6b10..370e1b7e73e1e1e71fad91afa515a91b6554f50b 100644 (file)
@@ -99,6 +99,10 @@ JH/17 Bug 2113: Fix conversation closedown with the Avast malware scanner.
 JH/18 Bug 2239: Enforce non-usability of control=utf8_downconvert in the mail
       ACL.  Previously, a crash would result.
 
+JH/19 Speed up macro lookups during configuration file read, by skipping non-
+      macro text after a replacement (previously it was only once per line) and
+      by skipping builtin macros when searching for an uppercase lead character.
+
 
 Exim version 4.90
 -----------------
index 327a8ecfe096af4c6ab3e37c0a2265049975b48f..fe1b1c19d5ca551a4c939f1c42da1a893934c789 100644 (file)
@@ -1372,7 +1372,7 @@ whites[i] = NULL;
 
 /* The list of commandline macros should be very short.
 Accept the N*M complexity. */
-for (m = macros; m; m = m->next) if (m->command_line)
+for (m = macros_user; m; m = m->next) if (m->command_line)
   {
   found = FALSE;
   for (w = whites; *w; ++w)
@@ -2422,14 +2422,14 @@ for (i = 1; i < argc; i++)
         while (isspace(*s)) s++;
         }
 
-      for (m = macros; m; m = m->next)
+      for (m = macros_user; m; m = m->next)
         if (Ustrcmp(m->name, name) == 0)
           {
           fprintf(stderr, "exim: duplicated -D in command line\n");
           exit(EXIT_FAILURE);
           }
 
-      m = macro_create(string_copy(name), string_copy(s), TRUE);
+      m = macro_create(name, s, TRUE);
 
       if (clmacro_count >= MAX_CLMACROS)
         {
@@ -4988,7 +4988,7 @@ if (expansion_test)
 
   /* Only admin users may see config-file macros this way */
 
-  if (!admin_user) macros = mlast = NULL;
+  if (!admin_user) macros_user = macros = mlast = NULL;
 
   /* Allow $recipients for this testing */
 
index 762e889d1b3389a35daf9c7c53d949c316eb0de0..bcc2a7a320b84cb8db938af5e147493ae2efbe3b 100644 (file)
@@ -953,6 +953,7 @@ uschar *lookup_dnssec_authenticated = NULL;
 int     lookup_open_max        = 25;
 uschar *lookup_value           = NULL;
 
+macro_item *macros_user        = NULL;
 uschar *mailstore_basename     = NULL;
 #ifdef WITH_CONTENT_SCAN
 uschar *malware_name           = NULL;  /* Virus Name */
index 766b8a42f6c8f2f3e68ef983bb2a804c6343811e..d6bc96a83f8a5e8c11be9db8422ddd921833686c 100644 (file)
@@ -566,6 +566,7 @@ extern int     lookup_open_max;        /* Max lookup files to cache */
 extern uschar *lookup_value;           /* Value looked up from file */
 
 extern macro_item *macros;             /* Configuration macros */
+extern macro_item *macros_user;        /* Non-builtin configuration macros */
 extern macro_item *mlast;              /* Last item in macro list */
 extern uschar *mailstore_basename;     /* For mailstore deliveries */
 #ifdef WITH_CONTENT_SCAN
index 5d519e9968df2e8c4cb77b95a800bb2de8e7a69d..cbbef6efdca0f75de7b74da6079481271bf986de 100644 (file)
@@ -599,8 +599,8 @@ return US"";
 /* We have a new definition; append to the list.
 
 Args:
- name  Name of the macro.  Must be in storage persistent past the call
- val   Expansion result for the macro.  Ditto persistence.
+ name  Name of the macro; will be copied
+ val   Expansion result for the macro; will be copied
 */
 
 macro_item *
@@ -613,13 +613,15 @@ m->next = NULL;
 m->command_line = command_line;
 m->namelen = Ustrlen(name);
 m->replen = Ustrlen(val);
-m->name = name;
-m->replacement = val;
+m->name = string_copy(name);
+m->replacement = string_copy(val);
 if (mlast)
   mlast->next = m;
 else
   macros = m;
 mlast = m;
+if (!macros_user)
+  macros_user = m;
 return m;
 }
 
@@ -731,7 +733,7 @@ if (redef)
 
 /* We have a new definition. */
 else
-  (void) macro_create(string_copy(name), string_copy(s), FALSE);
+  (void) macro_create(name, s, FALSE);
 return TRUE;
 }
 
@@ -741,7 +743,7 @@ return TRUE;
 
 /* Process line for macros. The line is in big_buffer starting at offset len.
 Expand big_buffer if needed.  Handle definitions of new macros, and
-imacro expansions, rewriting the line in thw buffer.
+macro expansions, rewriting the line in the buffer.
 
 Arguments:
  len           Offset in buffer of start of line
@@ -780,17 +782,21 @@ if (len == 0 && isupper(*s))
 /* Skip leading chars which cannot start a macro name, to avoid multiple
 pointless rescans in Ustrstr calls. */
 
-while (*s && !isupper(*s) && *s != '_') s++;
+while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++;
 
 /* For each defined macro, scan the line (from after XXX= if present),
 replacing all occurrences of the macro. */
 
 *macro_found = FALSE;
-for (m = macros; m; m = m->next)
+if (*s) for (m = *s == '_' ? macros : macros_user; m; m = m->next)
   {
   uschar * p, *pp;
-  uschar * t = s;
+  uschar * t;
+
+  while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++;
+  if (!*s) break;
 
+  t = s;
   while ((p = Ustrstr(t, m->name)) != NULL)
     {
     int moveby;
@@ -824,7 +830,7 @@ for (m = macros; m; m = m->next)
       }
     Ustrncpy(p, m->replacement, m->replen);
     t = p + m->replen;
-    while (*t && !isupper(*t) && *t != '_') t++;
+    while (*t && !isupper(*t) && !(*t == '_' && isupper(t[1]))) t++;
     *macro_found = TRUE;
     }
   }