/* since when does 'main()' take three arguments? */ int main(int argc, char *argv[], char *environ[]) { Tcl_Interp *interp; int return_val = 0; char *rc_name; char *rc_path; #if WITH_DEBUGGING ErrorLogger(NO_ERR_START, LOC, _proc_main, NULL); #endif /* WITH_DEBUGGING */ /** ** check if first argument is --version or -V then output the ** version to stdout. This is a special circumstance handled ** by the regular options. **/ if ((argc > 1) && (*argv[1] == '-')) { if ((!strcmp("-V", argv[1])) || (!strcmp("--version", argv[1]))) { version(stdout); return 0; } } /** ** Initialization. ** Check the command line syntax. There will be no return from the ** initialization function in case of invalid command line arguments. **/ if (TCL_OK != Initialize_Tcl(&interp, argc, argv, environ)) { goto unwind0; } if (TCL_OK != Setup_Environment(interp)) { goto unwind0; } /** ** Check for command line switches **/ if (TCL_OK != Check_Switches(&argc, argv)) { goto unwind0; } /** ** Figure out, which global RC file to use. This depends on the environ- ** ment variable 'MODULERCFILE', which can be set to one of the following: ** ** <filename> --> PREFIX/etc/<filename> ** <dir>/ --> <dir>/RC_FILE ** <dir>/<file> --> <dir>/<file> ** Use xgetenv to expand 1 level of env.vars. **/ if ((rc_name = xgetenv("MODULERCFILE"))) { /* found something in MODULERCFILE */ if ((char *)NULL == (rc_path = stringer(NULL, 0, rc_name, NULL))) { if (OK != ErrorLogger(ERR_STRING, LOC, NULL)) { goto unwind1; } else { null_free((void *)&rc_name); } } else { null_free((void *)&rc_name); if ((char *)NULL == (rc_name = strrchr(rc_path, '/'))) { rc_name = rc_path; rc_path = instpath; } else { *rc_name++ = '\0'; } if (!*rc_name) { rc_name = rc_file; } } } else { rc_path = instpath; null_free((void *)&rc_name); rc_name = rc_file; } /** ** Finally we have to change PREFIX -> PREFIX/etc **/ if (rc_path == instpath) { if ((char *)NULL == (rc_path = stringer(NULL, 0, instpath, "/etc", NULL))) { if (OK != ErrorLogger(ERR_ALLOC, LOC, NULL)) { goto unwind1; } else { rc_path = NULL; } } } /** ** Source the global and the user defined RC file **/ g_current_module = (char *)NULL; if ((TCL_ERROR == SourceRC(interp, rc_path, rc_name)) || (TCL_ERROR == SourceRC(interp, getenv("HOME"), modulerc_file))) { exit(1); } if (rc_path) { null_free((void *)&rc_path); } /** ** Invocation of the module command as specified in the command line **/ g_flags = 0; return_val = cmdModule((ClientData)0, interp, (argc - 1), (CONST84 char **)(argv + 1)); /** ** If we were doing some operation that has already flushed its output, ** then we do NOT need to re-flush the output here. ** ** Also, if we have had an error here, then the whole modulecmd failed ** and not just the values for a single modulefile. So, we shall pass in ** a NULL here to indicate that any error message should say that ** absolutely NO changes were made to the environment. **/ if (TCL_OK == return_val) { Output_Modulefile_Changes(interp); #ifdef HAS_X11LIBS xresourceFinish(1); #endif /* HAS_X11LIBS */ } else { Unwind_Modulefile_Changes(interp, NULL); #ifdef HAS_X11LIBS xresourceFinish(0); #endif /* HAS_X11LIBS */ } /** ** Finally clean up. Delete the required hash tables and conditionally ** allocated areas. **/ Delete_Global_Hash_Tables(); if (line) { null_free((void *)&line); } if (error_line) { null_free((void *)&error_line); } /** ** This return value may be evaluated by the calling shell: **/ #if WITH_DEBUGGING ErrorLogger(NO_ERR_END, LOC, _proc_main, NULL); #endif /* WITH_DEBUGGING */ OutputExit(); return (return_val ? return_val : g_retval); unwind2: null_free((void *)&rc_path); unwind1: null_free((void *)&rc_name); unwind0: /* an error occurred of some type */ g_retval = (g_retval ? g_retval : 1); OutputExit(); return (g_retval); } /** End of 'main' **/
int main( int argc, char *argv[], char *environ[] ) { Tcl_Interp *interp; int return_val = 0; char *rc_name; char *rc_path; Tcl_Obj **objv; /** Tcl Object vector **/ int objc; /** Tcl Object vector count **/ #ifdef HAVE_SETLOCALE /* set local via LC_ALL */ setlocale(LC_ALL, ""); #endif #if ENABLE_NLS /* the text message domain. */ bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif /** ** check if first argument is --version or -V then output the ** version to stdout. This is a special circumstance handled ** by the regular options. **/ if (argc > 1 && *argv[1] == '-') { if (!strcmp("-V", argv[1]) || !strcmp("--version", argv[1])) { version(stdout); return 0; } } /** ** Initialization. **/ if (!(ModulePathVec = ModulePathList())) { ModulePath = NULL; /* goto unwind0; */ } else { ModulePath = uvec_vector(ModulePathVec); } /** ** Check the command line syntax. There will be no return from the ** initialization function in case of invalid command line arguments. **/ if (TCL_OK != Initialize_Module(&interp, argc, argv, environ)) goto unwind1; if (TCL_OK != Setup_Environment(interp)) goto unwind1; /** ** Check for command line switches **/ if (TCL_OK != Check_Switches(&argc, argv)) goto unwind1; /** ** Figure out, which global RC file to use. This depends on the environ- ** ment variable 'MODULERCFILE', which can be set to one of the following: ** ** <filename> --> SYSCONFDIR/<filename> ** <dir>/ --> <dir>/RC_FILE ** <dir>/<file> --> <dir>/<file> ** Use xgetenv to expand 1 level of env.vars. **/ if ((rc_name = xgetenv("MODULERCFILE"))) { /* found something in MODULERCFILE */ if (!(rc_path = stringer(NULL, 0, rc_name, NULL))) { if (OK != ErrorLogger(ERR_STRING, LOC, NULL)) goto unwind2; else null_free((void *)&rc_name); } else { null_free((void *)&rc_name); if (!(rc_name = strrchr(rc_path, *psep))) { rc_name = rc_path; rc_path = etcpath; } else *rc_name++ = '\0'; if (!*rc_name) { rc_name = rc_file; } } } else { rc_path = stringer(NULL,0, etcpath, NULL); null_free((void *)&rc_name); rc_name = rc_file; } /** ** Source the global and the user defined RC file **/ g_current_module = (char *)NULL; if (TCL_ERROR == SourceRC(interp, rc_path, rc_name, Mod_Load) || TCL_ERROR == SourceRC(interp,getenv("HOME"),modulerc_file,Mod_Load)) exit(1); if (rc_path) null_free((void *)&rc_path); /** ** Invocation of the module command as specified in the command line **/ g_flags = 0; Tcl_ArgvToObjv(&objc, &objv, argc - 1, argv + 1); return_val = cmdModule((ClientData) 0, interp, objc, objv); /** ** If we were doing some operation that has already flushed its output, ** then we don't need to re-flush the output here. ** ** Also, if we've had an error here, then the whole modulecmd failed ** and not just the values for a single modulefile. So, we'll pass in ** a NULL here to indicate that any error message should say that ** absolutely NO changes were made to the environment. **/ if (TCL_OK == return_val) { Output_Modulefile_Changes(interp); #ifdef HAS_X11LIBS xresourceFinish(1); #endif } else { Unwind_Modulefile_Changes(interp, NULL); #ifdef HAS_X11LIBS xresourceFinish(0); #endif } /** ** Finally clean up. Delete the required hash tables and conditionally ** allocated areas. **/ Global_Hash_Tables(GHashDelete, NULL); if (line) null_free((void *)&line); if (error_line) null_free((void *)&error_line); /** ** This return value may be evaluated by the calling shell **/ OutputExit(); return (return_val ? return_val : g_retval); /* unwind3: null_free((void *) &rc_path); */ unwind2: null_free((void *)&rc_name); unwind1: FreeList(&ModulePathVec); unwind0: /* and error occurred of some type */ g_retval = (g_retval ? g_retval : 1); OutputExit(); return (g_retval); } /** End of 'main' **/
static char *GetModuleName(Tcl_Interp *interp, char *path, char *prefix, char *modulename) { struct stat stats; /** Buffer for the stat() systemcall **/ char *fullpath = NULL; /** Buffer for creating path names **/ char *Result = NULL; /** Our return value **/ char **filelist = NULL; /** Buffer for a list of possible ** module files **/ int numlist; /** Size of this list **/ int i, slen, is_def; char *s, *t; /** Private string buffer **/ char *mod, *ver; /** Pointer to module and version **/ char *mod1, *ver1; /** Temp pointer **/ #if WITH_DEBUGGING_LOCATE_1 ErrorLogger(NO_ERR_START, LOC, _proc_GetModuleName, NULL); #endif /* WITH_DEBUGGING_LOCATE_1 */ /** ** Split the modulename into module and version. Use a private buffer ** for this **/ if ((char *)NULL == (s = stringer(NULL, 0, modulename, NULL))) { ErrorLogger(ERR_ALLOC, LOC, NULL); goto unwind0; } slen = (int)(strlen(s) + 1); mod = s; /* assume that the '=' here is correct, because otherwise 'ver' would not * be initialized here yet (I think): */ if ((ver = strrchr(mod, '/'))) { *ver++ = '\0'; } /** ** Allocate a buffer for full pathname building: **/ if ((char *)NULL == (fullpath = stringer(NULL, MOD_BUFSIZE, NULL))) { if (OK != ErrorLogger(ERR_STRING, LOC, NULL)) { goto unwind1; } } /** ** Check whether $path/$prefix/$modulename is a directory. **/ if (prefix) { if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", prefix, "/", modulename, NULL)) { goto unwind1; } } else { if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", modulename, NULL)) { goto unwind1; } } if (!stat(fullpath, &stats) && S_ISDIR(stats.st_mode)) { /** ** So the full modulename is $modulename/default. Recurse on that. **/ if ((char *)NULL == (t = stringer(NULL, 0, modulename, "/", _default, NULL))) { goto unwind1; } Result = GetModuleName(interp, path, prefix, t); null_free((void *)&t); null_free((void *)&fullpath); null_free((void *)&s); return (Result); } /** ** Check whether $path/$prefix/$mod is a directory: **/ if (prefix) { if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", prefix, "/", mod, NULL)) { goto unwind1; } } else { if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", mod, NULL)) { goto unwind1; } } is_def = !strcmp(mod, _default); if (is_def || !stat(fullpath, &stats)) { /** ** If it is a directory, then do this: **/ if (!is_def && S_ISDIR( stats.st_mode)) { /** ** Source the ".modulerc" file if it exists. ** For compatibility source the .version file, too. **/ if (prefix) { if ((char *)NULL == stringer(modfil_buf, MOD_BUFSIZE, prefix, "/", mod, NULL)) { goto unwind2; } } else { if ((char *)NULL == stringer(modfil_buf, MOD_BUFSIZE, mod, NULL)) { goto unwind2; } } if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", modfil_buf, NULL)) { goto unwind2; } g_current_module = modfil_buf; if ((TCL_ERROR == SourceRC(interp, fullpath, modulerc_file)) || (TCL_ERROR == SourceVers(interp, fullpath, modfil_buf))) { /* flags = save_flags; */ goto unwind2; } /** ** After sourcing the RC files, we have to look up the ** versions again: **/ if (VersionLookup(modulename, &mod1, &ver1)) { int len = (int)(strlen(mod1) + strlen(ver1) + 2); /** ** Maybe we have to enlarge s: **/ if (len > slen) { null_free((void *)&s); if((char *)NULL == (s = stringer( NULL, len, NULL))) { ErrorLogger( ERR_STRING, LOC, NULL); goto unwind2; } slen = len; /* dummy condition to use 'slen': */ if (slen == 0) { ; } } /** ** Print the new module/version in the buffer: **/ if ((char *)NULL == stringer(s, len, mod1, "/", ver1, NULL)) { ErrorLogger(ERR_STRING, LOC, NULL); goto unwind2; } mod = s; if (ver = strchr(s, (int)'/')) { *ver++ = '\0'; } } /** ** recursively delve into subdirectories (until ver == NULL). **/ if (ver) { int len; len = (int)(strlen(mod) + 1); if (prefix) { len += (strlen(prefix) + 1); } /** ** Build the new prefix **/ if((char *) NULL == (t = stringer(NULL, len, NULL))) { ErrorLogger( ERR_STRING, LOC, NULL); goto unwind2; } if( prefix) { if((char *) NULL == stringer(t, len, prefix,"/",mod, NULL)){ ErrorLogger( ERR_STRING, LOC, NULL); goto unwindt; } } else { if((char *) NULL == stringer(t, len, mod, NULL)){ ErrorLogger( ERR_STRING, LOC, NULL); goto unwindt; } } /** ** This is the recursion **/ Result = GetModuleName( interp, path, t, ver); /** ** Free our temporary prefix buffer **/ null_free((void *) &t); if (0) { /* an error occurred */ unwindt: null_free((void *) &t); goto unwind2; } } } else { /** if ($path/$prefix/$mod is a directory) **/ /** ** Now 'mod' should be either a file or the word 'default' ** In case of default get the file with the highest version number ** in the current directory **/ if( is_def) { if( !prefix) prefix = "."; if( NULL == (filelist = SortedDirList( interp, path, prefix, &numlist))) goto unwind1; prefix = (char *)NULL; /** ** Select the first one on the list which is either a ** modulefile or another directory. We start at the highest ** lexicographical name in the directory since the filelist ** is reverse sorted. ** If it is a directory, then we delve into it. **/ for( i=0; i<numlist && Result==NULL; i++) { /** ** Build the full path name and check if it is a ** directory. If it is, recursively try to find there what ** we are/were seeking for **/ if ((char *)NULL == stringer(fullpath, MOD_BUFSIZE, path, "/", filelist[i], NULL)) goto unwind2; if( !stat( fullpath, &stats) && S_ISDIR( stats.st_mode)) { Result = GetModuleName( interp, path, prefix, filelist[ i]); } else { /** ** Otherwise check the file for a magic cookie ... **/ if( check_magic( fullpath, MODULES_MAGIC_COOKIE, MODULES_MAGIC_COOKIE_LENGTH)) Result = filelist[ i]; } /** end "if (!stat)" **/ } /** end for-loop **/ } else { /** default **/ /** ** If mod names a file, we have to check wheter it exists and ** is a valid module file **/ if( check_magic( fullpath, MODULES_MAGIC_COOKIE, MODULES_MAGIC_COOKIE_LENGTH)) Result = mod; else { ErrorLogger( ERR_MAGIC, LOC, fullpath, NULL); Result = NULL; } } /** if( mod is a filename) **/ /** ** Build the full filename (using prefix and Result) if ** Result is defined **/ if (Result) { int len; len = (int)(strlen(Result) + 1); if (prefix) { len += (strlen(prefix) + 1); } if((char *) NULL == (t = stringer(NULL, len, NULL))) { ErrorLogger( ERR_STRING, LOC, NULL); goto unwind2; } if( prefix) { if((char *) NULL == stringer(t,len, prefix,"/",Result,NULL)) goto unwindt2; } else { if((char *) NULL == stringer(t,len, Result,NULL)) goto unwindt2; } Result = t; if (0) { /* an error occurred */ unwindt2: null_free((void *) &t); goto unwind2; } } } /** mod is a file **/ } /** mod exists **/ /** ** Free up temporary values and return what we've found **/ null_free((void*) &fullpath); null_free((void*) &s); FreeList(filelist, numlist); #if WITH_DEBUGGING_LOCATE_1 ErrorLogger(NO_ERR_END, LOC, _proc_GetModuleName, NULL); #endif /* WITH_DEBUGGING_LOCATE_1 */ return (Result); /** -------- EXIT (SUCCESS) -------> **/ unwind2: null_free((void *)&fullpath); unwind1: null_free((void *)&s); unwind0: return(NULL); /** -------- EXIT (FAILURE) -------> **/ } /** End of 'GetModuleName' (that was a lengthy function...) **/
int ModuleCmd_List( Tcl_Interp *interp, int argc, char *argv[]) { /** ** Get the list of loaded modules at first **/ char *loaded, *lmfiles; int i, count1, count2; char *list[ MOD_BUFSIZE]; char *files[ MOD_BUFSIZE]; char *tmplist[ MOD_BUFSIZE], *s; int len; #if WITH_DEBUGGING_MODULECMD ErrorLogger( NO_ERR_START, LOC, _proc_ModuleCmd_List, NULL); #endif lmfiles = getLMFILES( interp); loaded = getenv( "LOADEDMODULES"); if( !loaded || !*loaded) { if( sw_format & (SW_TERSE | SW_LONG | SW_HUMAN) ) fprintf(stderr, "No Modulefiles Currently Loaded.\n"); } else { /** ** Now tokenize it, form a list and print it out. **/ if( sw_format & SW_LONG ) { fprintf( stderr, long_header); } if( sw_format & (SW_TERSE | SW_LONG | SW_HUMAN) ) fprintf( stderr, "Currently Loaded Modulefiles:\n"); /** ** LOADEDMODULES and _LMFILES_ should provide a list of loaded ** modules and assigned files in the SAME ORDER ** but double check, because if they aren't you will get a crash. **/ count1 = 1; for( list[ 0] = xstrtok( loaded, ":"); list[ count1] = xstrtok( NULL, ":"); count1++ ); count2 = 1; for( files[ 0] = xstrtok( lmfiles, ":"); files[ count2] = xstrtok( NULL, ":"); count2++ ); if (count1 != count2) { ErrorLogger( ERR_ENVVAR, LOC, NULL); } /** ** We have to build a single list of files for each loaded entry ** in order to be able to figure out the length of the directory ** part **/ for( i=0; i<count1; i++) { len = strlen( files[i]) - strlen( list[i]); tmplist[i] = files[i]; /** ** We have to source all relevant .modulerc and .version files ** on the path **/ s = files[i] + len; while( s) { if( s = strchr( s, '/')) *s = '\0'; SourceRC( interp, files[i], modulerc_file); SourceVers( interp, files[i], list[i]); if( s) *s++ = '/'; } /** ** Print this guy **/ } print_aligned_files( interp, NULL, NULL, tmplist, count1, 1); } /** ** Return on success **/ #if WITH_DEBUGGING_MODULECMD ErrorLogger( NO_ERR_END, LOC, _proc_ModuleCmd_List, NULL); #endif return( TCL_OK); } /** End of 'ModuleCmd_List' **/