[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / lib / posix / cbits / env.c
1 /*
2  * (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
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
15 #include "Rts.h"
16 #include "libposix.h"
17
18 /* Switch this on once we've moved the environment to the malloc arena */
19 int dirtyEnv = 0;
20
21 /* 
22  * For some reason, OSF turns off the prototype for this if we're
23  * _POSIX_SOURCE.  Seems to me that this ought to be an ANSI-ism
24  * rather than a POSIX-ism, but no matter.  (JSM(?))
25  */
26
27 char *
28 strDup(const char *src)
29 {
30     int len = strlen(src) + 1;
31     char *dst;
32
33     if ((dst = malloc(len)) != NULL)
34         memcpy(dst, src, len);
35     return dst;
36 }
37
38 /* Replace the entire environment */
39 int
40 setenviron(char **envp)
41 {
42     char **old = environ;
43     int dirtyOld = dirtyEnv;
44     int i;
45
46     /* A quick hack to move the strings out of the heap */
47     environ = envp;
48     if (copyenv() != 0) {
49         environ = old;
50         return -1;
51     }
52     /* Release the old space if we allocated it ourselves earlier */
53     if (dirtyOld) {
54         for (i = 0; old[i] != NULL; i++)
55             free(old[i]);
56         free(old);
57     }
58     return 0;
59 }
60
61 /* Copy initial environment into malloc arena */
62 int
63 copyenv(void)
64 {
65     char **new;
66     int i;
67
68     for (i = 0; environ[i] != NULL; i++)
69           ;
70
71     if ((new = (char **) malloc((i + 1) * sizeof(char *))) == NULL)
72          return -1;
73
74     new[i] = NULL;
75
76     while (--i >= 0) {
77         if ((new[i] = strDup(environ[i])) == NULL) {
78             while (new[++i] != NULL)
79                 free(new[i]);
80             free(new);
81             return -1;
82         }
83     }
84     environ = new;
85     dirtyEnv = 1;
86     return 0;
87 }
88
89 /* Set or replace an environment variable 
90  * simonm 14/2/96 - this is different to the standard C library 
91  * implementation and the prototypes clash, so I'm calling it _setenv.
92  */
93 int
94 _setenv(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         /* We want to grow the table by *two*, one for the new entry, one for the terminator */
122         if ((new = (char **) realloc((void*)environ, (i + 2) * sizeof(char *))) == NULL) {
123             free(p);
124             return -1;
125         }
126         new[i] = p;
127         new[i + 1] = NULL;
128         environ = new;
129     }
130     return 0;
131 }
132
133 /* Delete a variable from the environment */
134 int
135 delenv(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 }