void TclSetupEnv( Tcl_Interp *interp) /* Interpreter whose "env" array is to be * managed. */ { Tcl_DString envString; char *p1, *p2; int i; /* * Synchronize the values in the environ array with the contents of the * Tcl "env" variable. To do this: * 1) Remove the trace that fires when the "env" var is unset. * 2) Unset the "env" variable. * 3) If there are no environ variables, create an empty "env" array. * Otherwise populate the array with current values. * 4) Add a trace that synchronizes the "env" array. */ Tcl_UntraceVar2(interp, "env", NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc, NULL); Tcl_UnsetVar2(interp, "env", NULL, TCL_GLOBAL_ONLY); if (environ[0] == NULL) { Tcl_Obj *varNamePtr; TclNewLiteralStringObj(varNamePtr, "env"); Tcl_IncrRefCount(varNamePtr); TclArraySet(interp, varNamePtr, NULL); Tcl_DecrRefCount(varNamePtr); } else { Tcl_MutexLock(&envMutex); for (i = 0; environ[i] != NULL; i++) { p1 = Tcl_ExternalToUtfDString(NULL, environ[i], -1, &envString); p2 = strchr(p1, '='); if (p2 == NULL) { /* * This condition seem to happen occasionally under some * versions of Solaris, or when encoding accidents swallow the * '='; ignore the entry. */ continue; } p2++; p2[-1] = '\0'; Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY); Tcl_DStringFree(&envString); } Tcl_MutexUnlock(&envMutex); } Tcl_TraceVar2(interp, "env", NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc, NULL); }
SEXP RTcl_RemoveArrayElem(SEXP args) { SEXP x, i; const char *xstr, *istr; const void *vmax = vmaxget(); x = CADR(args); i = CADDR(args); xstr = translateChar(STRING_ELT(x, 0)); istr = translateChar(STRING_ELT(i, 0)); Tcl_UnsetVar2(RTcl_interp, xstr, istr, 0); vmaxset(vmax); return R_NilValue; }
/* ARGSUSED */ static char * EnvTraceProc( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter whose "env" variable is being * modified. */ const char *name1, /* Better be "env". */ const char *name2, /* Name of variable being modified, or NULL if * whole array is being deleted (UTF-8). */ int flags) /* Indicates what's happening. */ { /* * For array traces, let TclSetupEnv do all the work. */ if (flags & TCL_TRACE_ARRAY) { TclSetupEnv(interp); return NULL; } /* * If name2 is NULL, then return and do nothing. */ if (name2 == NULL) { return NULL; } /* * If a value is being set, call TclSetEnv to do all of the work. */ if (flags & TCL_TRACE_WRITES) { const char *value; value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY); TclSetEnv(name2, value); } /* * If a value is being read, call TclGetEnv to do all of the work. */ if (flags & TCL_TRACE_READS) { Tcl_DString valueString; const char *value = TclGetEnv(name2, &valueString); if (value == NULL) { Tcl_UnsetVar2(interp, name1, name2, 0); return NULL; } Tcl_SetVar2(interp, name1, name2, value, 0); Tcl_DStringFree(&valueString); } /* * For unset traces, let TclUnsetEnv do all the work. */ if (flags & TCL_TRACE_UNSETS) { TclUnsetEnv(name2); } return NULL; }