--- /dev/null
+/*
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
+%
+\subsection[env.lc]{Environment Handling for LibPosix}
+
+Many useful environment functions are not necessarily provided by libc.
+To get around this problem, we introduce our own. The first time that
+you modify your environment, we copy the environment wholesale into
+malloc'ed locations, so that subsequent modifications can do proper
+memory management. The $environ$ variable is updated with a pointer
+to the current environment so that the normal $getenv$ and $exec*$ functions
+should continue to work properly.
+
+\begin{code}
+*/
+
+#include "rtsdefs.h"
+#include "libposix.h"
+
+/* Switch this on once we've moved the environment to the malloc arena */
+int dirtyEnv = 0;
+
+/*
+ * For some reason, OSF turns off the prototype for this if we're
+ * _POSIX_SOURCE. Seems to me that this ought to be an ANSI-ism
+ * rather than a POSIX-ism, but no matter. (JSM(?))
+ */
+
+char *
+strDup(const char *src)
+{
+ int len = strlen(src) + 1;
+ char *dst;
+
+ if ((dst = malloc(len)) != NULL)
+ memcpy(dst, src, len);
+ return dst;
+}
+
+/* Replace the entire environment */
+int
+setenviron(char **envp)
+{
+ char **old = environ;
+ int dirtyOld = dirtyEnv;
+ int i;
+
+ /* A quick hack to move the strings out of the heap */
+ environ = envp;
+ if (copyenv() != 0) {
+ environ = old;
+ return -1;
+ }
+ /* Release the old space if we allocated it ourselves earlier */
+ if (dirtyOld) {
+ for (i = 0; old[i] != NULL; i++)
+ free(old[i]);
+ free(old);
+ }
+ return 0;
+}
+
+/* Copy initial environment into malloc arena */
+int
+copyenv(void)
+{
+ char **new;
+ int i;
+
+ for (i = 0; environ[i] != NULL; i++);
+
+ if ((new = (char **) malloc((i + 1) * sizeof(char *))) == NULL)
+ return -1;
+
+ new[i] = NULL;
+
+ while (--i >= 0) {
+ if ((new[i] = strDup(environ[i])) == NULL) {
+ while (new[++i] != NULL)
+ free(new[i]);
+ free(new);
+ return -1;
+ }
+ }
+ environ = new;
+ dirtyEnv = 1;
+ return 0;
+}
+
+/* Set or replace an environment variable
+ * simonm 14/2/96 - this is different to the standard C library
+ * implementation and the prototypes clash, so I'm calling it _setenv.
+ */
+int
+_setenv(char *mapping)
+{
+ int i, keylen;
+ char *p;
+ char **new;
+
+ /* We must have a non-empty key and an '=' */
+ if (mapping[0] == '=' || (p = strchr(mapping, '=')) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ /* Include through the '=' for matching */
+ keylen = p - mapping + 1;
+
+ if (!dirtyEnv && copyenv() != 0)
+ return -1;
+
+ if ((p = strDup(mapping)) == NULL)
+ return -1;
+
+ /* Look for an existing key that matches */
+ for (i = 0; environ[i] != NULL && strncmp(environ[i], p, keylen) != 0; i++);
+
+ if (environ[i] != NULL) {
+ free(environ[i]);
+ environ[i] = p;
+ } else {
+ if ((new = (char **) realloc(environ, (i + 1) * sizeof(char *))) == NULL) {
+ free(p);
+ return -1;
+ }
+ new[i] = p;
+ new[i + 1] = NULL;
+ environ = new;
+ }
+ return 0;
+}
+
+/* Delete a variable from the environment */
+int
+delenv(char *name)
+{
+ int i, keylen;
+
+ if (strchr(name, '=') != NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ keylen = strlen(name);
+
+ if (!dirtyEnv && copyenv() != 0)
+ return -1;
+
+ /* Look for a matching key */
+ for (i = 0; environ[i] != NULL &&
+ (strncmp(environ[i], name, keylen) != 0 || environ[i][keylen] != '='); i++);
+
+ /* Don't complain if it wasn't there to begin with */
+ if (environ[i] == NULL) {
+ return 0;
+ }
+ free(environ[i]);
+
+ do {
+ environ[i] = environ[i + 1];
+ i++;
+ } while (environ[i] != NULL);
+
+ return 0;
+}