+if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, GET_TAINTED);
+while ((item = string_nextinlist(&list, &sep, buffer, LISTNAMED_BUF_SIZE)))
+ {
+ uschar * buf = US" : ";
+ if (needsep)
+ yield = string_catn(yield, buf, 3);
+ else
+ needsep = TRUE;
+
+ if (*item == '+') /* list item is itself a named list */
+ {
+ yield = expand_listnamed(yield, item, listtype);
+ if (expand_string_message)
+ return yield;
+ }
+
+ else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */
+ {
+ char tok[3];
+ tok[0] = sep; tok[1] = ':'; tok[2] = 0;
+
+ for(char * cp; cp = strpbrk(CCS item, tok); item = US cp)
+ {
+ yield = string_catn(yield, item, cp - CS item);
+ if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
+ yield = string_catn(yield, US"::", 2);
+ else /* sep in item; should already be doubled; emit once */
+ {
+ yield = string_catn(yield, US tok, 1);
+ if (*cp == sep) cp++;
+ }
+ }
+ yield = string_cat(yield, item);
+ }
+ else
+ yield = string_cat(yield, item);
+ }
+return yield;
+}
+
+
+
+/************************************************/
+static void
+debug_expansion_interim(const uschar * what, const uschar * value, int nchar,
+ esi_flags flags)
+{
+debug_printf_indent("%V", "K");
+
+for (int fill = 11 - Ustrlen(what); fill > 0; fill--)
+ debug_printf("%V", "-");
+
+debug_printf("%s: %.*W\n", what, nchar, value);
+if (is_tainted(value))
+ debug_printf_indent("%V %V(tainted)\n",
+ flags & ESI_SKIPPING ? "|" : " ", "\\__");
+}
+
+
+/*************************************************
+* Expand string *
+*************************************************/
+
+/* Returns either an unchanged string, or the expanded string in stacking pool
+store. Interpreted sequences are:
+
+ \... normal escaping rules
+ $name substitutes the variable
+ ${name} ditto
+ ${op:string} operates on the expanded string value
+ ${item{arg1}{arg2}...} expands the args and then does the business
+ some literal args are not enclosed in {}
+
+There are now far too many operators and item types to make it worth listing
+them here in detail any more.
+
+We use an internal routine recursively to handle embedded substrings. The
+external function follows. The yield is NULL if the expansion failed, and there
+are two cases: if something collapsed syntactically, or if "fail" was given
+as the action on a lookup failure. These can be distinguished by looking at the
+variable expand_string_forcedfail, which is TRUE in the latter case.