summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-docbook/spec.xfpt24
-rw-r--r--doc/doc-txt/NewStuff2
-rw-r--r--src/src/expand.c49
-rw-r--r--test/scripts/0000-Basic/00025
-rw-r--r--test/stdout/00025
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 &<<SECTforexpfai>>&);
+{<&'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 {<variable>}} 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ò
>