summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2013-10-27 15:18:44 +0000
committerJeremy Harris <jgh146exb@wizmail.org>2013-12-22 17:38:14 +0000
commitaa26e1378803587c24924ad0055318959d597802 (patch)
treec861dec392e3e14c5e9fee59ea15f5a2d8ee8b4d /src
parentc5430c20d5c3b6fd293b96761ef850d6b301d791 (diff)
Add ${listextract {n}{list}...}
Diffstat (limited to 'src')
-rw-r--r--src/src/expand.c113
1 files changed, 112 insertions, 1 deletions
diff --git a/src/src/expand.c b/src/src/expand.c
index bf1f82c6f..325b05178 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -110,6 +110,7 @@ static uschar *item_table[] = {
US"hmac",
US"if",
US"length",
+ US"listextract",
US"lookup",
US"map",
US"nhash",
@@ -133,6 +134,7 @@ enum {
EITEM_HMAC,
EITEM_IF,
EITEM_LENGTH,
+ EITEM_LISTEXTRACT,
EITEM_LOOKUP,
EITEM_MAP,
EITEM_NHASH,
@@ -1131,6 +1133,22 @@ return fieldtext;
}
+static uschar *
+expand_getlistele (int field, uschar *list)
+{
+uschar * tlist= list;
+int sep= 0;
+uschar dummy;
+
+if(field<0)
+{
+ for(field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++;
+ sep= 0;
+}
+if(field==0) return NULL;
+while(--field>0 && (string_nextinlist(&list, &sep, &dummy, 1))) ;
+return string_nextinlist(&list, &sep, NULL, 0);
+}
/*************************************************
* Extract a substring from a string *
@@ -5149,7 +5167,7 @@ while (*s != 0)
for (i = 0; i < j; i++)
{
while (isspace(*s)) s++;
- if (*s == '{')
+ if (*s == '{') /*}*/
{
sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
if (sub[i] == NULL) goto EXPAND_FAILED; /*{*/
@@ -5230,6 +5248,99 @@ while (*s != 0)
continue;
}
+ /* return the Nth item from a list */
+
+ case EITEM_LISTEXTRACT:
+ {
+ int i;
+ int field_number = 1;
+ uschar *save_lookup_value = lookup_value;
+ uschar *sub[2];
+ int save_expand_nmax =
+ save_expand_strings(save_expand_nstring, save_expand_nlength);
+
+ /* Read the field & list arguments */
+
+ for (i = 0; i < 2; i++)
+ {
+ while (isspace(*s)) s++;
+ if (*s != '{') /*}*/
+ goto EXPAND_FAILED_CURLY;
+
+ sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ if (!sub[i]) goto EXPAND_FAILED; /*{*/
+ if (*s++ != '}') goto EXPAND_FAILED_CURLY;
+
+ /* After removal of leading and trailing white space, the first
+ argument must be numeric and nonempty. */
+
+ if (i == 0)
+ {
+ int len;
+ int x = 0;
+ uschar *p = sub[0];
+
+ while (isspace(*p)) p++;
+ sub[0] = p;
+
+ len = Ustrlen(p);
+ while (len > 0 && isspace(p[len-1])) len--;
+ p[len] = 0;
+
+ if (!*p && !skipping)
+ {
+ expand_string_message = US"first argument of \"listextract\" must "
+ "not be empty";
+ goto EXPAND_FAILED;
+ }
+
+ if (*p == '-')
+ {
+ field_number = -1;
+ p++;
+ }
+ while (*p && isdigit(*p)) x = x * 10 + *p++ - '0';
+ if (*p)
+ {
+ expand_string_message = US"first argument of \"listextract\" must "
+ "be numeric";
+ goto EXPAND_FAILED;
+ }
+ field_number *= x;
+ }
+ }
+
+ /* Extract the numbered element into $value. If
+ skipping, just pretend the extraction failed. */
+
+ lookup_value = skipping? NULL : expand_getlistele(field_number, sub[1]);
+
+ /* If no string follows, $value gets substituted; otherwise there can
+ be yes/no strings, as for lookup or if. */
+
+ switch(process_yesno(
+ skipping, /* were previously skipping */
+ lookup_value != NULL, /* success/failure indicator */
+ save_lookup_value, /* value to reset for string2 */
+ &s, /* input pointer */
+ &yield, /* output pointer */
+ &size, /* output size */
+ &ptr, /* output current point */
+ US"extract", /* condition type */
+ &resetok))
+ {
+ case 1: goto EXPAND_FAILED; /* when all is well, the */
+ case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
+ }
+
+ /* All done - restore numerical variables. */
+
+ restore_expand_strings(save_expand_nmax, save_expand_nstring,
+ save_expand_nlength);
+
+ continue;
+ }
+
/* Handle list operations */
case EITEM_FILTER: