]> cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclenv.c
Fixes for compilation with gcc 15
[micropolis] / src / tcl / tclenv.c
1 /*
2 * tclEnv.c --
3 *
4 * Tcl support for environment variables, including a setenv_tcl
5 * procedure.
6 *
7 * Copyright 1991 Regents of the University of California
8 * Permission to use, copy, modify, and distribute this
9 * software and its documentation for any purpose and without
10 * fee is hereby granted, provided that this copyright
11 * notice appears in all copies. The University of California
12 * makes no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without
14 * express or implied warranty.
15 */
16
17 #ifndef lint
18 static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclEnv.c,v 1.7 91/09/23 11:22:21 ouster Exp $ SPRITE (Berkeley)";
19 #endif /* not lint */
20
21 #include "tclint.h"
22 #include "tclunix.h"
23
24 /*
25 * The structure below is used to keep track of all of the interpereters
26 * for which we're managing the "env" array. It's needed so that they
27 * can all be updated whenever an environment variable is changed
28 * anywhere.
29 */
30
31 typedef struct EnvInterp {
32 Tcl_Interp *interp; /* Interpreter for which we're managing
33 * the env array. */
34 struct EnvInterp *nextPtr; /* Next in list of all such interpreters,
35 * or zero. */
36 } EnvInterp;
37
38 static EnvInterp *firstInterpPtr;
39 /* First in list of all managed interpreters,
40 * or NULL if none. */
41
42 static int environSize = 0; /* Non-zero means that the all of the
43 * environ-related information is malloc-ed
44 * and the environ array itself has this
45 * many total entries allocated to it (not
46 * all may be in use at once). Zero means
47 * that the environment array is in its
48 * original static state. */
49
50 /*
51 * Declarations for local procedures defined in this file:
52 */
53
54 static void EnvInit _ANSI_ARGS_((void));
55 static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData,
56 Tcl_Interp *interp, char *name1, char *name2,
57 int flags));
58 static int FindVariable _ANSI_ARGS_((char *name, int *lengthPtr));
59
60 void setenv_tcl _ANSI_ARGS_((char *name, char *value));
61 void unsetenv_tcl _ANSI_ARGS_((char *name));
62
63 \f
64 /*
65 *----------------------------------------------------------------------
66 *
67 * TclSetupEnv --
68 *
69 * This procedure is invoked for an interpreter to make environment
70 * variables accessible from that interpreter via the "env"
71 * associative array.
72 *
73 * Results:
74 * None.
75 *
76 * Side effects:
77 * The interpreter is added to a list of interpreters managed
78 * by us, so that its view of envariables can be kept consistent
79 * with the view in other interpreters. If this is the first
80 * call to Tcl_SetupEnv, then additional initialization happens,
81 * such as copying the environment to dynamically-allocated space
82 * for ease of management.
83 *
84 *----------------------------------------------------------------------
85 */
86
87 void
88 TclSetupEnv (
89 Tcl_Interp *interp /* Interpreter whose "env" array is to be
90 * managed. */
91 )
92 {
93 EnvInterp *eiPtr;
94 int i;
95
96 /*
97 * First, initialize our environment-related information, if
98 * necessary.
99 */
100
101 if (environSize == 0) {
102 EnvInit();
103 }
104
105 /*
106 * Next, add the interpreter to the list of those that we manage.
107 */
108
109 eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
110 eiPtr->interp = interp;
111 eiPtr->nextPtr = firstInterpPtr;
112 firstInterpPtr = eiPtr;
113
114 /*
115 * Store the environment variable values into the interpreter's
116 * "env" array, and arrange for us to be notified on future
117 * writes and unsets to that array.
118 */
119
120 (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
121 for (i = 0; ; i++) {
122 char *p, *p2;
123
124 p = environ[i];
125 if (p == NULL) {
126 break;
127 }
128 for (p2 = p; *p2 != '='; p2++) {
129 /* Empty loop body. */
130 }
131 *p2 = 0;
132 (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY);
133 *p2 = '=';
134 }
135 Tcl_TraceVar2(interp, "env", (char *) NULL,
136 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
137 EnvTraceProc, (ClientData) NULL);
138 }
139 \f
140 /*
141 *----------------------------------------------------------------------
142 *
143 * FindVariable --
144 *
145 * Locate the entry in environ for a given name.
146 *
147 * Results:
148 * The return value is the index in environ of an entry with the
149 * name "name", or -1 if there is no such entry. The integer at
150 * *lengthPtr is filled in with the length of name (if a matching
151 * entry is found) or the length of the environ array (if no matching
152 * entry is found).
153 *
154 * Side effects:
155 * None.
156 *
157 *----------------------------------------------------------------------
158 */
159
160 static int
161 FindVariable (
162 char *name, /* Name of desired environment variable. */
163 int *lengthPtr /* Used to return length of name (for
164 * successful searches) or number of non-NULL
165 * entries in environ (for unsuccessful
166 * searches). */
167 )
168 {
169 int i;
170 register char *p1, *p2;
171
172 for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
173 for (p2 = name; *p2 == *p1; p1++, p2++) {
174 /* NULL loop body. */
175 }
176 if ((*p1 == '=') && (*p2 == '\0')) {
177 *lengthPtr = p2-name;
178 return i;
179 }
180 }
181 *lengthPtr = i;
182 return -1;
183 }
184 \f
185 /*
186 *----------------------------------------------------------------------
187 *
188 * setenv_tcl --
189 *
190 * Set an environment variable, replacing an existing value
191 * or creating a new variable if there doesn't exist a variable
192 * by the given name.
193 *
194 * Results:
195 * None.
196 *
197 * Side effects:
198 * The environ array gets updated, as do all of the interpreters
199 * that we manage.
200 *
201 *----------------------------------------------------------------------
202 */
203
204 void
205 setenv_tcl (
206 char *name, /* Name of variable whose value is to be
207 * set. */
208 char *value /* New value for variable. */
209 )
210 {
211 int index, length, nameLength;
212 char *p;
213 EnvInterp *eiPtr;
214
215 if (environSize == 0) {
216 EnvInit();
217 }
218
219 /*
220 * Figure out where the entry is going to go. If the name doesn't
221 * already exist, enlarge the array if necessary to make room. If
222 * the name exists, free its old entry.
223 */
224
225 index = FindVariable((char *)name, &length);
226 if (index == -1) {
227 if ((length+2) > environSize) {
228 char **newEnviron;
229
230 newEnviron = (char **) ckalloc((unsigned)
231 ((length+5) * sizeof(char *)));
232 memcpy((VOID *) newEnviron, (VOID *) environ,
233 length*sizeof(char *));
234 ckfree((char *) environ);
235 environ = newEnviron;
236 environSize = length+5;
237 }
238 index = length;
239 environ[index+1] = NULL;
240 nameLength = strlen(name);
241 } else {
242 ckfree(environ[index]);
243 nameLength = length;
244 }
245
246 /*
247 * Create a new entry and enter it into the table.
248 */
249
250 p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
251 environ[index] = p;
252 strcpy(p, name);
253 p += nameLength;
254 *p = '=';
255 strcpy(p+1, value);
256
257 /*
258 * Update all of the interpreters.
259 */
260
261 for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
262 (void) Tcl_SetVar2(eiPtr->interp, "env", (char *)name, p+1, TCL_GLOBAL_ONLY);
263 }
264 }
265 \f
266 /*
267 *----------------------------------------------------------------------
268 *
269 * unsetenv_tcl --
270 *
271 * Remove an environment variable, updating the "env" arrays
272 * in all interpreters managed by us.
273 *
274 * Results:
275 * None.
276 *
277 * Side effects:
278 * Interpreters are updated, as is environ.
279 *
280 *----------------------------------------------------------------------
281 */
282
283 void
284 unsetenv_tcl (
285 char *name /* Name of variable to remove. */
286 )
287 {
288 int index, dummy;
289 char **envPtr;
290 EnvInterp *eiPtr;
291
292 if (environSize == 0) {
293 EnvInit();
294 }
295
296 /*
297 * Update the environ array.
298 */
299
300 index = FindVariable((char *)name, &dummy);
301 if (index == -1) {
302 return;
303 }
304 ckfree(environ[index]);
305 for (envPtr = environ+index+1; ; envPtr++) {
306 envPtr[-1] = *envPtr;
307 if (*envPtr == NULL) {
308 break;
309 }
310 }
311
312 /*
313 * Update all of the interpreters.
314 */
315
316 for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
317 (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *)name, TCL_GLOBAL_ONLY);
318 }
319 }
320 \f
321 /*
322 *----------------------------------------------------------------------
323 *
324 * EnvTraceProc --
325 *
326 * This procedure is invoked whenever an environment variable
327 * is modified or deleted. It propagates the change to the
328 * "environ" array and to any other interpreters for whom
329 * we're managing an "env" array.
330 *
331 * Results:
332 * Always returns NULL to indicate success.
333 *
334 * Side effects:
335 * Environment variable changes get propagated. If the whole
336 * "env" array is deleted, then we stop managing things for
337 * this interpreter (usually this happens because the whole
338 * interpreter is being deleted).
339 *
340 *----------------------------------------------------------------------
341 */
342
343 /* ARGSUSED */
344 static char *
345 EnvTraceProc (
346 ClientData clientData, /* Not used. */
347 Tcl_Interp *interp, /* Interpreter whose "env" variable is
348 * being modified. */
349 char *name1, /* Better be "env". */
350 char *name2, /* Name of variable being modified, or
351 * NULL if whole array is being deleted. */
352 int flags /* Indicates what's happening. */
353 )
354 {
355 /*
356 * First see if the whole "env" variable is being deleted. If
357 * so, just forget about this interpreter.
358 */
359
360 if (name2 == NULL) {
361 register EnvInterp *eiPtr, *prevPtr;
362
363 if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
364 != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
365 panic("EnvTraceProc called with confusing arguments");
366 }
367 eiPtr = firstInterpPtr;
368 if (eiPtr->interp == interp) {
369 firstInterpPtr = eiPtr->nextPtr;
370 } else {
371 for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
372 prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
373 if (eiPtr == NULL) {
374 panic("EnvTraceProc couldn't find interpreter");
375 }
376 if (eiPtr->interp == interp) {
377 prevPtr->nextPtr = eiPtr->nextPtr;
378 break;
379 }
380 }
381 }
382 ckfree((char *) eiPtr);
383 return NULL;
384 }
385
386 /*
387 * If a value is being set, call setenv_tcl to do all of the work.
388 */
389
390 if (flags & TCL_TRACE_WRITES) {
391 setenv_tcl(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY));
392 }
393
394 if (flags & TCL_TRACE_UNSETS) {
395 unsetenv_tcl(name2);
396 }
397 return NULL;
398 }
399 \f
400 /*
401 *----------------------------------------------------------------------
402 *
403 * EnvInit --
404 *
405 * This procedure is called to initialize our management
406 * of the environ array.
407 *
408 * Results:
409 * None.
410 *
411 * Side effects:
412 * Environ gets copied to malloc-ed storage, so that in
413 * the future we don't have to worry about which entries
414 * are malloc-ed and which are static.
415 *
416 *----------------------------------------------------------------------
417 */
418
419 static void
420 EnvInit (void)
421 {
422 char **newEnviron;
423 int i, length;
424
425 if (environSize != 0) {
426 return;
427 }
428 for (length = 0; environ[length] != NULL; length++) {
429 /* Empty loop body. */
430 }
431 environSize = length+5;
432 newEnviron = (char **) ckalloc((unsigned)
433 (environSize * sizeof(char *)));
434 for (i = 0; i < length; i++) {
435 newEnviron[i] = (char *) ckalloc((unsigned) (strlen(environ[i]) + 1));
436 strcpy(newEnviron[i], environ[i]);
437 }
438 newEnviron[length] = NULL;
439 environ = newEnviron;
440 }
Impressum, Datenschutz