]>
cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclenv.c
4 * Tcl support for environment variables, including a setenv_tcl
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.
18 static char rcsid
[] = "$Header: /user6/ouster/tcl/RCS/tclEnv.c,v 1.7 91/09/23 11:22:21 ouster Exp $ SPRITE (Berkeley)";
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
31 typedef struct EnvInterp
{
32 Tcl_Interp
*interp
; /* Interpreter for which we're managing
34 struct EnvInterp
*nextPtr
; /* Next in list of all such interpreters,
38 static EnvInterp
*firstInterpPtr
;
39 /* First in list of all managed interpreters,
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. */
51 * Declarations for local procedures defined in this file:
54 static void EnvInit
_ANSI_ARGS_((void));
55 static char * EnvTraceProc
_ANSI_ARGS_((ClientData clientData
,
56 Tcl_Interp
*interp
, char *name1
, char *name2
,
58 static int FindVariable
_ANSI_ARGS_((char *name
, int *lengthPtr
));
60 void setenv_tcl
_ANSI_ARGS_((char *name
, char *value
));
61 void unsetenv_tcl
_ANSI_ARGS_((char *name
));
65 *----------------------------------------------------------------------
69 * This procedure is invoked for an interpreter to make environment
70 * variables accessible from that interpreter via the "env"
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.
84 *----------------------------------------------------------------------
89 Tcl_Interp
*interp
/* Interpreter whose "env" array is to be
97 * First, initialize our environment-related information, if
101 if (environSize
== 0) {
106 * Next, add the interpreter to the list of those that we manage.
109 eiPtr
= (EnvInterp
*) ckalloc(sizeof(EnvInterp
));
110 eiPtr
->interp
= interp
;
111 eiPtr
->nextPtr
= firstInterpPtr
;
112 firstInterpPtr
= eiPtr
;
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.
120 (void) Tcl_UnsetVar2(interp
, "env", (char *) NULL
, TCL_GLOBAL_ONLY
);
128 for (p2
= p
; *p2
!= '='; p2
++) {
129 /* Empty loop body. */
132 (void) Tcl_SetVar2(interp
, "env", p
, p2
+1, TCL_GLOBAL_ONLY
);
135 Tcl_TraceVar2(interp
, "env", (char *) NULL
,
136 TCL_GLOBAL_ONLY
| TCL_TRACE_WRITES
| TCL_TRACE_UNSETS
,
137 EnvTraceProc
, (ClientData
) NULL
);
141 *----------------------------------------------------------------------
145 * Locate the entry in environ for a given name.
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
157 *----------------------------------------------------------------------
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
170 register char *p1
, *p2
;
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. */
176 if ((*p1
== '=') && (*p2
== '\0')) {
177 *lengthPtr
= p2
-name
;
186 *----------------------------------------------------------------------
190 * Set an environment variable, replacing an existing value
191 * or creating a new variable if there doesn't exist a variable
198 * The environ array gets updated, as do all of the interpreters
201 *----------------------------------------------------------------------
206 char *name
, /* Name of variable whose value is to be
208 char *value
/* New value for variable. */
211 int index
, length
, nameLength
;
215 if (environSize
== 0) {
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.
225 index
= FindVariable((char *)name
, &length
);
227 if ((length
+2) > environSize
) {
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;
239 environ
[index
+1] = NULL
;
240 nameLength
= strlen(name
);
242 ckfree(environ
[index
]);
247 * Create a new entry and enter it into the table.
250 p
= (char *) ckalloc((unsigned) (nameLength
+ strlen(value
) + 2));
258 * Update all of the interpreters.
261 for (eiPtr
= firstInterpPtr
; eiPtr
!= NULL
; eiPtr
= eiPtr
->nextPtr
) {
262 (void) Tcl_SetVar2(eiPtr
->interp
, "env", (char *)name
, p
+1, TCL_GLOBAL_ONLY
);
267 *----------------------------------------------------------------------
271 * Remove an environment variable, updating the "env" arrays
272 * in all interpreters managed by us.
278 * Interpreters are updated, as is environ.
280 *----------------------------------------------------------------------
285 char *name
/* Name of variable to remove. */
292 if (environSize
== 0) {
297 * Update the environ array.
300 index
= FindVariable((char *)name
, &dummy
);
304 ckfree(environ
[index
]);
305 for (envPtr
= environ
+index
+1; ; envPtr
++) {
306 envPtr
[-1] = *envPtr
;
307 if (*envPtr
== NULL
) {
313 * Update all of the interpreters.
316 for (eiPtr
= firstInterpPtr
; eiPtr
!= NULL
; eiPtr
= eiPtr
->nextPtr
) {
317 (void) Tcl_UnsetVar2(eiPtr
->interp
, "env", (char *)name
, TCL_GLOBAL_ONLY
);
322 *----------------------------------------------------------------------
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.
332 * Always returns NULL to indicate success.
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).
340 *----------------------------------------------------------------------
346 ClientData clientData
, /* Not used. */
347 Tcl_Interp
*interp
, /* Interpreter whose "env" variable is
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. */
356 * First see if the whole "env" variable is being deleted. If
357 * so, just forget about this interpreter.
361 register EnvInterp
*eiPtr
, *prevPtr
;
363 if ((flags
& (TCL_TRACE_UNSETS
|TCL_TRACE_DESTROYED
))
364 != (TCL_TRACE_UNSETS
|TCL_TRACE_DESTROYED
)) {
365 panic("EnvTraceProc called with confusing arguments");
367 eiPtr
= firstInterpPtr
;
368 if (eiPtr
->interp
== interp
) {
369 firstInterpPtr
= eiPtr
->nextPtr
;
371 for (prevPtr
= eiPtr
, eiPtr
= eiPtr
->nextPtr
; ;
372 prevPtr
= eiPtr
, eiPtr
= eiPtr
->nextPtr
) {
374 panic("EnvTraceProc couldn't find interpreter");
376 if (eiPtr
->interp
== interp
) {
377 prevPtr
->nextPtr
= eiPtr
->nextPtr
;
382 ckfree((char *) eiPtr
);
387 * If a value is being set, call setenv_tcl to do all of the work.
390 if (flags
& TCL_TRACE_WRITES
) {
391 setenv_tcl(name2
, Tcl_GetVar2(interp
, "env", name2
, TCL_GLOBAL_ONLY
));
394 if (flags
& TCL_TRACE_UNSETS
) {
401 *----------------------------------------------------------------------
405 * This procedure is called to initialize our management
406 * of the environ array.
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.
416 *----------------------------------------------------------------------
425 if (environSize
!= 0) {
428 for (length
= 0; environ
[length
] != NULL
; length
++) {
429 /* Empty loop body. */
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
]);
438 newEnviron
[length
] = NULL
;
439 environ
= newEnviron
;