|
|
1.1 root 1: /*
2: * tclEnv.c --
3: *
4: * Tcl support for environment variables, including a setenv
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: #ifdef IS_LINUX
61: int setenv _ANSI_ARGS_((const char *name, const char *value, int replace));
62: int unsetenv _ANSI_ARGS_((const char *name));
63: #else
64: void setenv _ANSI_ARGS_((char *name, char *value));
65: void unsetenv _ANSI_ARGS_((char *name));
66: #endif
67:
68:
69: /*
70: *----------------------------------------------------------------------
71: *
72: * TclSetupEnv --
73: *
74: * This procedure is invoked for an interpreter to make environment
75: * variables accessible from that interpreter via the "env"
76: * associative array.
77: *
78: * Results:
79: * None.
80: *
81: * Side effects:
82: * The interpreter is added to a list of interpreters managed
83: * by us, so that its view of envariables can be kept consistent
84: * with the view in other interpreters. If this is the first
85: * call to Tcl_SetupEnv, then additional initialization happens,
86: * such as copying the environment to dynamically-allocated space
87: * for ease of management.
88: *
89: *----------------------------------------------------------------------
90: */
91:
92: void
93: TclSetupEnv(interp)
94: Tcl_Interp *interp; /* Interpreter whose "env" array is to be
95: * managed. */
96: {
97: EnvInterp *eiPtr;
98: int i;
99:
100: /*
101: * First, initialize our environment-related information, if
102: * necessary.
103: */
104:
105: if (environSize == 0) {
106: EnvInit();
107: }
108:
109: /*
110: * Next, add the interpreter to the list of those that we manage.
111: */
112:
113: eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
114: eiPtr->interp = interp;
115: eiPtr->nextPtr = firstInterpPtr;
116: firstInterpPtr = eiPtr;
117:
118: /*
119: * Store the environment variable values into the interpreter's
120: * "env" array, and arrange for us to be notified on future
121: * writes and unsets to that array.
122: */
123:
124: (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
125: for (i = 0; ; i++) {
126: char *p, *p2;
127:
128: p = environ[i];
129: if (p == NULL) {
130: break;
131: }
132: for (p2 = p; *p2 != '='; p2++) {
133: /* Empty loop body. */
134: }
135: *p2 = 0;
136: (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY);
137: *p2 = '=';
138: }
139: Tcl_TraceVar2(interp, "env", (char *) NULL,
140: TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
141: EnvTraceProc, (ClientData) NULL);
142: }
143:
144: /*
145: *----------------------------------------------------------------------
146: *
147: * FindVariable --
148: *
149: * Locate the entry in environ for a given name.
150: *
151: * Results:
152: * The return value is the index in environ of an entry with the
153: * name "name", or -1 if there is no such entry. The integer at
154: * *lengthPtr is filled in with the length of name (if a matching
155: * entry is found) or the length of the environ array (if no matching
156: * entry is found).
157: *
158: * Side effects:
159: * None.
160: *
161: *----------------------------------------------------------------------
162: */
163:
164: static int
165: FindVariable(name, lengthPtr)
166: char *name; /* Name of desired environment variable. */
167: int *lengthPtr; /* Used to return length of name (for
168: * successful searches) or number of non-NULL
169: * entries in environ (for unsuccessful
170: * searches). */
171: {
172: int i;
173: register char *p1, *p2;
174:
175: for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
176: for (p2 = name; *p2 == *p1; p1++, p2++) {
177: /* NULL loop body. */
178: }
179: if ((*p1 == '=') && (*p2 == '\0')) {
180: *lengthPtr = p2-name;
181: return i;
182: }
183: }
184: *lengthPtr = i;
185: return -1;
186: }
187:
188: /*
189: *----------------------------------------------------------------------
190: *
191: * setenv --
192: *
193: * Set an environment variable, replacing an existing value
194: * or creating a new variable if there doesn't exist a variable
195: * by the given name.
196: *
197: * Results:
198: * None.
199: *
200: * Side effects:
201: * The environ array gets updated, as do all of the interpreters
202: * that we manage.
203: *
204: *----------------------------------------------------------------------
205: */
206:
207: #ifdef IS_LINUX
208: int
209: setenv(name, value, replace)
210: const char *name; /* Name of variable whose value is to be
211: * set. */
212: const char *value; /* New value for variable. */
213: int replace;
214: #else
215: void
216: setenv(name, value)
217: char *name; /* Name of variable whose value is to be
218: * set. */
219: char *value; /* New value for variable. */
220: #endif
221: {
222: int index, length, nameLength;
223: char *p;
224: EnvInterp *eiPtr;
225:
226: if (environSize == 0) {
227: EnvInit();
228: }
229:
230: /*
231: * Figure out where the entry is going to go. If the name doesn't
232: * already exist, enlarge the array if necessary to make room. If
233: * the name exists, free its old entry.
234: */
235:
236: index = FindVariable((char *)name, &length);
237: if (index == -1) {
238: if ((length+2) > environSize) {
239: char **newEnviron;
240:
241: newEnviron = (char **) ckalloc((unsigned)
242: ((length+5) * sizeof(char *)));
243: memcpy((VOID *) newEnviron, (VOID *) environ,
244: length*sizeof(char *));
245: ckfree((char *) environ);
246: environ = newEnviron;
247: environSize = length+5;
248: }
249: index = length;
250: environ[index+1] = NULL;
251: nameLength = strlen(name);
252: } else {
253: ckfree(environ[index]);
254: nameLength = length;
255: }
256:
257: /*
258: * Create a new entry and enter it into the table.
259: */
260:
261: p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
262: environ[index] = p;
263: strcpy(p, name);
264: p += nameLength;
265: *p = '=';
266: strcpy(p+1, value);
267:
268: /*
269: * Update all of the interpreters.
270: */
271:
272: for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
273: (void) Tcl_SetVar2(eiPtr->interp, "env", (char *)name, p+1, TCL_GLOBAL_ONLY);
274: }
275:
276: #ifdef IS_LINUX
277: return 0;
278: #endif
279:
280: }
281:
282: /*
283: *----------------------------------------------------------------------
284: *
285: * unsetenv --
286: *
287: * Remove an environment variable, updating the "env" arrays
288: * in all interpreters managed by us.
289: *
290: * Results:
291: * None.
292: *
293: * Side effects:
294: * Interpreters are updated, as is environ.
295: *
296: *----------------------------------------------------------------------
297: */
298:
299: int
300: unsetenv(name)
301: #ifdef IS_LINUX
302: const char *name; /* Name of variable to remove. */
303: #else
304: char *name; /* Name of variable to remove. */
305: #endif
306: {
307: int index, dummy;
308: char **envPtr;
309: EnvInterp *eiPtr;
310:
311: if (environSize == 0) {
312: EnvInit();
313: }
314:
315: /*
316: * Update the environ array.
317: */
318:
319: index = FindVariable((char *)name, &dummy);
320: if (index == -1) {
321: return;
322: }
323: ckfree(environ[index]);
324: for (envPtr = environ+index+1; ; envPtr++) {
325: envPtr[-1] = *envPtr;
326: if (*envPtr == NULL) {
327: break;
328: }
329: }
330:
331: /*
332: * Update all of the interpreters.
333: */
334:
335: for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
336: (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *)name, TCL_GLOBAL_ONLY);
337: }
338: }
339:
340: /*
341: *----------------------------------------------------------------------
342: *
343: * EnvTraceProc --
344: *
345: * This procedure is invoked whenever an environment variable
346: * is modified or deleted. It propagates the change to the
347: * "environ" array and to any other interpreters for whom
348: * we're managing an "env" array.
349: *
350: * Results:
351: * Always returns NULL to indicate success.
352: *
353: * Side effects:
354: * Environment variable changes get propagated. If the whole
355: * "env" array is deleted, then we stop managing things for
356: * this interpreter (usually this happens because the whole
357: * interpreter is being deleted).
358: *
359: *----------------------------------------------------------------------
360: */
361:
362: /* ARGSUSED */
363: static char *
364: EnvTraceProc(clientData, interp, name1, name2, flags)
365: ClientData clientData; /* Not used. */
366: Tcl_Interp *interp; /* Interpreter whose "env" variable is
367: * being modified. */
368: char *name1; /* Better be "env". */
369: char *name2; /* Name of variable being modified, or
370: * NULL if whole array is being deleted. */
371: int flags; /* Indicates what's happening. */
372: {
373: /*
374: * First see if the whole "env" variable is being deleted. If
375: * so, just forget about this interpreter.
376: */
377:
378: if (name2 == NULL) {
379: register EnvInterp *eiPtr, *prevPtr;
380:
381: if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
382: != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
383: panic("EnvTraceProc called with confusing arguments");
384: }
385: eiPtr = firstInterpPtr;
386: if (eiPtr->interp == interp) {
387: firstInterpPtr = eiPtr->nextPtr;
388: } else {
389: for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
390: prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
391: if (eiPtr == NULL) {
392: panic("EnvTraceProc couldn't find interpreter");
393: }
394: if (eiPtr->interp == interp) {
395: prevPtr->nextPtr = eiPtr->nextPtr;
396: break;
397: }
398: }
399: }
400: ckfree((char *) eiPtr);
401: return NULL;
402: }
403:
404: /*
405: * If a value is being set, call setenv to do all of the work.
406: */
407:
408: if (flags & TCL_TRACE_WRITES) {
409: setenv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY), 0);
410: }
411:
412: if (flags & TCL_TRACE_UNSETS) {
413: unsetenv(name2);
414: }
415: return NULL;
416: }
417:
418: /*
419: *----------------------------------------------------------------------
420: *
421: * EnvInit --
422: *
423: * This procedure is called to initialize our management
424: * of the environ array.
425: *
426: * Results:
427: * None.
428: *
429: * Side effects:
430: * Environ gets copied to malloc-ed storage, so that in
431: * the future we don't have to worry about which entries
432: * are malloc-ed and which are static.
433: *
434: *----------------------------------------------------------------------
435: */
436:
437: static void
438: EnvInit()
439: {
440: char **newEnviron;
441: int i, length;
442:
443: if (environSize != 0) {
444: return;
445: }
446: for (length = 0; environ[length] != NULL; length++) {
447: /* Empty loop body. */
448: }
449: environSize = length+5;
450: newEnviron = (char **) ckalloc((unsigned)
451: (environSize * sizeof(char *)));
452: for (i = 0; i < length; i++) {
453: newEnviron[i] = (char *) ckalloc((unsigned) (strlen(environ[i]) + 1));
454: strcpy(newEnviron[i], environ[i]);
455: }
456: newEnviron[length] = NULL;
457: environ = newEnviron;
458: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.