[project @ 1996-01-11 14:06:51 by partain]
[ghc-hetmet.git] / ghc / runtime / io / env.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
3 %
4 \subsection[env.lc]{Environment Handling for LibPosix}
5
6 Many useful environment functions are not necessarily provided by libc.
7 To get around this problem, we introduce our own.  The first time that
8 you modify your environment, we copy the environment wholesale into
9 malloc'ed locations, so that subsequent modifications can do proper
10 memory management.  The $environ$ variable is updated with a pointer
11 to the current environment so that the normal $getenv$ and $exec*$ functions
12 should continue to work properly.
13
14 \begin{code}
15
16 #include "rtsdefs.h"
17 #include "stgio.h"
18 #include "libposix.h"
19
20 /* Switch this on once we've moved the environment to the malloc arena */
21 int dirtyEnv = 0;
22
23 /* 
24  * For some reason, OSF turns off the prototype for this if we're
25  * _POSIX_SOURCE.  Seems to me that this ought to be an ANSI-ism
26  * rather than a POSIX-ism, but no matter.  (JSM(?))
27  */
28
29 char *
30 strdup(char *src) /* should be "const char *" but then some
31                      bozo OS (e.g., AIX) will come along and disagree.
32                      The alt is to rename this routine (WDP 96/01) */
33 {
34     int len = strlen(src) + 1;
35     char *dst;
36
37     if ((dst = malloc(len)) != NULL)
38         memcpy(dst, src, len);
39     return dst;
40 }
41
42 /* Replace the entire environment */
43 int
44 setenviron(envp)
45 char **envp;
46 {
47     char **old = environ;
48     int dirtyOld = dirtyEnv;
49     int i;
50
51     /* A quick hack to move the strings out of the heap */
52     environ = envp;
53     if (copyenv() != 0) {
54         environ = old;
55         return -1;
56     }
57     /* Release the old space if we allocated it ourselves earlier */
58     if (dirtyOld) {
59         for (i = 0; old[i] != NULL; i++)
60             free(old[i]);
61         free(old);
62     }
63     return 0;
64 }
65
66 /* Copy initial environment into malloc arena */
67 int
68 copyenv()
69 {
70     char **new;
71     int i;
72
73     for (i = 0; environ[i] != NULL; i++);
74
75     if ((new = (char **) malloc((i + 1) * sizeof(char *))) == NULL)
76          return -1;
77
78     new[i] = NULL;
79
80     while (--i >= 0) {
81         if ((new[i] = strdup(environ[i])) == NULL) {
82             while (new[++i] != NULL)
83                 free(new[i]);
84             free(new);
85             return -1;
86         }
87     }
88     environ = new;
89     dirtyEnv = 1;
90     return 0;
91 }
92
93 /* Set or replace an environment variable */
94 int
95 setenv(mapping)
96 char *mapping;
97 {
98     int i, keylen;
99     char *p;
100     char **new;
101
102     /* We must have a non-empty key and an '=' */
103     if (mapping[0] == '=' || (p = strchr(mapping, '=')) == NULL) {
104         errno = EINVAL;
105         return -1;
106     }
107     /* Include through the '=' for matching */
108     keylen = p - mapping + 1;
109
110     if (!dirtyEnv && copyenv() != 0)
111         return -1;
112
113     if ((p = strdup(mapping)) == NULL)
114         return -1;
115
116     /* Look for an existing key that matches */
117     for (i = 0; environ[i] != NULL && strncmp(environ[i], p, keylen) != 0; i++);
118
119     if (environ[i] != NULL) {
120         free(environ[i]);
121         environ[i] = p;
122     } else {
123         if ((new = (char **) realloc(environ, (i + 1) * sizeof(char *))) == NULL) {
124             free(p);
125             return -1;
126         }
127         new[i] = p;
128         new[i + 1] = NULL;
129         environ = new;
130     }
131     return 0;
132 }
133
134 /* Delete a variable from the environment */
135 int
136 delenv(name)
137 char *name;
138 {
139     int i, keylen;
140
141     if (strchr(name, '=') != NULL) {
142         errno = EINVAL;
143         return -1;
144     }
145     keylen = strlen(name);
146
147     if (!dirtyEnv && copyenv() != 0)
148         return -1;
149
150     /* Look for a matching key */
151     for (i = 0; environ[i] != NULL &&
152       (strncmp(environ[i], name, keylen) != 0 || environ[i][keylen] != '='); i++);
153
154     /* Don't complain if it wasn't there to begin with */
155     if (environ[i] == NULL) {
156         return 0;
157     }
158     free(environ[i]);
159
160     do {
161         environ[i] = environ[i + 1];
162         i++;
163     } while (environ[i] != NULL);
164
165     return 0;
166 }
167
168 \end{code}