[project @ 1996-06-27 16:13:29 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(const char *src)
31 {
32     int len = strlen(src) + 1;
33     char *dst;
34
35     if ((dst = malloc(len)) != NULL)
36         memcpy(dst, src, len);
37     return dst;
38 }
39
40 /* Replace the entire environment */
41 int
42 setenviron(envp)
43 char **envp;
44 {
45     char **old = environ;
46     int dirtyOld = dirtyEnv;
47     int i;
48
49     /* A quick hack to move the strings out of the heap */
50     environ = envp;
51     if (copyenv() != 0) {
52         environ = old;
53         return -1;
54     }
55     /* Release the old space if we allocated it ourselves earlier */
56     if (dirtyOld) {
57         for (i = 0; old[i] != NULL; i++)
58             free(old[i]);
59         free(old);
60     }
61     return 0;
62 }
63
64 /* Copy initial environment into malloc arena */
65 int
66 copyenv()
67 {
68     char **new;
69     int i;
70
71     for (i = 0; environ[i] != NULL; i++);
72
73     if ((new = (char **) malloc((i + 1) * sizeof(char *))) == NULL)
74          return -1;
75
76     new[i] = NULL;
77
78     while (--i >= 0) {
79         if ((new[i] = strDup(environ[i])) == NULL) {
80             while (new[++i] != NULL)
81                 free(new[i]);
82             free(new);
83             return -1;
84         }
85     }
86     environ = new;
87     dirtyEnv = 1;
88     return 0;
89 }
90
91 /* Set or replace an environment variable 
92  * simonm 14/2/96 - this is different to the standard C library 
93  * implementation and the prototypes clash, so I'm calling it _setenv.
94  */
95 int
96 _setenv(mapping)
97 char *mapping;
98 {
99     int i, keylen;
100     char *p;
101     char **new;
102
103     /* We must have a non-empty key and an '=' */
104     if (mapping[0] == '=' || (p = strchr(mapping, '=')) == NULL) {
105         errno = EINVAL;
106         return -1;
107     }
108     /* Include through the '=' for matching */
109     keylen = p - mapping + 1;
110
111     if (!dirtyEnv && copyenv() != 0)
112         return -1;
113
114     if ((p = strDup(mapping)) == NULL)
115         return -1;
116
117     /* Look for an existing key that matches */
118     for (i = 0; environ[i] != NULL && strncmp(environ[i], p, keylen) != 0; i++);
119
120     if (environ[i] != NULL) {
121         free(environ[i]);
122         environ[i] = p;
123     } else {
124         if ((new = (char **) realloc(environ, (i + 1) * sizeof(char *))) == NULL) {
125             free(p);
126             return -1;
127         }
128         new[i] = p;
129         new[i + 1] = NULL;
130         environ = new;
131     }
132     return 0;
133 }
134
135 /* Delete a variable from the environment */
136 int
137 delenv(name)
138 char *name;
139 {
140     int i, keylen;
141
142     if (strchr(name, '=') != NULL) {
143         errno = EINVAL;
144         return -1;
145     }
146     keylen = strlen(name);
147
148     if (!dirtyEnv && copyenv() != 0)
149         return -1;
150
151     /* Look for a matching key */
152     for (i = 0; environ[i] != NULL &&
153       (strncmp(environ[i], name, keylen) != 0 || environ[i][keylen] != '='); i++);
154
155     /* Don't complain if it wasn't there to begin with */
156     if (environ[i] == NULL) {
157         return 0;
158     }
159     free(environ[i]);
160
161     do {
162         environ[i] = environ[i + 1];
163         i++;
164     } while (environ[i] != NULL);
165
166     return 0;
167 }
168
169 \end{code}