/*This line lets emacs recognize this as -*- C -*- Code
 *-----------------------------------------------------------------------------
 *
 * Project:	Tcl Modules
 * Created:	91/10/23
 * Author:	John L. Furlani<john.furlani@East.Sun.COM>
 *
 * Description:
 *      The routines for setting and unsetting environment variables from
 *  within modulefiles.
 *	
 * $Log: cmdSetenv.c,v $
 *
 *
 * Revision 1.3  1993/01/29  06:16:26  jlf
 * Modified the DISPLAY output to align spacing.
 *
 * Revision 1.2  1993/01/25  18:48:13  jlf
 * Changed the method for keeping and unwinding failed modulefiles.
 * The output returns to its optimized state where only the aggregate
 * changes to the environment are sent to the executing shell.
 *
 * Revision 1.1  1992/11/05  23:37:08  jlf
 * Initial revision
 *
 *---------------------------------------------------------------------------*/
static char Id[] =
    "$Id: cmdSetenv.c,v 2.0 1993/02/21 00:00:58 jlf Exp jlf $";

#include "global.h"

int
cmdSetEnv(ClientData client_data,
	  Tcl_Interp* interp,
	  int argc,
	  char* argv[])
{
    int force;
    char* var;
    char* val;

    if(argc < 3 || argc > 4) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " [-force] variable value\"", (char *) NULL);
        return TCL_ERROR;
    }

    if(*argv[1] == '-') {
        if(!strncmp(argv[1], "-force", 6)) {
            force = 1;
            var = argv[2];
            val = argv[3];
        } else {
            Tcl_AppendResult(interp, "wrong args: expected \"", argv[0],
                             " [-force] variable value\"", (char *) NULL);
            return TCL_ERROR;
        }            
    } else  {
        force = 0;
        var = argv[1];
        val = argv[2];
    }
    (void) moduleSetenv(interp, var, val, force);

    /*
     *  This has to be done after everything has been set because the
     *  variables may be needed later in the modulefile.
     */
    if(flags & M_DISPLAY) {
        fprintf(stderr, "Setenv  %s to %s\n", var, val);
    }

    return TCL_OK;
}

int
moduleSetenv(Tcl_Interp* interp,
             char* variable,
             char* value,
             int   force)
{
    char* oldval;

    oldval = Tcl_GetVar2(interp, "env", variable, TCL_GLOBAL_ONLY);
  
    /* Check to see if variable is already set correctly... */
    if((! (flags & (M_REMOVE | M_DISPLAY | M_SWITCH))) && (oldval != NULL)) {
        if(!strcmp(value, oldval)) {
            return TCL_OK;
        }
    }

    /*
     *  If I'm in SWSTATE1, I'm removing stuff from the old modulefile, so
     *  I'll just mark the variables that were used with the SWSTATE1 flag and
     *  return.
     *
     *  When I come back through in SWSTATE2, I'm setting the variables that
     *  are in the new modulefile.  So, I'll keep track of these by marking
     *  them as touched by SWSTATE2 and then actually setting their values in
     *  the environment down below.
     *
     *  Finally, in SWSTATE3, I'll check to see if the variables in the old
     *  modulefiles that have been marked are still marked as SWSTATE1.  If
     *  they are still the same, then I'll just unset them and return.
     *
     *  And, if I'm not doing any switching, then just unset the variable if
     *  I'm in remove mode. 
     */
    if(flags & M_SWSTATE1) {
        set_marked_entry(markVariableHashTable, variable, M_SWSTATE1);
        return TCL_OK;
    } else if(flags & M_SWSTATE2) {
        set_marked_entry(markVariableHashTable, variable, M_SWSTATE2);
    } else if(flags & M_SWSTATE3) {
        int marked_val;
        marked_val = chk_marked_entry(markVariableHashTable, variable);
        if(marked_val) {
            if(marked_val == M_SWSTATE1)
                return moduleUnsetenv(interp, variable);
            else
                return TCL_OK;
        }
    } else if((flags & M_REMOVE) && !force) {
        return moduleUnsetenv(interp, variable);
    }

    /*
     *  Keep track of our changes just in case we have to bail out and restore
     *  the environment.
     */
    if(!(flags & M_DISPLAY)) {
        store_shell_variable(setenvHashTable, variable, value);
        clear_shell_variable(unsetenvHashTable, variable);
    }

    /*
     *  Store the value into the environment
     */
    (void) Tcl_SetVar2(interp, "env", variable, value, TCL_GLOBAL_ONLY);

    return TCL_OK;
}


int
cmdUnsetEnv(ClientData client_data,
	    Tcl_Interp* interp,
	    int argc,
	    char* argv[])
{
    char* oldval;
    
    if(argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " variable\"", (char *) NULL);
        return TCL_ERROR;
    }

    moduleUnsetenv(interp, argv[1]);
    
    if(flags & M_DISPLAY) {
        fprintf(stderr, "Unsetenv %s\n", argv[1]);
    }

    return TCL_OK;
}

int
moduleUnsetenv(Tcl_Interp* interp,
               char* variable)
{
    char* oldval;
    
    oldval = Tcl_GetVar2(interp, "env", variable, TCL_GLOBAL_ONLY);

    /*
     * Don't unset the variable in Tcl Space.
     * If module writer *REALLY* wants it gone, use $env
     */
    if(!(flags & M_DISPLAY)) {
        store_shell_variable(unsetenvHashTable, variable, NULL);
        clear_shell_variable(setenvHashTable, variable);
    }
  
    return TCL_OK;
}

