Expansion item ${listquote }. Bug 1066
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 6 Apr 2020 15:20:35 +0000 (16:20 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 6 Apr 2020 15:20:35 +0000 (16:20 +0100)
doc/doc-txt/NewStuff
src/src/expand.c
test/scripts/0000-Basic/0002
test/stdout/0002

index 80d35254368413ee1e3023f84659794e53d224a1..f922f2cf4c226e27362f77e907eed96c5db8c0fd 100644 (file)
@@ -54,6 +54,8 @@ Version 4.94
 14. Options on pgsql and mysql lookups, to specify server separate from the
     lookup string.
 
 14. Options on pgsql and mysql lookups, to specify server separate from the
     lookup string.
 
+15. Expansion item ${listquote {<char} {<item>}}
+
 
 
 Version 4.93
 
 
 Version 4.93
index 789f09907f074e27ff65984337a56ef6f8665fc4..6d9a1695bd9e4e3c3769374b63e941689969b0a0 100644 (file)
@@ -117,6 +117,7 @@ static uschar *item_table[] = {
 #endif
   US"length",
   US"listextract",
 #endif
   US"length",
   US"listextract",
+  US"listquote",
   US"lookup",
   US"map",
   US"nhash",
   US"lookup",
   US"map",
   US"nhash",
@@ -151,6 +152,7 @@ enum {
 #endif
   EITEM_LENGTH,
   EITEM_LISTEXTRACT,
 #endif
   EITEM_LENGTH,
   EITEM_LISTEXTRACT,
+  EITEM_LISTQUOTE,
   EITEM_LOOKUP,
   EITEM_MAP,
   EITEM_NHASH,
   EITEM_LOOKUP,
   EITEM_MAP,
   EITEM_NHASH,
@@ -2744,7 +2746,7 @@ switch(cond_type = identify_operator(&s, &opname))
     if (*s++ != '{') goto COND_FAILED_CURLY_START;     /*}*/
 
     switch(read_subs(sub, nelem(sub), 1,
     if (*s++ != '{') goto COND_FAILED_CURLY_START;     /*}*/
 
     switch(read_subs(sub, nelem(sub), 1,
-      &s, yield == NULL, TRUE, US"acl", resetok))
+      &s, yield == NULL, TRUE, name, resetok))
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
         "error for acl";
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
         "error for acl";
@@ -2795,7 +2797,7 @@ switch(cond_type = identify_operator(&s, &opname))
     uschar *sub[4];
     while (isspace(*s)) s++;
     if (*s++ != '{') goto COND_FAILED_CURLY_START;     /* }-for-text-editors */
     uschar *sub[4];
     while (isspace(*s)) s++;
     if (*s++ != '{') goto COND_FAILED_CURLY_START;     /* }-for-text-editors */
-    switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, US"saslauthd",
+    switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, name,
                    resetok))
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
                    resetok))
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
@@ -3457,7 +3459,7 @@ switch(cond_type = identify_operator(&s, &opname))
     uschar cksum[4];
     BOOL boolvalue = FALSE;
 
     uschar cksum[4];
     BOOL boolvalue = FALSE;
 
-    switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, US"inbound_srs", resetok))
+    switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, name, resetok))
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
        "error for inbound_srs";
       {
       case 1: expand_string_message = US"too few arguments or bracketing "
        "error for inbound_srs";
@@ -4599,7 +4601,7 @@ while (*s != 0)
       uschar *user_msg;
       int rc;
 
       uschar *user_msg;
       int rc;
 
-      switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, US"acl",
+      switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name,
                      &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
                      &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
@@ -4980,7 +4982,7 @@ while (*s != 0)
         }
 
       switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, skipping, TRUE,
         }
 
       switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, skipping, TRUE,
-           US"perl", &resetok))
+           name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -5051,7 +5053,7 @@ while (*s != 0)
       uschar *sub_arg[3];
       uschar *p,*domain;
 
       uschar *sub_arg[3];
       uschar *p,*domain;
 
-      switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, US"prvs", &resetok))
+      switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -5125,7 +5127,7 @@ while (*s != 0)
       prvscheck_address = NULL;
       prvscheck_keynum = NULL;
 
       prvscheck_address = NULL;
       prvscheck_keynum = NULL;
 
-      switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs", &resetok))
+      switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -5157,7 +5159,7 @@ while (*s != 0)
         prvscheck_keynum = string_copy(key_num);
 
         /* Now expand the second argument */
         prvscheck_keynum = string_copy(key_num);
 
         /* Now expand the second argument */
-        switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs", &resetok))
+        switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok))
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
@@ -5211,7 +5213,7 @@ while (*s != 0)
         /* Now expand the final argument. We leave this till now so that
         it can include $prvscheck_result. */
 
         /* Now expand the final argument. We leave this till now so that
         it can include $prvscheck_result. */
 
-        switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, US"prvs", &resetok))
+        switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, name, &resetok))
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
@@ -5232,7 +5234,7 @@ while (*s != 0)
            We need to make sure all subs are expanded first, so as to skip over
            the entire item. */
 
            We need to make sure all subs are expanded first, so as to skip over
            the entire item. */
 
-        switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, US"prvs", &resetok))
+        switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok))
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
           {
           case 1: goto EXPAND_FAILED_CURLY;
           case 2:
@@ -5255,7 +5257,7 @@ while (*s != 0)
         goto EXPAND_FAILED;
         }
 
         goto EXPAND_FAILED;
         }
 
-      switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, US"readfile", &resetok))
+      switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -5305,7 +5307,7 @@ while (*s != 0)
       /* Read up to 4 arguments, but don't do the end of item check afterwards,
       because there may be a string for expansion on failure. */
 
       /* Read up to 4 arguments, but don't do the end of item check afterwards,
       because there may be a string for expansion on failure. */
 
-      switch(read_subs(sub_arg, 4, 2, &s, skipping, FALSE, US"readsocket", &resetok))
+      switch(read_subs(sub_arg, 4, 2, &s, skipping, FALSE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:                             /* Won't occur: no end check */
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:                             /* Won't occur: no end check */
@@ -5692,7 +5694,7 @@ while (*s != 0)
       int o2m;
       uschar *sub[3];
 
       int o2m;
       uschar *sub[3];
 
-      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, US"tr", &resetok))
+      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -5904,7 +5906,7 @@ while (*s != 0)
       int save_expand_nmax =
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
       int save_expand_nmax =
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
-      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, US"sg", &resetok))
+      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -6253,7 +6255,7 @@ while (*s != 0)
 
       for (int i = 0; i < 2; i++)
         {
 
       for (int i = 0; i < 2; i++)
         {
-        while (isspace(*s)) s++;
+        skip_whitespace(&s);
         if (*s != '{')                                 /*'}'*/
          {
          expand_string_message = string_sprintf(
         if (*s != '{')                                 /*'}'*/
          {
          expand_string_message = string_sprintf(
@@ -6338,6 +6340,23 @@ while (*s != 0)
       continue;
       }
 
       continue;
       }
 
+    case EITEM_LISTQUOTE:
+      {
+      uschar * sub[2];
+      switch(read_subs(sub, 2, 2, &s, skipping, TRUE, name, &resetok))
+        {
+        case 1: goto EXPAND_FAILED_CURLY;
+        case 2:
+        case 3: goto EXPAND_FAILED;
+        }
+      for (uschar sep = *sub[0], c; c = *sub[1]; sub[1]++)
+       {
+       if (c == sep) yield = string_catn(yield, sub[1], 1);
+       yield = string_catn(yield, sub[1], 1);
+       }
+      continue;
+      }
+
 #ifndef DISABLE_TLS
     case EITEM_CERTEXTRACT:
       {
 #ifndef DISABLE_TLS
     case EITEM_CERTEXTRACT:
       {
@@ -6347,7 +6366,7 @@ while (*s != 0)
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
       /* Read the field argument */
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
       /* Read the field argument */
-      while (isspace(*s)) s++;
+      skip_whitespace(&s);
       if (*s != '{')                                   /*}*/
        {
        expand_string_message = US"missing '{' for field arg of certextract";
       if (*s != '{')                                   /*}*/
        {
        expand_string_message = US"missing '{' for field arg of certextract";
@@ -6825,7 +6844,7 @@ while (*s != 0)
         }
 
       switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, skipping,
         }
 
       switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, skipping,
-           TRUE, US"dlfunc", &resetok))
+           TRUE, name, &resetok))
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
         {
         case 1: goto EXPAND_FAILED_CURLY;
         case 2:
@@ -7445,6 +7464,8 @@ while (*s != 0)
         continue;
        }
 
         continue;
        }
 
+      /* quote a list-item for the given list-separator */
+
       /* mask applies a mask to an IP address; for example the result of
       ${mask:131.111.10.206/28} is 131.111.10.192/28. */
 
       /* mask applies a mask to an IP address; for example the result of
       ${mask:131.111.10.206/28} is 131.111.10.192/28. */
 
index 2bf8f164e3f79ba5847527493fcb67e21403ce4f..db8d709811c1b4ba7e16ca10f3448552e9d49e24 100644 (file)
@@ -126,6 +126,14 @@ listextract: ${listextract{-5}{a:b:c:d}}
 listextract: ${listextract{ 5}{a:b:c:d}{}{fail}}
 listextract: ${listextract{ 5}{a:b:c:d}{}fail}
 
 listextract: ${listextract{ 5}{a:b:c:d}{}{fail}}
 listextract: ${listextract{ 5}{a:b:c:d}{}fail}
 
+listquote: ${listquote{:}{abcd}}
+listquote: ${listquote{:}{ab:cd}}
+listquote: ${listquote{:}{:a:b:c:d:}}
+listquote: ${listquote{:}{ab::cd}}
+listquote: ${listquote{;}{ab:cd}}
+listquote: ${listquote{;}{ab;cd}}
+listquote: ${listquote{ }{ ab cd}}
+
 sort: ${sort{3:2:1:4}{<}{$item}}
 sort: ${sort {<, 3,2,1,4}{>}{$item}}
 sort: ${sort{c:B:a:aa}{lti}{$item}}
 sort: ${sort{3:2:1:4}{<}{$item}}
 sort: ${sort {<, 3,2,1,4}{>}{$item}}
 sort: ${sort{c:B:a:aa}{lti}{$item}}
index 01e96fe78cffcc33f00567b58c777fcf47c06aa5..4345a09692ab24adbc12c9523bdbf23ebfa9aa4a 100644 (file)
 > listextract: fail
 > Failed: "listextract" failed and "fail" requested
 > 
 > listextract: fail
 > Failed: "listextract" failed and "fail" requested
 > 
+> listquote: abcd
+> listquote: ab::cd
+> listquote: ::a::b::c::d::
+> listquote: ab::::cd
+> listquote: ab:cd
+> listquote: ab;;cd
+> listquote:   ab  cd
+> 
 > sort: 1:2:3:4
 > sort: 4,3,2,1
 > sort: a:aa:B:c
 > sort: 1:2:3:4
 > sort: 4,3,2,1
 > sort: a:aa:B:c