[project @ 1998-02-02 17:27:26 by simonm]
[ghc-hetmet.git] / ghc / lib / posix / cbits / env.c
1 /*
2 %
3 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
4 %
5 \subsection[env.lc]{Environment Handling for LibPosix}
6
7 Many useful environment functions are not necessarily provided by libc.
8 To get around this problem, we introduce our own.  The first time that
9 you modify your environment, we copy the environment wholesale into
10 malloc'ed locations, so that subsequent modifications can do proper
11 memory management.  The $environ$ variable is updated with a pointer
12 to the current environment so that the normal $getenv$ and $exec*$ functions
13 should continue to work properly.
14
15 \begin{code}
16 */
17
18 #include "rtsdefs.h"
19 #include "libposix.h"
20
21 /* Switch this on once we've moved the environment to the malloc arena */
22 int dirtyEnv = 0;
23
24 /* 
25  * For some reason, OSF turns off the prototype for this if we're
26  * _POSIX_SOURCE.  Seems to me that this ought to be an ANSI-ism
27  * rather than a POSIX-ism, but no matter.  (JSM(?))
28  */
29
30 char *
31 strDup(const char *src)
32 {
33     int len = strlen(src) + 1;
34     char *dst;
35
36     if ((dst = malloc(len)) != NULL)
37         memcpy(dst, src, len);
38     return dst;
39 }
40
41 /* Replace the entire environment */
42 int
43 setenviron(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(void)
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(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(char *name)
137 {
138     int i, keylen;
139
140     if (strchr(name, '=') != NULL) {
141         errno = EINVAL;
142         return -1;
143     }
144     keylen = strlen(name);
145
146     if (!dirtyEnv && copyenv() != 0)
147         return -1;
148
149     /* Look for a matching key */
150     for (i = 0; environ[i] != NULL &&
151       (strncmp(environ[i], name, keylen) != 0 || environ[i][keylen] != '='); i++);
152
153     /* Don't complain if it wasn't there to begin with */
154     if (environ[i] == NULL) {
155         return 0;
156     }
157     free(environ[i]);
158
159     do {
160         environ[i] = environ[i + 1];
161         i++;
162     } while (environ[i] != NULL);
163
164     return 0;
165 }