mirror of
https://github.com/envmodules/modules.git
synced 2026-06-10 00:56:30 +08:00
* Changed the configure to search for libTcl.sh to acquire all it's necessary Tcl env.vars from it. * created a utility function stringer() to handle most of the strcpy/strcat operations and to automatically allocate string memory. * Mostly changed the memory malloc/free to use stringer/null_free. * rewrote some of the code logic to have a single point of exit with unwinding of memory allocations.
312 lines
9.1 KiB
C
312 lines
9.1 KiB
C
/*****
|
||
** ** Module Header ******************************************************* **
|
||
** **
|
||
** Modules Revision 3.0 **
|
||
** Providing a flexible user environment **
|
||
** **
|
||
** File: ModuleCmd_Switch.c **
|
||
** First Edition: 91/10/23 **
|
||
** **
|
||
** Authors: John Furlan, jlf@behere.com **
|
||
** Jens Hamisch, jens@Strawberry.COM **
|
||
** **
|
||
** Description: Switches two modulefiles such that the paths are **
|
||
** switched in-place. **
|
||
** **
|
||
** Exports: ModuleCmd_Switch **
|
||
** **
|
||
** Notes: **
|
||
** **
|
||
** ************************************************************************ **
|
||
****/
|
||
|
||
/** ** Copyright *********************************************************** **
|
||
** **
|
||
** Copyright 1991-1994 by John L. Furlan. **
|
||
** see LICENSE.GPL, which must be provided, for details **
|
||
** **
|
||
** ************************************************************************ **/
|
||
|
||
static char Id[] = "@(#)$Id: ModuleCmd_Switch.c,v 1.4 2002/04/29 21:16:48 rkowen Exp $";
|
||
static void *UseId[] = { &UseId, Id };
|
||
|
||
/** ************************************************************************ **/
|
||
/** HEADERS **/
|
||
/** ************************************************************************ **/
|
||
|
||
#include "modules_def.h"
|
||
|
||
/** ************************************************************************ **/
|
||
/** LOCAL DATATYPES **/
|
||
/** ************************************************************************ **/
|
||
|
||
/** not applicable **/
|
||
|
||
/** ************************************************************************ **/
|
||
/** CONSTANTS **/
|
||
/** ************************************************************************ **/
|
||
|
||
/** not applicable **/
|
||
|
||
/** ************************************************************************ **/
|
||
/** MACROS **/
|
||
/** ************************************************************************ **/
|
||
|
||
/** not applicable **/
|
||
|
||
/** ************************************************************************ **/
|
||
/** LOCAL DATA **/
|
||
/** ************************************************************************ **/
|
||
|
||
static char module_name[] = "ModuleCmd_Switch.c"; /** File name of this module **/
|
||
|
||
/** ************************************************************************ **/
|
||
/** PROTOTYPES **/
|
||
/** ************************************************************************ **/
|
||
|
||
/** not applicable **/
|
||
|
||
|
||
/*++++
|
||
** ** Function-Header ***************************************************** **
|
||
** **
|
||
** Function: ModuleCmd_Switch **
|
||
** **
|
||
** Description: Execution of the module-command 'switch' **
|
||
** **
|
||
** First Edition: 91/10/23 **
|
||
** **
|
||
** Parameters: Tcl_Interp *interp Attached Tcl Interp. **
|
||
** int argc Number of arguments **
|
||
** char *argv[] Argument list **
|
||
** **
|
||
** Result: int TCL_ERROR Failure **
|
||
** TCL_OK Successfull operation **
|
||
** **
|
||
** Attached Globals: g_flags Controlling the callback **
|
||
** functions. **
|
||
** specified_module The module name from the **
|
||
** command line. **
|
||
** g_current_module The module which is handled **
|
||
** by the current command **
|
||
** **
|
||
** ************************************************************************ **
|
||
++++*/
|
||
|
||
int ModuleCmd_Switch( Tcl_Interp *interp,
|
||
int argc,
|
||
char *argv[])
|
||
{
|
||
char *oldmodule,
|
||
*newmodule,
|
||
*realname,
|
||
*oldfile,
|
||
*newfile,
|
||
*oldname,
|
||
*newname,
|
||
*oldmodule_buffer;
|
||
int ret_val = TCL_OK;
|
||
|
||
#if WITH_DEBUGGING_MODULECMD
|
||
fprintf( stderr, "ModuleCmd_Switch(%d):DEBUG: Starting\n", __LINE__);
|
||
#endif
|
||
/**
|
||
** allocate buffer memory
|
||
**/
|
||
if ((char *) NULL == (oldfile = stringer(NULL, MOD_BUFSIZE, NULL)))
|
||
if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
|
||
goto unwind0;
|
||
|
||
if ((char *) NULL == (newfile = stringer(NULL, MOD_BUFSIZE, NULL)))
|
||
if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
|
||
goto unwind1;
|
||
|
||
if ((char *) NULL == (oldname = stringer(NULL, MOD_BUFSIZE, NULL)))
|
||
if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
|
||
goto unwind2;
|
||
|
||
if ((char *) NULL == (newname = stringer(NULL, MOD_BUFSIZE, NULL)))
|
||
if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
|
||
goto unwind3;
|
||
|
||
/**
|
||
** Parameter check. the required syntax is:
|
||
** module switch [ <old> ] <new>
|
||
** If <old> is not specified, then the pathname of <new> is assumed.
|
||
**/
|
||
|
||
if( argc == 1) {
|
||
char* o;
|
||
oldmodule = oldmodule_buffer;
|
||
newmodule = argv[0];
|
||
strncpy(oldmodule_buffer,newmodule,MOD_BUFSIZE);
|
||
oldmodule_buffer[MOD_BUFSIZE-1]=0; /* terminate just in case */
|
||
/* starting from the end of the module name, find the first
|
||
* forward slash and replace with null
|
||
*/
|
||
for(o = &oldmodule_buffer[strlen(oldmodule_buffer)-1];
|
||
o>oldmodule_buffer;
|
||
o--) {
|
||
if (*o == '/') {
|
||
*o = 0;
|
||
break;
|
||
}
|
||
}
|
||
} else if( argc == 2) {
|
||
oldmodule = argv[0];
|
||
newmodule = argv[1];
|
||
} else {
|
||
if( OK != ErrorLogger( ERR_USAGE, LOC, "switch oldmodule newmodule",
|
||
NULL))
|
||
return( TCL_ERROR); /** ------- EXIT (FAILURE) --------> **/
|
||
}
|
||
|
||
|
||
/**
|
||
** Set the name of the module specified on the command line
|
||
**/
|
||
|
||
specified_module = oldmodule;
|
||
|
||
/**
|
||
** First try to find a match for the modulefile out of the LOADEDMODULES.
|
||
**/
|
||
|
||
if( !IsLoaded( interp, oldmodule, &realname, oldfile))
|
||
if( OK != ErrorLogger( ERR_NOTLOADED, LOC, oldmodule, NULL))
|
||
goto unwind4;
|
||
|
||
/**
|
||
** If we have another name to try, try finding it on disk.
|
||
**/
|
||
|
||
if( realname)
|
||
ret_val = Locate_ModuleFile( interp, realname, oldname, oldfile);
|
||
|
||
/**
|
||
** If we've made it this far without finding a file, then look using the
|
||
** exact name the user gave me -- i.e. the old method.
|
||
**/
|
||
|
||
if( ret_val == TCL_ERROR) {
|
||
|
||
if( TCL_ERROR == (ret_val = Locate_ModuleFile( interp, oldmodule,
|
||
oldname, oldfile)))
|
||
if( OK != ErrorLogger( ERR_LOCATE, LOC, oldmodule, NULL))
|
||
goto unwind4;
|
||
|
||
/**
|
||
** OK, this one is known. Is it loaded, too?
|
||
**/
|
||
|
||
if( !IsLoaded( interp, oldname, NULL, oldfile))
|
||
if( OK != ErrorLogger( ERR_NOTLOADED, LOC, oldmodule, NULL))
|
||
goto unwind4;
|
||
}
|
||
|
||
/**
|
||
** Set the name of the module specified on the command line
|
||
**/
|
||
|
||
specified_module = newmodule;
|
||
|
||
/**
|
||
** Now try to find the new file to swap with.
|
||
**/
|
||
|
||
if( TCL_ERROR == (ret_val = Locate_ModuleFile( interp, newmodule, newname,
|
||
newfile)))
|
||
if( OK != ErrorLogger( ERR_LOCATE, LOC, newmodule, NULL))
|
||
goto unwind4;
|
||
|
||
ErrorLogger( NO_ERR_VERBOSE, LOC, "Switching '$1' to '$2'", oldmodule,
|
||
newmodule, NULL);
|
||
|
||
/**
|
||
** We'll remove the current modulefile with the SWITCH1 state set.
|
||
** This means that instead of really removing the paths, markers will
|
||
** be put in its place for later use.
|
||
**/
|
||
|
||
g_flags |= (M_REMOVE | M_SWSTATE1);
|
||
|
||
specified_module = oldmodule;
|
||
g_current_module = oldname;
|
||
if( Read_Modulefile( interp, oldfile) == 0)
|
||
Update_LoadedList( interp, oldname, oldfile);
|
||
else {
|
||
ErrorLogger( NO_ERR_VERBOSE, LOC, "failed", NULL);
|
||
goto unwind4;
|
||
}
|
||
|
||
g_flags &= ~(M_REMOVE | M_SWSTATE1);
|
||
|
||
/**
|
||
** Move on to state SWITCH2. This loads the modulefile at the append
|
||
** and prepend markers.
|
||
**/
|
||
|
||
g_flags |= M_SWSTATE2;
|
||
|
||
specified_module = newmodule;
|
||
g_current_module = newname;
|
||
if( Read_Modulefile( interp, newfile) == 0)
|
||
Update_LoadedList( interp, newname, newfile);
|
||
else {
|
||
ErrorLogger( NO_ERR_VERBOSE, LOC, "failed", NULL);
|
||
goto unwind4;
|
||
}
|
||
|
||
g_flags &= ~M_SWSTATE2;
|
||
|
||
/**
|
||
** This actually unsets environment variables and gets rid of the
|
||
** markers.
|
||
**/
|
||
|
||
g_flags |= (M_REMOVE | M_SWSTATE3);
|
||
|
||
specified_module = oldmodule;
|
||
g_current_module = oldname;
|
||
if( Read_Modulefile( interp, oldfile) == 0)
|
||
Update_LoadedList( interp, newname, newfile);
|
||
else {
|
||
ErrorLogger( NO_ERR_VERBOSE, LOC, "failed", NULL);
|
||
goto unwind4;
|
||
}
|
||
|
||
/**
|
||
** Return on success
|
||
**/
|
||
|
||
ErrorLogger( NO_ERR_VERBOSE, LOC, "done", NULL);
|
||
|
||
#if WITH_DEBUGGING_MODULECMD
|
||
fprintf( stderr, "ModuleCmd_Switch(%d):DEBUG: End\n", __LINE__);
|
||
#endif
|
||
/**
|
||
** free space
|
||
** assume don't need what's pointed to by g_current_module
|
||
** and specified_module
|
||
**/
|
||
null_free((void *) &newname);
|
||
null_free((void *) &oldname);
|
||
null_free((void *) &newfile);
|
||
null_free((void *) &oldfile);
|
||
|
||
return( TCL_OK); /** ------- EXIT (SUCCESS) --------> **/
|
||
|
||
unwind4:
|
||
null_free((void *) &newname);
|
||
unwind3:
|
||
null_free((void *) &oldname);
|
||
unwind2:
|
||
null_free((void *) &newfile);
|
||
unwind1:
|
||
null_free((void *) &oldfile);
|
||
unwind0:
|
||
return( TCL_ERROR); /** ------- EXIT (FAILURE) --------> **/
|
||
|
||
} /** End of 'ModuleCmd_Switch' **/
|
||
|