** ** Module Header ******************************************************* **
** **
** Modules Revision 3.0 **
** Providing a flexible user environment **
** **
** File: utility.c **
** First Edition: 91/10/23 **
** **
** Authors: John Furlan, jlf@behere.com **
** Jens Hamisch, jens@Strawberry.COM **
** **
** Description: General routines that are called throughout Modules **
** which are not necessarily specific to any single **
** block of functionality. **
** **
** Exports: store_hash_value **
** clear_hash_value **
** Delete_Global_Hash_Tables **
** Delete_Hash_Tables **
** Copy_Hash_Tables **
** Unwind_Modulefile_Changes **
** Output_Modulefile_Changes **
** set_derelict **
** IsLoaded_ExactMatch **
** IsLoaded **
** chk_marked_entry **
** set_marked_entry **
** Update_LoadedList **
** ForceBasePath **
** ForceSacredPath **
** check_magic **
** cleanse_path **
** chk4spch **
** xdup **
** xgetenv **
** **
** strdup if not defined by the system libs. **
** strtok if not defined by the system libs. **
** **
** Notes: **
** **
** ************************************************************************ **
Included Files
- #include "modules_def.h"
- #include <stdio.h>
- #include <tcl.h>
- #include "config.h"
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <ctype.h>
- #include <sys/stat.h>
- #include <sys/termios.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <dirent.h>
- #include <errno.h>
Local Variables
Id
static char Id[]
UseId
static void* UseId[]
module_name
static char module_name[]
cmd_separator
static char cmd_separator
aliasfile
static FILE* aliasfile
alias_separator
static char alias_separator
** ** Function-Header ***************************************************** **
** **
** Function: Copy_Hash_Tables **
** **
** Description: Allocate new hash tables for the global environment, **
** initialize them and copy the contents of the current **
** tables into them. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: - **
** Result: Tcl_HashTable** Pointer to the new list of **
** hash tables **
** Attached Globals: setenvHashTable, **
** unsetenvHashTable, **
** aliasSetHashTable, **
** aliasUnsetHashTable **
** **
** ************************************************************************ **
Tcl_HashTable** Copy_Hash_Tables ( void )
** ** Function-Header ***************************************************** **
** **
** Function: Delete_Global_Hash_Tables **
** Delete_Hash_Tables **
** **
** Description: Deletes our environment hash tables. **
** **
** First Edition: 92/10/14 **
** **
** Parameters: Tcl_HashTable **table_ptr NULL-Terminated list **
** of hash tables to be **
** deleted **
** Result: - **
** **
** Attached Globals: setenvHashTable, **
** unsetenvHashTable, **
** aliasSetHashTable, **
** aliasUnsetHashTable **
** **
** ************************************************************************ **
void Delete_Global_Hash_Tables ( void )
void Delete_Hash_Tables ( Tcl_HashTable** table_ptr )
int ForceBasePath ( Tcl_Interp* interp, char* variable_name, char* force_pathname )
** ** Function-Header ***************************************************** **
** **
** Function: ForceBasePath **
** **
** Description: Remove and than add the passed value from/to the **
** passed variable. After removal, the module-path is **
** APPENDED to the passed variable if 'ForceBasePath' **
** has been called and PREPENDED if it was **
** 'ForceSacredPath' **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp Attached Tcl interpr.**
** char *variable_name Attached variable **
** char *force_pathname Name of the path to **
** be removed/added **
** **
** Result: int 1 Successfull operation **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
int ForceSacredPath ( Tcl_Interp* interp, char* variable_name, char* force_pathname )
int IsLoaded ( Tcl_Interp* interp, char* modulename, char** realname, char* filename )
int IsLoaded_ExactMatch ( Tcl_Interp* interp, char* modulename, char** realname, char* filename )
** ** Function-Header ***************************************************** **
** **
** Function: Output_Modulefile_Changes **
** **
** Description: Is used to flush out the changes of the current **
** modulefile in a manner depending upon whether the **
** modulefile was successfull or unsuccessfull. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp The attached Tcl in- **
** terpreter **
** **
** Result: int TCL_OK Successful operation **
** **
** Attached Globals: setenvHashTable, **
** unsetenvHashTable, **
** aliasSetHashTable, via Output_Modulefile_Aliases**
** aliasUnsetHashTable via Output_Modulefile_Aliases**
** **
** ************************************************************************ **
int Output_Modulefile_Changes ( Tcl_Interp* interp )
** ** Function-Header ***************************************************** **
** **
** Function: **
** **
** Description: Once a the loading or unloading of a modulefile **
** fails, any changes it has made to the environment **
** must be undone and reset to its previous state. This **
** function is responsible for unwinding any changes a **
** modulefile has made. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp According TCL interp.**
** Tcl_HashTable **oldTables Hash tables storing **
** the former environm. **
** Result: **
** Attached Globals: **
** **
** ************************************************************************ **
int Unwind_Modulefile_Changes ( Tcl_Interp* interp, Tcl_HashTable** oldTables )
** ** Function-Header ***************************************************** **
** **
** Function: Update_LoadedList **
** **
** Description: Add or remove the passed modulename and filename to/ **
** from LOADEDMODULES and _LMFILES_ **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp Attached Tcl Interp. **
** char *modulename Name of the module **
** char *filename Full path name of the**
** related modulefile **
** **
** Result: int 1 Successfull operation **
** **
** Attached Globals: g_flags Controls whether the modulename **
** should be added (M_XXXX) or removed **
** (M_REMOVE) from the list of loaded **
** modules **
** **
** ************************************************************************ **
int Update_LoadedList ( Tcl_Interp* interp, char* modulename, char* filename )
** ** Function-Header ***************************************************** **
** **
** Function: check_magic **
** **
** Description: Check the magic cookie of the file passed as para- **
** meter if it is a valid module file **
** Based on check_magic in Richard Elling's **
** find_by_magic <Richard.Elling"@eng.auburn.edu> **
** **
** First Edition: 91/10/23 **
** **
** Parameters: char *filename Name of the file to check **
** char *magic_name Magic cookie **
** int magic_len Length of the magic cookie **
** **
** Result: int 0 Magic cookie doesn't match or any **
** I/O error **
** 1 Success - Magic cookie has matched **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
int check_magic ( char* filename, char* magic_name, int magic_len )
** ** Function-Header ***************************************************** **
** **
** Function: chk4spch **
** **
** Description: goes through the given string and changes any non- **
** printable characters to question marks. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: char *s String to be checke **
** **
** Result: *s Will be changed accordingly **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
void chk4spch ( char* s )
** ** Function-Header ***************************************************** **
** **
** Function: chk_marked_entry, set_marked_entry **
** **
** Description: When switching, the variables are marked with a mar- **
** ker that is tested to see if the variable was changed**
** in the second modulefile. If it was not, then the **
** variable is unset. **
** **
** First Edition: 92/10/25 **
** **
** Parameters: Tcl_HashTable *table Attached hash table **
** char *var According variable name **
** int val Value to be set. **
** **
** Result: int 0 Mark not set (or the value of the **
** mark was 0 ;-) **
** else Value of the mark that has been set **
** with set_marked_entry. **
** Attached Globals: - **
** **
** ************************************************************************ **
int chk_marked_entry ( Tcl_HashTable* table, char* var )
** ** Function-Header ***************************************************** **
** **
** Function: cleanse_path **
** **
** Description: Copy the passed path into the new path buffer and **
** devalue '.' and '+' **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *path Original path **
** char *newpath Buffer for to copy the new **
** path in **
** int len Max length of the new path **
** **
** Result: newpath will be filled up with the new, de- **
** valuated path **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
void cleanse_path ( const char* path, char* newpath, int len )
** ** Function-Header ***************************************************** **
** **
** Function: clear_hash_value **
** **
** Description: Remove the specified shell variable from the passed **
** hash table **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_HashTable *htable Hash table to be used**
** const char *key Attached key **
** **
** Result: int TCL_OK Successfull completion **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
int clear_hash_value ( Tcl_HashTable* htable, const char* key )
** ** Function-Header ***************************************************** **
** **
** Function: getLMFILES **
** **
** Description: Read in the _LMFILES_ environment variable. This one **
** may be split into several variables cause by limited **
** variable space of some shells (esp. the SUN csh) **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp Attached Tcl interpreter **
** **
** Result: char* Value of the environment varibale _LMFILES_ **
** **
** Attached Globals: **
** **
** ************************************************************************ **
char* getLMFILES ( Tcl_Interp* interp )
** ** Function-Header ***************************************************** **
** **
** Function: set_derelict **
** **
** Description: Normalize the current calling shell to one of the **
** basic shells definig the varaible and alias syntax **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *name Invoking shell name **
** **
** Result: char* Shell derelict name **
** **
** Attached Globals: shell_derelict **
** **
** ************************************************************************ **
char* set_derelict ( const char* name )
void set_marked_entry ( Tcl_HashTable* table, char* var, int val )
** ** Function-Header ***************************************************** **
** **
** Function: store_hash_value **
** **
** Description: Keeps the old value of the variable around if it is **
** touched in the modulefile to enable undoing a **
** modulefile by resetting the evironment to it started.**
** **
** This is the same for unset_shell_variable() **
** **
** First Edition: 92/10/14 **
** **
** Parameters: Tcl_HashTable *htable Hash table to be used**
** const char *key Attached key **
** const char *value Alias value **
** **
** Result: int TCL_OK Successfull completion **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
int store_hash_value ( Tcl_HashTable* htable, const char* key, const char* value )
** ** Function-Header ***************************************************** **
** **
** Function: xdup **
** **
** Description: will return a string with 1 level of environment **
** variables expanded. The limit is MOD_BUFSIZE. **
** An env.var. is denoted with either $name or ${name} **
** \$ escapes the expansion and substitutes a '$' in **
** its place. **
** **
** First Edition: 2000/01/21 **
** **
** Parameters: char *string Environment variable **
** **
** Result: char * An allocated string **
** **
** ************************************************************************ **
zero out buffers
char* xdup ( char const* string )
** ** Function-Header ***************************************************** **
** **
** Function: xgetenv **
** **
** Description: will return an expanded environment variable. **
** However, it will only expand 1 level. **
** See xdup() for details. **
** **
** First Edition: 2000/01/18 **
** **
** Parameters: char *var Environment variable **
** **
** Result: char * An allocated string **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
char* xgetenv ( char const* var )
** ** Function-Header ***************************************************** **
** **
** Function: Clear_Global_Hash_Tables **
** **
** Description: Deletes and reinitializes our env. hash tables. **
** **
** First Edition: 92/10/14 **
** **
** Parameters: - **
** Result: - **
** **
** Attached Globals: setenvHashTable, **
** unsetenvHashTable, **
** aliasSetHashTable, **
** aliasUnsetHashTable **
** **
** ************************************************************************ **
static void Clear_Global_Hash_Tables ( void )
static int ForcePath ( Tcl_Interp* interp, char* variable_name, char* force_pathname, int append )
** ** Function-Header ***************************************************** **
** **
** Function: Output_Modulefile_Aliases **
** **
** Description: Is used to flush out the changes to the aliases of **
** the current modulefile. But, some shells don't work **
** well with having their alias information set via the **
** 'eval' command. So, what we'll do now is output the **
** aliases into a /tmp dotfile, have the shell source **
** the /tmp dotfile and then have the shell remove the **
** /tmp dotfile. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp The attached Tcl in- **
** terpreter **
** **
** Result: int TCL_OK Successful operation **
** **
** Attached Globals: aliasSetHashTable, via Output_Modulefile_Aliases**
** aliasUnsetHashTable via Output_Modulefile_Aliases**
** **
** ************************************************************************ **
static int Output_Modulefile_Aliases ( Tcl_Interp* interp )
** Oops! Fewer entries in the list of loaded modulefiles
** than in the list of loaded modules. This will
** generally suggest that _LMFILES_ has become corrupted,
** but it may just mean we're working intermittantly with
** an old version. So, I'll just not touch filename which
** means the search will continue using the old method of
** looking through MODULEPATH.
static int __IsLoaded ( Tcl_Interp* interp, char* modulename, char** realname, char* filename, int exact )
** ** Function-Header ***************************************************** **
** **
** Function: chop **
** **
** Description: Remove '\n' characters from the passed string **
** **
** First Edition: 91/10/23 **
** **
** Parameters: char *string String to be chopped **
** **
** Result: string The chopped string **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
static char* chop ( const char* string )
** ** Function-Header ***************************************************** **
** **
** Function: get_module_basename **
** **
** Description: Get the name of a module without its version. **
** This function modifies the string passed in. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: char *modulename Full module name **
** **
** Result: char* Module name without version **
** **
** Attached Globals: **
** **
** ************************************************************************ **
static char* get_module_basename ( char* modulename )
** ** Function-Header ***************************************************** **
** **
** Function: output_function **
** **
** Description: Actually turns the Modules set-alias information **
** into a string that a shell can source. Previously, **
** this routine just output the alias information to be **
** eval'd by the shell. **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *var Name of the alias to be set **
** const char *val Value to be assigned **
** **
** Result: - **
** **
** Attached Globals: aliasfile, The output file for alias commands. **
** see 'Output_Modulefile_Aliases' **
** alias_separator **
** **
** ************************************************************************ **
static void output_function ( const char* var, const char* val )
** ** Function-Header ***************************************************** **
** **
** Function: output_set_alias **
** **
** Description: Flush the commands required to set shell aliases de- **
** pending on the current invoking shell **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *alias Name of the alias **
** const char *val Value to be assigned **
** **
** Result: int TCL_OK Operation successfull **
** **
** Attached Globals: aliasfile, The alias command is writte out to **
** alias_separator Defined the command separator **
** shell_derelict to determine the shell family **
** shell_name to determine the real shell type **
** **
** ************************************************************************ **
static int output_set_alias ( const char* alias, const char* val )
** ** Function-Header ***************************************************** **
** **
** Function: output_set_variable **
** **
** Description: Outputs the command required to set a shell variable **
** according to the current shell **
** **
** First Edition: 91/10/23 **
** **
** Parameters: Tcl_Interp *interp The attached Tcl interpreter **
** const char *var Name of the variable to be **
** set **
** const char *val Value to be assigned **
** **
** Result: int TCL_OK Finished successfull **
** TCL_ERROR Unknown shell type **
** **
** Attached Globals: shell_derelict **
** **
** ************************************************************************ **
static int output_set_variable ( Tcl_Interp* interp, const char* var, const char* val )
** ** Function-Header ***************************************************** **
** **
** Function: output_unset_alias **
** **
** Description: Flush the commands required to reset shell aliases **
** depending on the current invoking shell **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *alias Name of the alias **
** const char *val Value which has been **
** assigned **
** **
** Result: int TCL_OK Operation successfull **
** **
** Attached Globals: aliasfile, The alias command is writte out to **
** alias_separator Defined the command separator **
** shell_derelict to determine the shell family **
** shell_name to determine the real shell type **
** **
** ************************************************************************ **
static int output_unset_alias ( const char* alias, const char* val )
** ** Function-Header ***************************************************** **
** **
** Function: output_unset_variable **
** **
** Description: Outputs the command required to unset a shell **
** variable according to the current shell **
** **
** First Edition: 91/10/23 **
** **
** Parameters: const char *var Name of the variable to be **
** unset **
** **
** Result: int TCL_OK Finished successfull **
** TCL_ERROR Unknown shell type **
** **
** Attached Globals: shell_derelict **
** **
** ************************************************************************ **
static int output_unset_variable ( const char* var )