diff options
-rw-r--r-- | doc/doc-docbook/spec.xfpt | 29 | ||||
-rw-r--r-- | doc/doc-txt/ChangeLog | 2 | ||||
-rw-r--r-- | doc/doc-txt/NewStuff | 4 | ||||
-rw-r--r-- | src/src/expand.c | 44 | ||||
-rw-r--r-- | test/scripts/0000-Basic/0002 | 28 | ||||
-rw-r--r-- | test/stdout/0002 | 20 |
6 files changed, 64 insertions, 63 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 7c0a400d2..675d3f956 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -9567,6 +9567,7 @@ environments where Exim uses base 36 instead of base 62 for its message identifiers, base-36 digits. The number is converted to decimal and output as a string. + .vitem &*${domain:*&<&'string'&>&*}*& .cindex "domain" "extraction" .cindex "expansion" "domain extraction" @@ -9726,17 +9727,17 @@ See the description of the general &%length%& item above for details. Note that when &%length%& is used as an operator. -.vitem &*${local_part:*&<&'string'&>&*}*& -.cindex "expansion" "local part extraction" -.cindex "&%local_part%& expansion item" -The string is interpreted as an RFC 2822 address and the local part is -extracted from it. If the string does not parse successfully, the result is -empty. +.vitem &*${listcount:*&<&'string'&>&*}*& +.cindex "expansion" "list item count" +.cindex "list" "item count" +.cindex "list" "count of items" +.cindex "&%listcount%& expansion item" +The string is interpreted as a list and the number of items is returned. -.vitem &*${list:*&<&'name'&>&*}*&&~and&~&*${list_*&<&'type'&>&*name'&>&*}*& +.vitem &*${listnamed:*&<&'name'&>&*}*&&~and&~&*${list_*&<&'type'&>&*name'&>&*}*& .cindex "expansion" "named list" -.cindex "&%list%& expansion item" +.cindex "&%listnamed%& expansion item" The name is interpreted as a named list and the content of the list is returned, expanding any referenced lists, re-quoting as needed for colon-separation. If the optional type if given it must be one of "a", "d", "h" or "l" @@ -9745,12 +9746,12 @@ Otherwise all types are searched in an undefined order and the first matching list is returned. -.vitem &*${nlist:*&<&'string'&>&*}*& -.cindex "expansion" "list item count" -.cindex "list" "item count" -.cindex "list" "count of items" -.cindex "&%nlist%& expansion item" -The string is interpreted as a list and the number of items is returned. +.vitem &*${local_part:*&<&'string'&>&*}*& +.cindex "expansion" "local part extraction" +.cindex "&%local_part%& expansion item" +The string is interpreted as an RFC 2822 address and the local part is +extracted from it. If the string does not parse successfully, the result is +empty. .vitem &*${mask:*&<&'IP&~address'&>&*/*&<&'bit&~count'&>&*}*& diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index af6080985..1bf2cd06b 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -39,7 +39,7 @@ JH/02 Support "G" suffix to numbers in ${if comparisons. PP/08 Handle smtp transport tls_sni option forced-fail for OpenSSL. -JH/03 Add expansion operators ${list:name} and ${nlist:string} +JH/03 Add expansion operators ${listnamed:name} and ${listcount:string} Exim version 4.80 diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 64c1c14b7..6d64faa00 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -84,8 +84,8 @@ Version 4.81 Not yet supported: IGNOREQUOTA, SIZE, PIPELINING, AUTH. - 8. New expansion operators ${list:name} to get the content of a named list - and ${nlist:string} to count the items in a list. + 8. New expansion operators ${listnamed:name} to get the content of a named list + and ${listcount:string} to count the items in a list. Version 4.80 ------------ diff --git a/src/src/expand.c b/src/src/expand.c index 2a9e6b4fc..965842611 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -182,12 +182,12 @@ static uschar *op_table_main[] = { US"l", US"lc", US"length", - US"list", + US"listcount", + US"listnamed", US"mask", US"md5", US"nh", US"nhash", - US"nlist", US"quote", US"randint", US"rfc2047", @@ -217,12 +217,12 @@ enum { EOP_L, EOP_LC, EOP_LENGTH, - EOP_LIST, + EOP_LISTCOUNT, + EOP_LISTNAMED, EOP_MASK, EOP_MD5, EOP_NH, EOP_NHASH, - EOP_NLIST, EOP_QUOTE, EOP_RANDINT, EOP_RFC2047, @@ -5474,10 +5474,25 @@ while (*s != 0) continue; } + /* count the number of list elements */ + + case EOP_LISTCOUNT: + { + int cnt = 0; + int sep = 0; + uschar * cp; + uschar buffer[256]; + + while (string_nextinlist(&sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++; + cp = string_sprintf("%d", cnt); + yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp)); + continue; + } + /* expand a named list given the name */ - /* handles nested named lists but will confuse the separators in the result */ + /* handles nested named lists; requotes as colon-sep list */ - case EOP_LIST: + case EOP_LISTNAMED: { tree_node *t = NULL; uschar * list; @@ -5531,7 +5546,7 @@ while (*s != 0) if (*item == '+') /* list item is itself a named list */ { - uschar * sub = string_sprintf("${list%s:%s}", suffix, item); + uschar * sub = string_sprintf("${listnamed%s:%s}", suffix, item); item = expand_string_internal(sub, FALSE, NULL, FALSE, TRUE); } else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */ @@ -5560,21 +5575,6 @@ while (*s != 0) continue; } - /* count the number of list elements */ - - case EOP_NLIST: - { - int cnt = 0; - int sep = 0; - uschar * cp; - uschar buffer[256]; - - while (string_nextinlist(&sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++; - cp = string_sprintf("%d", cnt); - yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp)); - continue; - } - /* 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. */ diff --git a/test/scripts/0000-Basic/0002 b/test/scripts/0000-Basic/0002 index 41e0d0064..652891615 100644 --- a/test/scripts/0000-Basic/0002 +++ b/test/scripts/0000-Basic/0002 @@ -60,20 +60,20 @@ reduce: ${reduce{a:b:c}{+}{$value$item}} reduce: ${reduce {<, 1,2,3}{0}{${eval:$value+$item}}} reduce: ${reduce {3:0:9:4:6}{0}{${if >{$item}{$value}{$item}{$value}}}} -list: ${list:dlist} -list: ${list:+dlist} -list: ${list:hlist} -list: ${list:elist} -list: ${list:flist} -list: ${list:nolist} -list: ${list_d:dlist} -list: ${list_d:hlist} -list: ${list_z:dlist} - -nlist: ${nlist:a:b:c} -nlist: ${nlist:} -nlist: ${nlist:<;a;b;c} -nlist: ${nlist:${list:dlist}} +listnamed: ${listnamed:dlist} +listnamed: ${listnamed:+dlist} +listnamed: ${listnamed:hlist} +listnamed: ${listnamed:elist} +listnamed: ${listnamed:flist} +listnamed: ${listnamed:nolist} +listnamed: ${listnamed_d:dlist} +listnamed: ${listnamed_d:hlist} +listnamed: ${listnamed_z:dlist} + +listcount: ${listcount:a:b:c} +listcount: ${listcount:} +listcount: ${listcount:<;a;b;c} +listcount: ${listcount:${listnamed:dlist}} # Tests with iscntrl() and illegal separators diff --git a/test/stdout/0002 b/test/stdout/0002 index a7c876229..de67f99fc 100644 --- a/test/stdout/0002 +++ b/test/stdout/0002 @@ -49,20 +49,20 @@ > reduce: 6 > reduce: 9 > -> list: *.aa.bb : ^\Nxxx(.*) -> list: *.aa.bb : ^\Nxxx(.*) -> list: V4NET.11.12.13 : iplsearch;TESTSUITE/aux-fixed/0002.iplsearch -> list: *.aa.bb : ^\Nxxx(.*) : ;; -> list: a : b;c : *.aa.bb : ^\Nxxx(.*) : ;; : 2001::630::212::8::204::::b664 +> listnamed: *.aa.bb : ^\Nxxx(.*) +> listnamed: *.aa.bb : ^\Nxxx(.*) +> listnamed: V4NET.11.12.13 : iplsearch;TESTSUITE/aux-fixed/0002.iplsearch +> listnamed: *.aa.bb : ^\Nxxx(.*) : ;; +> listnamed: a : b;c : *.aa.bb : ^\Nxxx(.*) : ;; : 2001::630::212::8::204::::b664 > Failed: "nolist" is not a named list -> list: *.aa.bb : ^\Nxxx(.*) +> listnamed: *.aa.bb : ^\Nxxx(.*) > Failed: "hlist" is not a domain named list > Failed: bad suffix on "list" operator > -> nlist: 3 -> nlist: 0 -> nlist: 3 -> nlist: 2 +> listcount: 3 +> listcount: 0 +> listcount: 3 +> listcount: 2 > > # Tests with iscntrl() and illegal separators > |