OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclEnv.c] - Diff between revs 578 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 578 Rev 1765
/*
/*
 * tclEnv.c --
 * tclEnv.c --
 *
 *
 *      Tcl support for environment variables, including a setenv
 *      Tcl support for environment variables, including a setenv
 *      procedure.  This file contains the generic portion of the
 *      procedure.  This file contains the generic portion of the
 *      environment module.  It is primarily responsible for keeping
 *      environment module.  It is primarily responsible for keeping
 *      the "env" arrays in sync with the system environment variables.
 *      the "env" arrays in sync with the system environment variables.
 *
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
 *
 *
 * See the file "license.terms" for information on usage and redistribution
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 *
 * RCS: @(#) $Id: tclEnv.c,v 1.1.1.1 2002-01-16 10:25:26 markom Exp $
 * RCS: @(#) $Id: tclEnv.c,v 1.1.1.1 2002-01-16 10:25:26 markom Exp $
 */
 */
 
 
#include "tclInt.h"
#include "tclInt.h"
#include "tclPort.h"
#include "tclPort.h"
 
 
/* CYGNUS LOCAL */
/* CYGNUS LOCAL */
#if defined(__CYGWIN__) && defined(__WIN32__)
#if defined(__CYGWIN__) && defined(__WIN32__)
 
 
/* Under cygwin, the environment is imported from the cygwin DLL.  */
/* Under cygwin, the environment is imported from the cygwin DLL.  */
 
 
extern char ***_imp____cygwin_environ;
extern char ***_imp____cygwin_environ;
 
 
#define environ (*_imp____cygwin_environ)
#define environ (*_imp____cygwin_environ)
 
 
/* We need to use a special putenv function to handle PATH.  */
/* We need to use a special putenv function to handle PATH.  */
#ifndef USE_PUTENV
#ifndef USE_PUTENV
#define USE_PUTENV
#define USE_PUTENV
#endif
#endif
#define putenv TclCygwin32Putenv
#define putenv TclCygwin32Putenv
 
 
#endif
#endif
/* END CYGNUS LOCAL */
/* END CYGNUS LOCAL */
 
 
/*
/*
 * The structure below is used to keep track of all of the interpereters
 * The structure below is used to keep track of all of the interpereters
 * for which we're managing the "env" array.  It's needed so that they
 * for which we're managing the "env" array.  It's needed so that they
 * can all be updated whenever an environment variable is changed
 * can all be updated whenever an environment variable is changed
 * anywhere.
 * anywhere.
 */
 */
 
 
typedef struct EnvInterp {
typedef struct EnvInterp {
    Tcl_Interp *interp;         /* Interpreter for which we're managing
    Tcl_Interp *interp;         /* Interpreter for which we're managing
                                 * the env array. */
                                 * the env array. */
    struct EnvInterp *nextPtr;  /* Next in list of all such interpreters,
    struct EnvInterp *nextPtr;  /* Next in list of all such interpreters,
                                 * or zero. */
                                 * or zero. */
} EnvInterp;
} EnvInterp;
 
 
static EnvInterp *firstInterpPtr = NULL;
static EnvInterp *firstInterpPtr = NULL;
                                /* First in list of all managed interpreters,
                                /* First in list of all managed interpreters,
                                 * or NULL if none. */
                                 * or NULL if none. */
 
 
static int cacheSize = 0;        /* Number of env strings in environCache. */
static int cacheSize = 0;        /* Number of env strings in environCache. */
static char **environCache = NULL;
static char **environCache = NULL;
                                /* Array containing all of the environment
                                /* Array containing all of the environment
                                 * strings that Tcl has allocated. */
                                 * strings that Tcl has allocated. */
 
 
#ifndef USE_PUTENV
#ifndef USE_PUTENV
static int environSize = 0;      /* Non-zero means that the environ array was
static int environSize = 0;      /* Non-zero means that the environ array was
                                 * malloced and has this many total entries
                                 * malloced and has this many total entries
                                 * allocated to it (not all may be in use at
                                 * allocated to it (not all may be in use at
                                 * once).  Zero means that the environment
                                 * once).  Zero means that the environment
                                 * array is in its original static state. */
                                 * array is in its original static state. */
#endif
#endif
 
 
/*
/*
 * Declarations for local procedures defined in this file:
 * Declarations for local procedures defined in this file:
 */
 */
 
 
static char *           EnvTraceProc _ANSI_ARGS_((ClientData clientData,
static char *           EnvTraceProc _ANSI_ARGS_((ClientData clientData,
                            Tcl_Interp *interp, char *name1, char *name2,
                            Tcl_Interp *interp, char *name1, char *name2,
                            int flags));
                            int flags));
static int              FindVariable _ANSI_ARGS_((CONST char *name,
static int              FindVariable _ANSI_ARGS_((CONST char *name,
                            int *lengthPtr));
                            int *lengthPtr));
static void             ReplaceString _ANSI_ARGS_((CONST char *oldStr,
static void             ReplaceString _ANSI_ARGS_((CONST char *oldStr,
                            char *newStr));
                            char *newStr));
void                    TclSetEnv _ANSI_ARGS_((CONST char *name,
void                    TclSetEnv _ANSI_ARGS_((CONST char *name,
                            CONST char *value));
                            CONST char *value));
void                    TclUnsetEnv _ANSI_ARGS_((CONST char *name));
void                    TclUnsetEnv _ANSI_ARGS_((CONST char *name));
 
 
/* CYGNUS LOCAL */
/* CYGNUS LOCAL */
#if defined (__CYGWIN__) && defined(__WIN32__)
#if defined (__CYGWIN__) && defined(__WIN32__)
static void             TclCygwin32Putenv _ANSI_ARGS_((CONST char *string));
static void             TclCygwin32Putenv _ANSI_ARGS_((CONST char *string));
#endif
#endif


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * TclSetupEnv --
 * TclSetupEnv --
 *
 *
 *      This procedure is invoked for an interpreter to make environment
 *      This procedure is invoked for an interpreter to make environment
 *      variables accessible from that interpreter via the "env"
 *      variables accessible from that interpreter via the "env"
 *      associative array.
 *      associative array.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The interpreter is added to a list of interpreters managed
 *      The interpreter is added to a list of interpreters managed
 *      by us, so that its view of envariables can be kept consistent
 *      by us, so that its view of envariables can be kept consistent
 *      with the view in other interpreters.  If this is the first
 *      with the view in other interpreters.  If this is the first
 *      call to Tcl_SetupEnv, then additional initialization happens,
 *      call to Tcl_SetupEnv, then additional initialization happens,
 *      such as copying the environment to dynamically-allocated space
 *      such as copying the environment to dynamically-allocated space
 *      for ease of management.
 *      for ease of management.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
void
void
TclSetupEnv(interp)
TclSetupEnv(interp)
    Tcl_Interp *interp;         /* Interpreter whose "env" array is to be
    Tcl_Interp *interp;         /* Interpreter whose "env" array is to be
                                 * managed. */
                                 * managed. */
{
{
    EnvInterp *eiPtr;
    EnvInterp *eiPtr;
    char *p, *p2;
    char *p, *p2;
    Tcl_DString ds;
    Tcl_DString ds;
    int i, sz;
    int i, sz;
 
 
#ifdef MAC_TCL
#ifdef MAC_TCL
    if (environ == NULL) {
    if (environ == NULL) {
        environSize = TclMacCreateEnv();
        environSize = TclMacCreateEnv();
    }
    }
#endif
#endif
 
 
    /*
    /*
     * Next, initialize the DString we are going to use for copying
     * Next, initialize the DString we are going to use for copying
     * the names of the environment variables.
     * the names of the environment variables.
     */
     */
 
 
    Tcl_DStringInit(&ds);
    Tcl_DStringInit(&ds);
 
 
    /*
    /*
     * Next, add the interpreter to the list of those that we manage.
     * Next, add the interpreter to the list of those that we manage.
     */
     */
 
 
    eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
    eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
    eiPtr->interp = interp;
    eiPtr->interp = interp;
    eiPtr->nextPtr = firstInterpPtr;
    eiPtr->nextPtr = firstInterpPtr;
    firstInterpPtr = eiPtr;
    firstInterpPtr = eiPtr;
 
 
    /*
    /*
     * Store the environment variable values into the interpreter's
     * Store the environment variable values into the interpreter's
     * "env" array, and arrange for us to be notified on future
     * "env" array, and arrange for us to be notified on future
     * writes and unsets to that array.
     * writes and unsets to that array.
     */
     */
 
 
    (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
    (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
    for (i = 0; ; i++) {
    for (i = 0; ; i++) {
        p = environ[i];
        p = environ[i];
        if (p == NULL) {
        if (p == NULL) {
            break;
            break;
        }
        }
        for (p2 = p; *p2 != '='; p2++) {
        for (p2 = p; *p2 != '='; p2++) {
            if (*p2 == 0) {
            if (*p2 == 0) {
                /*
                /*
                 * This condition doesn't seem like it should ever happen,
                 * This condition doesn't seem like it should ever happen,
                 * but it does seem to happen occasionally under some
                 * but it does seem to happen occasionally under some
                 * versions of Solaris; ignore the entry.
                 * versions of Solaris; ignore the entry.
                 */
                 */
 
 
                goto nextEntry;
                goto nextEntry;
            }
            }
        }
        }
        sz = p2 - p;
        sz = p2 - p;
        Tcl_DStringSetLength(&ds, 0);
        Tcl_DStringSetLength(&ds, 0);
        Tcl_DStringAppend(&ds, p, sz);
        Tcl_DStringAppend(&ds, p, sz);
        (void) Tcl_SetVar2(interp, "env", Tcl_DStringValue(&ds),
        (void) Tcl_SetVar2(interp, "env", Tcl_DStringValue(&ds),
                p2+1, TCL_GLOBAL_ONLY);
                p2+1, TCL_GLOBAL_ONLY);
        nextEntry:
        nextEntry:
        continue;
        continue;
    }
    }
    Tcl_TraceVar2(interp, "env", (char *) NULL,
    Tcl_TraceVar2(interp, "env", (char *) NULL,
            TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
            TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
            EnvTraceProc, (ClientData) NULL);
            EnvTraceProc, (ClientData) NULL);
 
 
    /*
    /*
     * Finally clean up the DString.
     * Finally clean up the DString.
     */
     */
 
 
    Tcl_DStringFree(&ds);
    Tcl_DStringFree(&ds);
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * TclSetEnv --
 * TclSetEnv --
 *
 *
 *      Set an environment variable, replacing an existing value
 *      Set an environment variable, replacing an existing value
 *      or creating a new variable if there doesn't exist a variable
 *      or creating a new variable if there doesn't exist a variable
 *      by the given name.  This procedure is intended to be a
 *      by the given name.  This procedure is intended to be a
 *      stand-in for the  UNIX "setenv" procedure so that applications
 *      stand-in for the  UNIX "setenv" procedure so that applications
 *      using that procedure will interface properly to Tcl.  To make
 *      using that procedure will interface properly to Tcl.  To make
 *      it a stand-in, the Makefile must define "TclSetEnv" to "setenv".
 *      it a stand-in, the Makefile must define "TclSetEnv" to "setenv".
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The environ array gets updated, as do all of the interpreters
 *      The environ array gets updated, as do all of the interpreters
 *      that we manage.
 *      that we manage.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
void
void
TclSetEnv(name, value)
TclSetEnv(name, value)
    CONST char *name;           /* Name of variable whose value is to be
    CONST char *name;           /* Name of variable whose value is to be
                                 * set. */
                                 * set. */
    CONST char *value;          /* New value for variable. */
    CONST char *value;          /* New value for variable. */
{
{
    int index, length, nameLength;
    int index, length, nameLength;
    char *p, *oldValue;
    char *p, *oldValue;
    EnvInterp *eiPtr;
    EnvInterp *eiPtr;
 
 
#ifdef MAC_TCL
#ifdef MAC_TCL
    if (environ == NULL) {
    if (environ == NULL) {
        environSize = TclMacCreateEnv();
        environSize = TclMacCreateEnv();
    }
    }
#endif
#endif
 
 
    /*
    /*
     * Figure out where the entry is going to go.  If the name doesn't
     * Figure out where the entry is going to go.  If the name doesn't
     * already exist, enlarge the array if necessary to make room.  If
     * already exist, enlarge the array if necessary to make room.  If
     * the name exists, free its old entry.
     * the name exists, free its old entry.
     */
     */
 
 
    index = FindVariable(name, &length);
    index = FindVariable(name, &length);
    if (index == -1) {
    if (index == -1) {
#ifndef USE_PUTENV
#ifndef USE_PUTENV
        if ((length+2) > environSize) {
        if ((length+2) > environSize) {
            char **newEnviron;
            char **newEnviron;
 
 
            newEnviron = (char **) ckalloc((unsigned)
            newEnviron = (char **) ckalloc((unsigned)
                    ((length+5) * sizeof(char *)));
                    ((length+5) * sizeof(char *)));
 
 
            /* CYGNUS LOCAL: Added to avoid an error from Purify,
            /* CYGNUS LOCAL: Added to avoid an error from Purify,
               although I don't personally see where the error would
               although I don't personally see where the error would
               occur--ian.  */
               occur--ian.  */
            memset((VOID *) newEnviron, 0, (length+5) * sizeof(char *));
            memset((VOID *) newEnviron, 0, (length+5) * sizeof(char *));
 
 
            memcpy((VOID *) newEnviron, (VOID *) environ,
            memcpy((VOID *) newEnviron, (VOID *) environ,
                    length*sizeof(char *));
                    length*sizeof(char *));
            if (environSize != 0) {
            if (environSize != 0) {
                ckfree((char *) environ);
                ckfree((char *) environ);
            }
            }
            environ = newEnviron;
            environ = newEnviron;
            environSize = length+5;
            environSize = length+5;
        }
        }
        index = length;
        index = length;
        environ[index+1] = NULL;
        environ[index+1] = NULL;
#endif
#endif
        oldValue = NULL;
        oldValue = NULL;
        nameLength = strlen(name);
        nameLength = strlen(name);
    } else {
    } else {
        /*
        /*
         * Compare the new value to the existing value.  If they're
         * Compare the new value to the existing value.  If they're
         * the same then quit immediately (e.g. don't rewrite the
         * the same then quit immediately (e.g. don't rewrite the
         * value or propagate it to other interpreters).  Otherwise,
         * value or propagate it to other interpreters).  Otherwise,
         * when there are N interpreters there will be N! propagations
         * when there are N interpreters there will be N! propagations
         * of the same value among the interpreters.
         * of the same value among the interpreters.
         */
         */
 
 
        if (strcmp(value, environ[index]+length+1) == 0) {
        if (strcmp(value, environ[index]+length+1) == 0) {
            return;
            return;
        }
        }
        oldValue = environ[index];
        oldValue = environ[index];
        nameLength = length;
        nameLength = length;
    }
    }
 
 
 
 
    /*
    /*
     * Create a new entry.
     * Create a new entry.
     */
     */
 
 
    p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
    p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
    strcpy(p, name);
    strcpy(p, name);
    p[nameLength] = '=';
    p[nameLength] = '=';
    strcpy(p+nameLength+1, value);
    strcpy(p+nameLength+1, value);
 
 
    /*
    /*
     * Update the system environment.
     * Update the system environment.
     */
     */
 
 
#ifdef USE_PUTENV
#ifdef USE_PUTENV
    putenv(p);
    putenv(p);
#else
#else
    environ[index] = p;
    environ[index] = p;
#endif
#endif
 
 
    /*
    /*
     * Replace the old value with the new value in the cache.
     * Replace the old value with the new value in the cache.
     */
     */
 
 
    ReplaceString(oldValue, p);
    ReplaceString(oldValue, p);
 
 
    /*
    /*
     * Update all of the interpreters.
     * Update all of the interpreters.
     */
     */
 
 
    /* CYGNUS LOCAL: The original code was bogus.  If we are being
    /* CYGNUS LOCAL: The original code was bogus.  If we are being
       called because of a trace on the env array, then the call to
       called because of a trace on the env array, then the call to
       Tcl_SetVar2 would free value.  We avoid that by checking
       Tcl_SetVar2 would free value.  We avoid that by checking
       whether the value is the same before calling Tcl_SetVar2.
       whether the value is the same before calling Tcl_SetVar2.
 
 
       NOTE: This is not necessary in tcl8.1a2 which handles this in a
       NOTE: This is not necessary in tcl8.1a2 which handles this in a
       completely different, and better, way.  */
       completely different, and better, way.  */
 
 
    for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
    for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
        CONST char *v;
        CONST char *v;
 
 
        v = Tcl_GetVar2(eiPtr->interp, "env", (char *) name, TCL_GLOBAL_ONLY);
        v = Tcl_GetVar2(eiPtr->interp, "env", (char *) name, TCL_GLOBAL_ONLY);
        if (v == NULL || (v != value && strcmp (v, value) != 0)) {
        if (v == NULL || (v != value && strcmp (v, value) != 0)) {
            (void) Tcl_SetVar2(eiPtr->interp, "env", (char *) name,
            (void) Tcl_SetVar2(eiPtr->interp, "env", (char *) name,
                    (char *) value, TCL_GLOBAL_ONLY);
                    (char *) value, TCL_GLOBAL_ONLY);
        }
        }
    }
    }
 
 
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * Tcl_PutEnv --
 * Tcl_PutEnv --
 *
 *
 *      Set an environment variable.  Similar to setenv except that
 *      Set an environment variable.  Similar to setenv except that
 *      the information is passed in a single string of the form
 *      the information is passed in a single string of the form
 *      NAME=value, rather than as separate name strings.  This procedure
 *      NAME=value, rather than as separate name strings.  This procedure
 *      is intended to be a stand-in for the  UNIX "putenv" procedure
 *      is intended to be a stand-in for the  UNIX "putenv" procedure
 *      so that applications using that procedure will interface
 *      so that applications using that procedure will interface
 *      properly to Tcl.  To make it a stand-in, the Makefile will
 *      properly to Tcl.  To make it a stand-in, the Makefile will
 *      define "Tcl_PutEnv" to "putenv".
 *      define "Tcl_PutEnv" to "putenv".
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The environ array gets updated, as do all of the interpreters
 *      The environ array gets updated, as do all of the interpreters
 *      that we manage.
 *      that we manage.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
int
int
Tcl_PutEnv(string)
Tcl_PutEnv(string)
    CONST char *string;         /* Info about environment variable in the
    CONST char *string;         /* Info about environment variable in the
                                 * form NAME=value. */
                                 * form NAME=value. */
{
{
    int nameLength;
    int nameLength;
    char *name, *value;
    char *name, *value;
 
 
    if (string == NULL) {
    if (string == NULL) {
        return 0;
        return 0;
    }
    }
 
 
    /*
    /*
     * Separate the string into name and value parts, then call
     * Separate the string into name and value parts, then call
     * TclSetEnv to do all of the real work.
     * TclSetEnv to do all of the real work.
     */
     */
 
 
    value = strchr(string, '=');
    value = strchr(string, '=');
    if (value == NULL) {
    if (value == NULL) {
        return 0;
        return 0;
    }
    }
    nameLength = value - string;
    nameLength = value - string;
    if (nameLength == 0) {
    if (nameLength == 0) {
        return 0;
        return 0;
    }
    }
    name = (char *) ckalloc((unsigned) nameLength+1);
    name = (char *) ckalloc((unsigned) nameLength+1);
    memcpy((VOID *) name, (VOID *) string, (size_t) nameLength);
    memcpy((VOID *) name, (VOID *) string, (size_t) nameLength);
    name[nameLength] = 0;
    name[nameLength] = 0;
    TclSetEnv(name, value+1);
    TclSetEnv(name, value+1);
    ckfree(name);
    ckfree(name);
    return 0;
    return 0;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * TclUnsetEnv --
 * TclUnsetEnv --
 *
 *
 *      Remove an environment variable, updating the "env" arrays
 *      Remove an environment variable, updating the "env" arrays
 *      in all interpreters managed by us.  This function is intended
 *      in all interpreters managed by us.  This function is intended
 *      to replace the UNIX "unsetenv" function (but to do this the
 *      to replace the UNIX "unsetenv" function (but to do this the
 *      Makefile must be modified to redefine "TclUnsetEnv" to
 *      Makefile must be modified to redefine "TclUnsetEnv" to
 *      "unsetenv".
 *      "unsetenv".
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Interpreters are updated, as is environ.
 *      Interpreters are updated, as is environ.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
void
void
TclUnsetEnv(name)
TclUnsetEnv(name)
    CONST char *name;                   /* Name of variable to remove. */
    CONST char *name;                   /* Name of variable to remove. */
{
{
    EnvInterp *eiPtr;
    EnvInterp *eiPtr;
    char *oldValue;
    char *oldValue;
    int length, index;
    int length, index;
#ifdef USE_PUTENV
#ifdef USE_PUTENV
    char *string;
    char *string;
#else
#else
    char **envPtr;
    char **envPtr;
#endif
#endif
 
 
#ifdef MAC_TCL
#ifdef MAC_TCL
    if (environ == NULL) {
    if (environ == NULL) {
        environSize = TclMacCreateEnv();
        environSize = TclMacCreateEnv();
    }
    }
#endif
#endif
 
 
    index = FindVariable(name, &length);
    index = FindVariable(name, &length);
 
 
    /*
    /*
     * First make sure that the environment variable exists to avoid
     * First make sure that the environment variable exists to avoid
     * doing needless work and to avoid recursion on the unset.
     * doing needless work and to avoid recursion on the unset.
     */
     */
 
 
    if (index == -1) {
    if (index == -1) {
        return;
        return;
    }
    }
    /*
    /*
     * Remember the old value so we can free it if Tcl created the string.
     * Remember the old value so we can free it if Tcl created the string.
     */
     */
 
 
    oldValue = environ[index];
    oldValue = environ[index];
 
 
    /*
    /*
     * Update the system environment.  This must be done before we
     * Update the system environment.  This must be done before we
     * update the interpreters or we will recurse.
     * update the interpreters or we will recurse.
     */
     */
 
 
#ifdef USE_PUTENV
#ifdef USE_PUTENV
    string = ckalloc(length+2);
    string = ckalloc(length+2);
    memcpy((VOID *) string, (VOID *) name, (size_t) length);
    memcpy((VOID *) string, (VOID *) name, (size_t) length);
    string[length] = '=';
    string[length] = '=';
    string[length+1] = '\0';
    string[length+1] = '\0';
    putenv(string);
    putenv(string);
    ckfree(string);
    ckfree(string);
#else
#else
    for (envPtr = environ+index+1; ; envPtr++) {
    for (envPtr = environ+index+1; ; envPtr++) {
        envPtr[-1] = *envPtr;
        envPtr[-1] = *envPtr;
        if (*envPtr == NULL) {
        if (*envPtr == NULL) {
            break;
            break;
        }
        }
    }
    }
#endif
#endif
 
 
    /*
    /*
     * Replace the old value in the cache.
     * Replace the old value in the cache.
     */
     */
 
 
    ReplaceString(oldValue, NULL);
    ReplaceString(oldValue, NULL);
 
 
    /*
    /*
     * Update all of the interpreters.
     * Update all of the interpreters.
     */
     */
 
 
    for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
    for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
        (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *) name,
        (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *) name,
                TCL_GLOBAL_ONLY);
                TCL_GLOBAL_ONLY);
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * TclGetEnv --
 * TclGetEnv --
 *
 *
 *      Retrieve the value of an environment variable.
 *      Retrieve the value of an environment variable.
 *
 *
 * Results:
 * Results:
 *      Returns a pointer to a static string in the environment,
 *      Returns a pointer to a static string in the environment,
 *      or NULL if the value was not found.
 *      or NULL if the value was not found.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
char *
char *
TclGetEnv(name)
TclGetEnv(name)
    CONST char *name;           /* Name of variable to find. */
    CONST char *name;           /* Name of variable to find. */
{
{
    int length, index;
    int length, index;
 
 
#ifdef MAC_TCL
#ifdef MAC_TCL
    if (environ == NULL) {
    if (environ == NULL) {
        environSize = TclMacCreateEnv();
        environSize = TclMacCreateEnv();
    }
    }
#endif
#endif
 
 
    index = FindVariable(name, &length);
    index = FindVariable(name, &length);
    if ((index != -1) &&  (*(environ[index]+length) == '=')) {
    if ((index != -1) &&  (*(environ[index]+length) == '=')) {
        return environ[index]+length+1;
        return environ[index]+length+1;
    } else {
    } else {
        return NULL;
        return NULL;
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * EnvTraceProc --
 * EnvTraceProc --
 *
 *
 *      This procedure is invoked whenever an environment variable
 *      This procedure is invoked whenever an environment variable
 *      is modified or deleted.  It propagates the change to the
 *      is modified or deleted.  It propagates the change to the
 *      "environ" array and to any other interpreters for whom
 *      "environ" array and to any other interpreters for whom
 *      we're managing an "env" array.
 *      we're managing an "env" array.
 *
 *
 * Results:
 * Results:
 *      Always returns NULL to indicate success.
 *      Always returns NULL to indicate success.
 *
 *
 * Side effects:
 * Side effects:
 *      Environment variable changes get propagated.  If the whole
 *      Environment variable changes get propagated.  If the whole
 *      "env" array is deleted, then we stop managing things for
 *      "env" array is deleted, then we stop managing things for
 *      this interpreter (usually this happens because the whole
 *      this interpreter (usually this happens because the whole
 *      interpreter is being deleted).
 *      interpreter is being deleted).
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
        /* ARGSUSED */
        /* ARGSUSED */
static char *
static char *
EnvTraceProc(clientData, interp, name1, name2, flags)
EnvTraceProc(clientData, interp, name1, name2, flags)
    ClientData clientData;      /* Not used. */
    ClientData clientData;      /* Not used. */
    Tcl_Interp *interp;         /* Interpreter whose "env" variable is
    Tcl_Interp *interp;         /* Interpreter whose "env" variable is
                                 * being modified. */
                                 * being modified. */
    char *name1;                /* Better be "env". */
    char *name1;                /* Better be "env". */
    char *name2;                /* Name of variable being modified, or
    char *name2;                /* Name of variable being modified, or
                                 * NULL if whole array is being deleted. */
                                 * NULL if whole array is being deleted. */
    int flags;                  /* Indicates what's happening. */
    int flags;                  /* Indicates what's happening. */
{
{
    /*
    /*
     * First see if the whole "env" variable is being deleted.  If
     * First see if the whole "env" variable is being deleted.  If
     * so, just forget about this interpreter.
     * so, just forget about this interpreter.
     */
     */
 
 
    if (name2 == NULL) {
    if (name2 == NULL) {
        register EnvInterp *eiPtr, *prevPtr;
        register EnvInterp *eiPtr, *prevPtr;
 
 
        if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
        if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
                != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
                != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
            panic("EnvTraceProc called with confusing arguments");
            panic("EnvTraceProc called with confusing arguments");
        }
        }
        eiPtr = firstInterpPtr;
        eiPtr = firstInterpPtr;
        if (eiPtr->interp == interp) {
        if (eiPtr->interp == interp) {
            firstInterpPtr = eiPtr->nextPtr;
            firstInterpPtr = eiPtr->nextPtr;
        } else {
        } else {
            for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
            for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
                    prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
                    prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
                if (eiPtr == NULL) {
                if (eiPtr == NULL) {
                    panic("EnvTraceProc couldn't find interpreter");
                    panic("EnvTraceProc couldn't find interpreter");
                }
                }
                if (eiPtr->interp == interp) {
                if (eiPtr->interp == interp) {
                    prevPtr->nextPtr = eiPtr->nextPtr;
                    prevPtr->nextPtr = eiPtr->nextPtr;
                    break;
                    break;
                }
                }
            }
            }
        }
        }
        ckfree((char *) eiPtr);
        ckfree((char *) eiPtr);
        return NULL;
        return NULL;
    }
    }
 
 
    /*
    /*
     * If a value is being set, call TclSetEnv to do all of the work.
     * If a value is being set, call TclSetEnv to do all of the work.
     */
     */
 
 
    if (flags & TCL_TRACE_WRITES) {
    if (flags & TCL_TRACE_WRITES) {
        TclSetEnv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY));
        TclSetEnv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY));
    }
    }
 
 
    if (flags & TCL_TRACE_UNSETS) {
    if (flags & TCL_TRACE_UNSETS) {
        TclUnsetEnv(name2);
        TclUnsetEnv(name2);
    }
    }
    return NULL;
    return NULL;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * ReplaceString --
 * ReplaceString --
 *
 *
 *      Replace one string with another in the environment variable
 *      Replace one string with another in the environment variable
 *      cache.  The cache keeps track of all of the environment
 *      cache.  The cache keeps track of all of the environment
 *      variables that Tcl has modified so they can be freed later.
 *      variables that Tcl has modified so they can be freed later.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      May free the old string.
 *      May free the old string.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
ReplaceString(oldStr, newStr)
ReplaceString(oldStr, newStr)
    CONST char *oldStr;         /* Old environment string. */
    CONST char *oldStr;         /* Old environment string. */
    char *newStr;               /* New environment string. */
    char *newStr;               /* New environment string. */
{
{
    int i;
    int i;
    char **newCache;
    char **newCache;
 
 
    /*
    /*
     * Check to see if the old value was allocated by Tcl.  If so,
     * Check to see if the old value was allocated by Tcl.  If so,
     * it needs to be deallocated to avoid memory leaks.  Note that this
     * it needs to be deallocated to avoid memory leaks.  Note that this
     * algorithm is O(n), not O(1).  This will result in n-squared behavior
     * algorithm is O(n), not O(1).  This will result in n-squared behavior
     * if lots of environment changes are being made.
     * if lots of environment changes are being made.
     */
     */
 
 
    for (i = 0; i < cacheSize; i++) {
    for (i = 0; i < cacheSize; i++) {
        if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {
        if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {
            break;
            break;
        }
        }
    }
    }
    if (i < cacheSize) {
    if (i < cacheSize) {
        /*
        /*
         * Replace or delete the old value.
         * Replace or delete the old value.
         */
         */
 
 
        if (environCache[i]) {
        if (environCache[i]) {
            ckfree(environCache[i]);
            ckfree(environCache[i]);
        }
        }
 
 
        if (newStr) {
        if (newStr) {
            environCache[i] = newStr;
            environCache[i] = newStr;
        } else {
        } else {
            for (; i < cacheSize-1; i++) {
            for (; i < cacheSize-1; i++) {
                environCache[i] = environCache[i+1];
                environCache[i] = environCache[i+1];
            }
            }
            environCache[cacheSize-1] = NULL;
            environCache[cacheSize-1] = NULL;
        }
        }
    } else {
    } else {
        int allocatedSize = (cacheSize + 5) * sizeof(char *);
        int allocatedSize = (cacheSize + 5) * sizeof(char *);
 
 
        /*
        /*
         * We need to grow the cache in order to hold the new string.
         * We need to grow the cache in order to hold the new string.
         */
         */
 
 
        newCache = (char **) ckalloc((size_t) allocatedSize);
        newCache = (char **) ckalloc((size_t) allocatedSize);
        (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);
        (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);
 
 
        if (environCache) {
        if (environCache) {
            memcpy((VOID *) newCache, (VOID *) environCache,
            memcpy((VOID *) newCache, (VOID *) environCache,
                    (size_t) (cacheSize * sizeof(char*)));
                    (size_t) (cacheSize * sizeof(char*)));
            ckfree((char *) environCache);
            ckfree((char *) environCache);
        }
        }
        environCache = newCache;
        environCache = newCache;
        environCache[cacheSize] = (char *) newStr;
        environCache[cacheSize] = (char *) newStr;
        environCache[cacheSize+1] = NULL;
        environCache[cacheSize+1] = NULL;
        cacheSize += 5;
        cacheSize += 5;
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * FindVariable --
 * FindVariable --
 *
 *
 *      Locate the entry in environ for a given name.
 *      Locate the entry in environ for a given name.
 *
 *
 * Results:
 * Results:
 *      The return value is the index in environ of an entry with the
 *      The return value is the index in environ of an entry with the
 *      name "name", or -1 if there is no such entry.   The integer at
 *      name "name", or -1 if there is no such entry.   The integer at
 *      *lengthPtr is filled in with the length of name (if a matching
 *      *lengthPtr is filled in with the length of name (if a matching
 *      entry is found) or the length of the environ array (if no matching
 *      entry is found) or the length of the environ array (if no matching
 *      entry is found).
 *      entry is found).
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static int
static int
FindVariable(name, lengthPtr)
FindVariable(name, lengthPtr)
    CONST char *name;           /* Name of desired environment variable. */
    CONST char *name;           /* Name of desired environment variable. */
    int *lengthPtr;             /* Used to return length of name (for
    int *lengthPtr;             /* Used to return length of name (for
                                 * successful searches) or number of non-NULL
                                 * successful searches) or number of non-NULL
                                 * entries in environ (for unsuccessful
                                 * entries in environ (for unsuccessful
                                 * searches). */
                                 * searches). */
{
{
    int i;
    int i;
    register CONST char *p1, *p2;
    register CONST char *p1, *p2;
 
 
    for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
    for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
        for (p2 = name; *p2 == *p1; p1++, p2++) {
        for (p2 = name; *p2 == *p1; p1++, p2++) {
            /* NULL loop body. */
            /* NULL loop body. */
        }
        }
        if ((*p1 == '=') && (*p2 == '\0')) {
        if ((*p1 == '=') && (*p2 == '\0')) {
            *lengthPtr = p2-name;
            *lengthPtr = p2-name;
            return i;
            return i;
        }
        }
    }
    }
    *lengthPtr = i;
    *lengthPtr = i;
    return -1;
    return -1;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * TclFinalizeEnvironment --
 * TclFinalizeEnvironment --
 *
 *
 *      This function releases any storage allocated by this module
 *      This function releases any storage allocated by this module
 *      that isn't still in use by the global environment.  Any
 *      that isn't still in use by the global environment.  Any
 *      strings that are still in the environment will be leaked.
 *      strings that are still in the environment will be leaked.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      May deallocate storage.
 *      May deallocate storage.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
void
void
TclFinalizeEnvironment()
TclFinalizeEnvironment()
{
{
    /*
    /*
     * For now we just deallocate the cache array and none of the environment
     * For now we just deallocate the cache array and none of the environment
     * strings.  This may leak more memory that strictly necessary, since some
     * strings.  This may leak more memory that strictly necessary, since some
     * of the strings may no longer be in the environment.  However,
     * of the strings may no longer be in the environment.  However,
     * determining which ones are ok to delete is n-squared, and is pretty
     * determining which ones are ok to delete is n-squared, and is pretty
     * unlikely, so we don't bother.
     * unlikely, so we don't bother.
     */
     */
 
 
    if (environCache) {
    if (environCache) {
        ckfree((char *) environCache);
        ckfree((char *) environCache);
        environCache = NULL;
        environCache = NULL;
        cacheSize    = 0;
        cacheSize    = 0;
#ifndef USE_PUTENV
#ifndef USE_PUTENV
        environSize  = 0;
        environSize  = 0;
#endif
#endif
    }
    }
}
}


/* CYGNUS LOCAL */
/* CYGNUS LOCAL */
#if defined(__CYGWIN__) && defined(__WIN32__)
#if defined(__CYGWIN__) && defined(__WIN32__)
 
 
#include "windows.h"
#include "windows.h"
 
 
/* When using cygwin, when an environment variable changes, we need
/* When using cygwin, when an environment variable changes, we need
   to synch with both the cygwin environment (in case the
   to synch with both the cygwin environment (in case the
   application C code calls fork) and the Windows environment (in case
   application C code calls fork) and the Windows environment (in case
   the application TCL code calls exec, which calls the Windows
   the application TCL code calls exec, which calls the Windows
   CreateProcess function).  */
   CreateProcess function).  */
 
 
static void
static void
TclCygwin32Putenv(str)
TclCygwin32Putenv(str)
     const char *str;
     const char *str;
{
{
  char *name, *value;
  char *name, *value;
 
 
  /* Get the name and value, so that we can change the environment
  /* Get the name and value, so that we can change the environment
     variable for Windows.  */
     variable for Windows.  */
  name = (char *) alloca (strlen (str) + 1);
  name = (char *) alloca (strlen (str) + 1);
  strcpy (name, str);
  strcpy (name, str);
  for (value = name; *value != '=' && *value != '\0'; ++value)
  for (value = name; *value != '=' && *value != '\0'; ++value)
    ;
    ;
  if (*value == '\0')
  if (*value == '\0')
    {
    {
      /* Can't happen.  */
      /* Can't happen.  */
      return;
      return;
    }
    }
  *value = '\0';
  *value = '\0';
  ++value;
  ++value;
  if (*value == '\0')
  if (*value == '\0')
    value = NULL;
    value = NULL;
 
 
  /* Set the cygwin environment variable.  */
  /* Set the cygwin environment variable.  */
#undef putenv
#undef putenv
  if (value == NULL)
  if (value == NULL)
    unsetenv (name);
    unsetenv (name);
  else
  else
    putenv(str);
    putenv(str);
 
 
  /* Before changing the environment variable in Windows, if this is
  /* Before changing the environment variable in Windows, if this is
     PATH, we need to convert the value back to a Windows style path.
     PATH, we need to convert the value back to a Windows style path.
 
 
     FIXME: The calling program may now it is running under windows,
     FIXME: The calling program may now it is running under windows,
     and may have set the path to a Windows path, or, worse, appended
     and may have set the path to a Windows path, or, worse, appended
     or prepended a Windows path to PATH.  */
     or prepended a Windows path to PATH.  */
  if (strcmp (name, "PATH") != 0)
  if (strcmp (name, "PATH") != 0)
    {
    {
      /* If this is Path, eliminate any PATH variable, to prevent any
      /* If this is Path, eliminate any PATH variable, to prevent any
         confusion.  */
         confusion.  */
      if (strcmp (name, "Path") == 0)
      if (strcmp (name, "Path") == 0)
        {
        {
          SetEnvironmentVariable ("PATH", (char *) NULL);
          SetEnvironmentVariable ("PATH", (char *) NULL);
          unsetenv ("PATH");
          unsetenv ("PATH");
        }
        }
 
 
      SetEnvironmentVariable (name, value);
      SetEnvironmentVariable (name, value);
    }
    }
  else
  else
    {
    {
      char *buf;
      char *buf;
 
 
      /* Eliminate any Path variable, to prevent any confusion.  */
      /* Eliminate any Path variable, to prevent any confusion.  */
      SetEnvironmentVariable ("Path", (char *) NULL);
      SetEnvironmentVariable ("Path", (char *) NULL);
      unsetenv ("Path");
      unsetenv ("Path");
 
 
      if (value == NULL)
      if (value == NULL)
        buf = NULL;
        buf = NULL;
      else
      else
        {
        {
          int size;
          int size;
 
 
          size = cygwin_posix_to_win32_path_list_buf_size (value);
          size = cygwin_posix_to_win32_path_list_buf_size (value);
          buf = (char *) alloca (size + 1);
          buf = (char *) alloca (size + 1);
          cygwin_posix_to_win32_path_list (value, buf);
          cygwin_posix_to_win32_path_list (value, buf);
        }
        }
 
 
      SetEnvironmentVariable (name, buf);
      SetEnvironmentVariable (name, buf);
    }
    }
}
}
 
 
#endif /* __CYGWIN__ */
#endif /* __CYGWIN__ */
/* END CYGNUS LOCAL */
/* END CYGNUS LOCAL */
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.