[project @ 1996-01-08 20:28:12 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 _POSIX_SOURCE.
25  * Seems to me that this ought to be an ANSI-ism rather than a POSIX-ism,
26  * but no matter.
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 int
93 setenv(mapping)
94 char *mapping;
95 {
96     int i, keylen;
97     char *p;
98     char **new;
99
100     /* We must have a non-empty key and an '=' */
101     if (mapping[0] == '=' || (p = strchr(mapping, '=')) == NULL) {
102         errno = EINVAL;
103         return -1;
104     }
105     /* Include through the '=' for matching */
106     keylen = p - mapping + 1;
107
108     if (!dirtyEnv && copyenv() != 0)
109         return -1;
110
111     if ((p = strdup(mapping)) == NULL)
112         return -1;
113
114     /* Look for an existing key that matches */
115     for (i = 0; environ[i] != NULL && strncmp(environ[i], p, keylen) != 0; i++);
116
117     if (environ[i] != NULL) {
118         free(environ[i]);
119         environ[i] = p;
120     } else {
121         if ((new = (char **) realloc(environ, (i + 1) * sizeof(char *))) == NULL) {
122             free(p);
123             return -1;
124         }
125         new[i] = p;
126         new[i + 1] = NULL;
127         environ = new;
128     }
129     return 0;
130 }
131
132 /* Delete a variable from the environment */
133 int
134 delenv(name)
135 char *name;
136 {
137     int i, keylen;
138
139     if (strchr(name, '=') != NULL) {
140         errno = EINVAL;
141         return -1;
142     }
143     keylen = strlen(name);
144
145     if (!dirtyEnv && copyenv() != 0)
146         return -1;
147
148     /* Look for a matching key */
149     for (i = 0; environ[i] != NULL &&
150       (strncmp(environ[i], name, keylen) != 0 || environ[i][keylen] != '='); i++);
151
152     /* Don't complain if it wasn't there to begin with */
153     if (environ[i] == NULL) {
154         return 0;
155     }
156     free(environ[i]);
157
158     do {
159         environ[i] = environ[i + 1];
160         i++;
161     } while (environ[i] != NULL);
162
163     return 0;
164 }
165
166 \end{code}