summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib.c15
-rw-r--r--lib.h1
-rw-r--r--stdlib/doc-syms.tl1
-rw-r--r--sysif.c35
-rw-r--r--sysif.h1
-rw-r--r--txr.145
6 files changed, 98 insertions, 0 deletions
diff --git a/lib.c b/lib.c
index 534013eb..cf2d6cf8 100644
--- a/lib.c
+++ b/lib.c
@@ -4293,6 +4293,21 @@ char *chk_strdup_utf8(const char *str)
return copy;
}
+char *chk_substrdup_utf8(const char *str, size_t off, size_t len)
+{
+ size_t size = strlen(str) + 1, nchar;
+ char *copy;
+ if (off >= size - 1)
+ return chk_strdup_utf8("");
+ if (off + len < off)
+ uw_throw(error_s, lit("string size overflow"));
+ nchar = min(size - off, len + 1);
+ copy = coerce(char *, chk_malloc(nchar));
+ memcpy(copy, str, nchar - 1);
+ copy[nchar - 1] = 0;
+ return copy;
+}
+
unsigned char *chk_strdup_8bit(const wchar_t *str)
{
size_t nchar = wcslen(str) + 1, i;
diff --git a/lib.h b/lib.h
index f5b5ed42..25cfc6d1 100644
--- a/lib.h
+++ b/lib.h
@@ -735,6 +735,7 @@ wchar_t *chk_wrealloc(wchar_t *, size_t nwchar);
wchar_t *chk_strdup(const wchar_t *str);
wchar_t *chk_substrdup(const wchar_t *str, size_t off, size_t len);
char *chk_strdup_utf8(const char *str);
+char *chk_substrdup_utf8(const char *str, size_t off, size_t len);
unsigned char *chk_strdup_8bit(const wchar_t *str);
mem_t *chk_copy_obj(mem_t *orig, size_t size);
mem_t *chk_xalloc(ucnum m, ucnum n, val self);
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index c9fcf582..9cc7068e 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -1584,6 +1584,7 @@
("repeat" "D-006A")
("replace" "N-035991E1")
("replace-buf" "N-01C59E4E")
+ ("replace-env" "N-03C59E3B")
("replace-list" "N-03E43DA2")
("replace-str" "N-02059F0A")
("replace-struct" "N-01A8343B")
diff --git a/sysif.c b/sysif.c
index 2c8bc6b0..d1fefdce 100644
--- a/sysif.c
+++ b/sysif.c
@@ -336,6 +336,40 @@ val env(void)
}
}
+val replace_env(val env_list)
+{
+#if HAVE_ENVIRON && HAVE_SETENV
+ val self = lit("replace-env");
+ extern char **environ;
+ val iter;
+ static char *empty_env[1];
+
+ environ = empty_env;
+
+ for (iter = env_list; iter; iter = cdr(iter)) {
+ const wchar_t *pair = c_str(car(iter), self);
+ char *pair8 = utf8_dup_to(pair);
+ char *eq = strchr(pair8, '=');
+ int res;
+ if (eq != 0) {
+ char *name = chk_substrdup_utf8(pair8, 0, eq - pair8);
+ res = setenv(name, eq + 1, 1);
+ free(name);
+ } else {
+ res = setenv(pair8, "", 1);
+ }
+ free(pair8);
+ if (res < 0)
+ uw_ethrowf(system_error_s, lit("~a: setenv failed: ~d/~s"),
+ self, num(errno), errno_to_str(errno), nao);
+ }
+
+ return env_list;
+#else
+ uw_throwf(error_s, lit("environ mechanism not available"), nao);
+#endif
+}
+
static val get_env_hash(void)
{
if (env_hash) {
@@ -2703,6 +2737,7 @@ void sysif_init(void)
#endif
reg_fun(intern(lit("env"), user_package), func_n0(env));
+ reg_fun(intern(lit("replace-env"), user_package), func_n1(replace_env));
reg_fun(intern(lit("env-hash"), user_package), func_n0(get_env_hash));
#if HAVE_DAEMON
diff --git a/sysif.h b/sysif.h
index 1001368d..6dc150e2 100644
--- a/sysif.h
+++ b/sysif.h
@@ -38,6 +38,7 @@ extern val path_s;
val errno_to_file_error(int err);
val env(void);
+val replace_env(val env_list);
val getenv_wrap(val name);
val errno_to_str(int err);
val at_exit_call(val func);
diff --git a/txr.1 b/txr.1
index a48a881c..dc8b6cf0 100644
--- a/txr.1
+++ b/txr.1
@@ -66049,6 +66049,51 @@ The
function accesses the underlying environment and updates the hash
table with the name-value pair which is retrieved.
+.coNP Function @ replace-env
+.synb
+.mets (replace-env << env-list )
+.syne
+.desc
+The
+.code replace-env
+function replaces the environment with the environment variables specified in
+.metn env-list .
+The argument is a list of character strings, in the same format
+as the list returned by the
+.code env
+function: each element of the list describes an environment variable
+as a single character string in which the name is separated by the
+value by the
+.code =
+character. As a special concession, if this character is missing, the
+.code replace-env
+function treats that entry as being a name with an empty value.
+
+The
+.code replace-env
+first empties the existing environment, rendering it devoid of environment
+variables. Then it installs the entries specified in
+.metn env-list .
+
+The return value is
+.metn env-list .
+
+Note:
+.code replace-env
+may be used to specify an exact environment to child programs executed
+by functions like
+.codn open-process ,
+.code sh
+or
+.codn run .
+
+Note: the previous environment may be saved by calling
+.code env
+and retaining the returned list. Then after modifying the environment,
+the original environment can be restored by passing that retained
+list to
+.codn replace-env .
+
.SS* Command-Line-Option Processing
\*(TL provides a support for recognizing, extracting and validating