From 089fc87a02b0c682ace3afc2f597f5e5b3b8f076 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 23 May 2015 21:48:26 +0100 Subject: [PATCH] New ${env {NAME}} expansion. Bug 1604 --- doc/doc-docbook/spec.xfpt | 24 ++++++++++++++++++ doc/doc-txt/NewStuff | 2 ++ src/src/expand.c | 49 ++++++++++++++++++++++++++++++------ test/scripts/0000-Basic/0002 | 5 ++++ test/stdout/0002 | 5 ++++ 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 752712181..a598ec08b 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -9031,6 +9031,30 @@ When compiling a function that is to be used in this way with gcc, you need to add &%-shared%& to the gcc command. Also, in the Exim build-time configuration, you must add &%-export-dynamic%& to EXTRALIBS. + +.vitem "&*${env{*&<&'key'&>&*}{*&<&'string1'&>&*}{*&<&'string2'&>&*}}*&" +.cindex "expansion" "extracting value from environment" +.cindex "environment" "value from" +The key is first expanded separately, and leading and trailing white space +removed. +This is then searched for as a name in the environment. +If a variable is found then its value is placed in &$value$& +and <&'string1'&> is expanded, otherwise <&'string2'&> is expanded. + +Instead of {<&'string2'&>} the word &"fail"& (not in curly brackets) can +appear, for example: +.code +${env{USER}{$value} fail } +.endd +This forces an expansion failure (see section &<>&); +{<&'string1'&>} must be present for &"fail"& to be recognized. + +If {<&'string2'&>} is omitted an empty string is substituted on +search failure. +If {<&'string1'&>} is omitted the search result is substituted on +search success. + + .vitem "&*${extract{*&<&'key'&>&*}{*&<&'string1'&>&*}{*&<&'string2'&>&*}&&& {*&<&'string3'&>&*}}*&" .cindex "expansion" "extracting substrings by key" diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index aa60f46f1..3fe332556 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -33,6 +33,8 @@ Version 4.86 10. A logging option for slow DNS lookups, +11. New ${env {}} expansion. + Version 4.85 ------------ diff --git a/src/src/expand.c b/src/src/expand.c index b4e2a5a83..7660e9aa4 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -105,6 +105,7 @@ static uschar *item_table[] = { US"acl", US"certextract", US"dlfunc", + US"env", US"extract", US"filter", US"hash", @@ -134,6 +135,7 @@ enum { EITEM_ACL, EITEM_CERTEXTRACT, EITEM_DLFUNC, + EITEM_ENV, EITEM_EXTRACT, EITEM_FILTER, EITEM_HASH, @@ -4001,7 +4003,8 @@ while (*s != 0) uschar *sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */ uschar *user_msg; - switch(read_subs(sub, 10, 1, &s, skipping, TRUE, US"acl", &resetok)) + switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, US"acl", + &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5859,12 +5862,12 @@ while (*s != 0) #define EXPAND_DLFUNC_MAX_ARGS 8 case EITEM_DLFUNC: - #ifndef EXPAND_DLFUNC - expand_string_message = US"\"${dlfunc\" encountered, but this facility " /*}*/ - "is not included in this binary"; - goto EXPAND_FAILED; +#ifndef EXPAND_DLFUNC + expand_string_message = US"\"${dlfunc\" encountered, but this facility " /*}*/ + "is not included in this binary"; + goto EXPAND_FAILED; - #else /* EXPAND_DLFUNC */ +#else /* EXPAND_DLFUNC */ { tree_node *t; exim_dlfunc_t *func; @@ -5950,7 +5953,39 @@ while (*s != 0) goto EXPAND_FAILED; } } - #endif /* EXPAND_DLFUNC */ +#endif /* EXPAND_DLFUNC */ + + case EITEM_ENV: /* ${env {name} {val_if_found} {val_if_unfound}} */ + { + uschar * key; + uschar *save_lookup_value = lookup_value; + + while (isspace(*s)) s++; + if (*s != '{') /*}*/ + goto EXPAND_FAILED; + + key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); + if (!key) goto EXPAND_FAILED; /*{*/ + if (*s++ != '}') goto EXPAND_FAILED_CURLY; + + lookup_value = US getenv(CS key); + + 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"env", /* condition type */ + &resetok)) + { + case 1: goto EXPAND_FAILED; /* when all is well, the */ + case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */ + } + continue; + } } /* EITEM_* switch */ /* Control reaches here if the name is not recognized as one of the more diff --git a/test/scripts/0000-Basic/0002 b/test/scripts/0000-Basic/0002 index acb308324..9afb556a3 100644 --- a/test/scripts/0000-Basic/0002 +++ b/test/scripts/0000-Basic/0002 @@ -827,6 +827,11 @@ ${if forany{a:b:c}\ ${if ={1}{1} {true}{${if ={1}{1} {true}{${if ={1}{1}{true}fail}}}}} +# Environment access + +${env {USER}} +${env {NO_SUCH_VARIABLE} {oops, success} {correct}} + **** # Test "escape" with print_topbitchars exim -be -DPTBC=print_topbitchars diff --git a/test/stdout/0002 b/test/stdout/0002 index d145e7ec3..9a3219d59 100644 --- a/test/stdout/0002 +++ b/test/stdout/0002 @@ -778,6 +778,11 @@ xyz > > true > +> # Environment access +> +> CALLER +> correct +> > > escape: B7·F2ò > -- 2.30.2