|
|
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.