1    | /*****
2    |  ** ** Module Header ******************************************************* **
3    |  ** 									     **
4    |  **   Modules Revision 3.0						     **
5    |  **   Providing a flexible user environment				     **
6    |  ** 									     **
7    |  **   File:		ModuleCmd_Init.c				     **
8    |  **   First Edition:	91/10/23					     **
9    |  ** 									     **
10   |  **   Authors:	John Furlan, jlf@behere.com				     **
11   |  **		Jens Hamisch, jens@Strawberry.COM			     **
12   |  ** 									     **
13   |  **   Description:	Routines that act on a user's "dot" startup files to **
14   |  **			add, remove, and list modulefiles to/from/in their   **
15   |  **			startup files.					     **
16   |  ** 									     **
17   |  **   Exports:		ModuleCmd_Init					     **
18   |  ** 									     **
19   |  **   Notes:								     **
20   |  ** 									     **
21   |  ** ************************************************************************ **
22   |  ****/
23   | 
24   | /** ** Copyright *********************************************************** **
25   |  ** 									     **
26   |  ** Copyright 1991-1994 by John L. Furlan.                      	     **
27   |  ** see LICENSE.GPL, which must be provided, for details		     **
28   |  ** 									     ** 
29   |  ** ************************************************************************ **/
30   | 
31   | static char Id[] = "@(#)$Id: ModuleCmd_Init.c.src.html,v 1.2 2005/11/25 20:09:37 rkowen Exp $";
32   | static void *UseId[] = { &UseId, Id };
33   | 
34   | /** ************************************************************************ **/
35   | /** 				      HEADERS				     **/
36   | /** ************************************************************************ **/
37   | 
38   | #include "modules_def.h"
39   | 
40   | /** ************************************************************************ **/
41   | /** 				  LOCAL DATATYPES			     **/
42   | /** ************************************************************************ **/
43   | 
44   | /** not applicable **/
45   | 
46   | /** ************************************************************************ **/
47   | /** 				     CONSTANTS				     **/
48   | /** ************************************************************************ **/
49   | 
50   | /** not applicable **/
51   | 
52   | /** ************************************************************************ **/
53   | /**				      MACROS				     **/
54   | /** ************************************************************************ **/
55   | 
56   | /** not applicable **/
57   | 
58   | /** ************************************************************************ **/
59   | /** 				    LOCAL DATA				     **/
60   | /** ************************************************************************ **/
61   | 
62   | static	char	module_name[] = "ModuleCmd_Init.c";	/** File name of this module **/
63   | 
64   | #if WITH_DEBUGGING_MODULECMD
65   | static	char	_proc_ModuleCmd_Init[] = "ModuleCmd_Init";
66   | #endif
67   | 
68   | /** ************************************************************************ **/
69   | /**				    PROTOTYPES				     **/
70   | /** ************************************************************************ **/
71   | 
72   | /** not applicable **/
73   | 
74   | /** ************************************************************************ **/
75   | /**				    STATIC FUNCTIONS			     **/
76   | /** ************************************************************************ **/
77   | 
78   | /* Handles the output of a substring where the start & ending positions
79   |  * are given - if either is NULL then just do nothing and return -1
80   |  * all other cases it returns 0
81   |  */
82   | static int out_substr(FILE *stream, char *start, char *end) {
83   | 	char save;
84   | 
85   | 	if (!start || !end) return -1;
86   | 
87   | 	save = *end;
88   | 	*end = '\0';
89   | 	fputs(start, stream);
90   | 	*end = save;
91   | 	return 0;
92   | }
93   | 
94   | 
95   | /*++++
96   |  ** ** Function-Header ***************************************************** **
97   |  ** 									     **
98   |  **   Function:		ModuleCmd_Init					     **
99   |  ** 									     **
100  |  **   Description:	Execution of the module-command 'init'		     **
101  |  ** 									     **
102  |  **   First Edition:	91/10/23					     **
103  |  ** 									     **
104  |  **   Parameters:	Tcl_Interp	*interp		Attached Tcl Interp. **
105  |  **			int		 argc		Number of arguments  **
106  |  **			char 		*argv[]		Argument list	     **
107  |  ** 									     **
108  |  **   Result:		int	TCL_ERROR	Failure			     **
109  |  **				TCL_OK		Successfull operation	     **
110  |  ** 									     **
111  |  **   Attached Globals:	g_flags		These are set up accordingly before  **
112  |  **					this function is called in order to  **
113  |  **					control everything		     **
114  |  ** 									     **
115  |  ** ************************************************************************ **
116  |  ++++*/
117  | 
118  | int	ModuleCmd_Init(	Tcl_Interp	*interp,
119  | 	       		int            	 argc,
120  | 	       		char		*argv[])
121  | {
122  |     char	 *home_pathname,
123  | 		 *home_pathname2,
124  | 		 **shell_startups;	/** A list off all startup files our **/                                        /** invoking shell will source       **/
125  |     int		  max_home_path = MOD_BUFSIZE + 40;
126  |     Tcl_RegExp	 modcmdPtr = Tcl_RegExpCompile(interp,
127  | 	"^([ \t]*module[ \t]+)(load|add)[ \t]+([^#\n]*)([#.\n]*)");
128  |     char	**modlist,
129  | 		 *home,
130  | 		 *buffer,
131  | 		  ch,
132  | 		 *startp, *endp;
133  |     FILE	 *fileptr, *newfileptr;
134  |     int		  i, j,
135  | 		  found_module_command = 0,
136  | 		  found_modload_flag = 0,
137  | 		  shell_num = 0,
138  | 		  nummods, bufsiz = 8192,
139  | 		  homelen, home_end, path_end,
140  | 		  sw_found = 0, rm_found = 0;
141  | 
142  | #if WITH_DEBUGGING_MODULECMD
143  |     ErrorLogger( NO_ERR_START, LOC, _proc_ModuleCmd_Init, NULL);
144  | #endif
145  | 
146  |     /**
147  |      **  If called with no arguments and the flags don't say that there's some-
148  |      **  thing to do - exit now!
149  |      **/
150  |     if( argc < 1 && !(g_flags & (M_DISPLAY | M_CLEAR)))
151  | 	goto success0;
152  |   
153  |     /**
154  |      **  Parameter check for the initswitch command
155  |      **/
156  |     if(g_flags & M_SWITCH) {
157  | 	argc--;
158  | 	if(argc != 1)
159  | 	    if( OK != ErrorLogger( ERR_USAGE, LOC,
160  | 		"initswitch oldmodule newmodule", NULL))
161  | 		goto unwind0;
162  |     }
163  |   
164  |     /**
165  |      **  Where's my HOME?
166  |      **/
167  |     if((char *) NULL == (home = (char *) getenv("HOME")))
168  | 	if( OK != ErrorLogger( ERR_HOME, LOC, NULL))
169  | 	    goto unwind1;
170  |       
171  |     /**
172  |      **  Put HOME into a buffer and store a slash where the end of HOME is
173  |      **  for quick concatination of the shell startup files.
174  |      **/
175  |     homelen = strlen(home) + 40;
176  |     if ((char *) NULL ==
177  | 	(home_pathname = stringer( NULL, homelen, home,"/", NULL)))
178  | 	if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
179  | 	    goto unwind0;
180  | 
181  |     if ((char *) NULL ==
182  | 	(home_pathname2 = stringer( NULL, homelen, NULL)))
183  | 	if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
184  | 	    goto unwind1;
185  | 
186  |     home_end = strlen(home_pathname);
187  |   
188  |     /**
189  |      **  Allocate a buffer for fgets ...
190  |      **/
191  |     if( NULL == (buffer = stringer(NULL, bufsiz ,NULL)))
192  | 	if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
193  | 	    goto unwind2;
194  | 
195  |     /**
196  |      **  Scan all startup files related to the current invoking shell
197  |      **/
198  |     if((char **) NULL == (shell_startups = SetStartupFiles(shell_name)))
199  | 	goto unwind3;
200  | 
201  |     while( shell_startups[ shell_num]) {
202  | 
203  | 	if ((char *) NULL == stringer( home_pathname + home_end , 40,
204  | 		shell_startups[ shell_num]))
205  | 		if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
206  | 			goto unwind3;
207  | 
208  | 	if( NULL == (fileptr = fopen(home_pathname, "r"))) {
209  | 	    shell_num++;
210  | 	    continue;			/** while( shell_startups) ...	     **/
211  | 	}
212  |  
213  | 	/**
214  | 	 **  ... when the startup file exists ...
215  | 	 **  open a new startupfile with the extension -NEW for output
216  | 	 **/
217  | 	path_end = strlen( home_pathname );
218  | 	if ((char *) NULL == stringer( home_pathname + path_end,
219  | 		homelen - path_end, "-NEW", NULL))
220  | 	    if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
221  | 		goto unwind3;
222  | 
223  | 	shell_num++;
224  | 
225  | 	if( !(g_flags & M_DISPLAY) &&
226  | 	((FILE *) NULL == (newfileptr = fopen( home_pathname, "w")))) {
227  | 	    (void) ErrorLogger(ERR_OPEN,LOC,home_pathname,"init",NULL);
228  | 	    continue;			/** while( shell_startups) ...	     **/
229  | 	}
230  |     
231  | 	/**
232  | 	 **  Seek for a modules load|add command within the shell startup file
233  | 	 **  Copy the shell input file to the new one until the magic cookie
234  | 	 **  is found.
235  | 	 **/
236  | 	while( fgets( buffer, bufsiz, fileptr)) {
237  | 	    if( Tcl_RegExpExec(interp, modcmdPtr, buffer, buffer)) {
238  | 		found_modload_flag = 1;
239  | 		break;
240  | 	    }
241  | 	    if (!(g_flags & M_DISPLAY)) fputs( buffer, newfileptr);
242  | 	}
243  | 
244  | 	/**
245  | 	 **  If not found...
246  | 	 **/
247  | 	if( !found_modload_flag) {
248  | 
249  | 	    if( EOF == fclose( fileptr))
250  | 		if( OK != ErrorLogger( ERR_CLOSE, LOC, home_pathname, NULL))
251  | 		    goto unwind3;
252  | 
253  | 	    if (!(g_flags & M_DISPLAY)) {
254  | 		if( EOF == fclose( newfileptr))
255  | 		    if( OK != ErrorLogger(ERR_CLOSE,LOC,home_pathname,NULL))
256  | 			goto unwind3;
257  | 
258  | 		if( 0 > unlink( home_pathname))
259  | 		    if( OK != ErrorLogger(ERR_UNLINK,LOC,home_pathname,NULL))
260  | 			goto unwind3;
261  | 	    }
262  | 
263  | 	    continue;			/** while( shell_startups) ...	     **/
264  | 	}
265  |  
266  | 	/**
267  | 	 **  ... module load|add found ...
268  | 	 **/
269  | 	found_module_command = 1;
270  | 	found_modload_flag = 0;
271  | 
272  | 	/* print out the "module" part */
273  | 	(void) Tcl_RegExpRange(modcmdPtr, 1, &startp, &endp);
274  | 	if (!(g_flags & M_DISPLAY)) (void) out_substr(newfileptr, startp, endp);
275  | 
276  | 	/* print out the "add/load" part */
277  | 	(void) Tcl_RegExpRange(modcmdPtr, 2, &startp, &endp);
278  | 	if (!(g_flags & M_DISPLAY)) (void) out_substr(newfileptr, startp, endp);
279  | 
280  | 	if( !(g_flags & M_CLEAR)) {
281  | 	
282  | 	    /* look at the "module list" part */
283  | 	    (void) Tcl_RegExpRange(modcmdPtr, 3, &startp, &endp);
284  | 	    /* save the end character & set to 0 */
285  | 	    if(endp) {
286  | 		ch = *endp;
287  | 		*endp = '\0';
288  | 	    }
289  | 	
290  | 	    if((char **) NULL==(modlist=SplitIntoList(interp,startp,&nummods)))
291  | 		continue;
292  | 	    /* restore the list end character */
293  | 	    if(endp)
294  | 		*endp = ch;
295  | 
296  | 	    if( g_flags & M_DISPLAY) {
297  | 		if( modlist[0] == NULL) {
298  | 		    fprintf( stderr,
299  | 			"\nNo modules are loaded in %s's initialization file "
300  | 			"$HOME/%s\n\n",shell_name,shell_startups[shell_num-1]);
301  | 		} else {
302  | 		    fprintf( stderr, 
303  | 		   "\n%s initialization file $HOME/%s loads modules:\n\t%s\n\n",
304  | 			shell_name, shell_startups[shell_num - 1], startp);
305  | 		}
306  | 
307  | 		FreeList( modlist, nummods);
308  | 
309  | 		continue;
310  | 	    }
311  | 	
312  | 	    for(i = 0; i < argc; i++) {
313  | 		/**
314  | 		 **  Search through the modlist of modules that are currently
315  | 		 **  in the ~/.startup.  If one is found, it handles removing
316  | 		 **  it, switching it, etc.
317  | 		 **/
318  | 		for( j=0; j < nummods; j++) {
319  | 		    if( !strcmp( modlist[j], argv[i])) {
320  | 			if( g_flags & (M_LOAD | M_PREPEND | M_REMOVE)) {
321  | 			    /**
322  | 			     **  If removing, adding, prepending it,
323  | 			     **  NULL it off the list.
324  | 			     **/
325  | 			    if ( g_flags & M_REMOVE )
326  | 				fprintf( stderr, "Removed %s\n", modlist[j]);
327  | 			    else if ( (g_flags & M_LOAD)
328  | 				&& !(g_flags & M_PREPEND))
329  | 				fprintf(stderr,"Moving %s to end\n",modlist[j]);
330  | 			    else if ( g_flags & M_PREPEND )
331  | 				fprintf(stderr,"Moving %s to beginning\n",
332  | 				modlist[j]);
333  | 			    null_free((void *) modlist + j);
334  | 			    rm_found = 1;
335  | 
336  | 			} else if( g_flags & M_SWITCH) {
337  | 
338  | 			    /**
339  | 			     **  If switching it, swap the old string with
340  | 			     **  the new string in the list.
341  | 			     **/
342  | 
343  | 			    fprintf( stderr, "Switching %s to %s\n", modlist[j],
344  | 				argv[i+1]);
345  | 			    sw_found = 1;
346  | 			    null_free((void *) modlist + j);
347  | 			    modlist[j] = strdup( argv[i+1]);
348  | 			}
349  | 
350  | 		    } /** if **/
351  | 		} /** for(j) **/
352  | 	    } /** for(i) **/
353  | 	
354  | 	    /**
355  | 	     **  Ok, if we're removing it, prepending it, or switching it, 
356  | 	     **  the modlist contains what needs to be put where...
357  | 	     **/
358  | 	    if( g_flags & M_PREPEND) {
359  | 		/**
360  | 		 **  PREPENDING
361  | 		 **/
362  | 		for(i = 0; i < argc; i++)
363  | 		    fprintf( newfileptr, " %s", argv[i]);
364  | 	    }
365  | 
366  | 	    if( (g_flags & (M_LOAD | M_PREPEND | M_REMOVE | M_SWITCH )) )
367  | 		/**
368  | 		 **  DUMP LIST
369  | 		 **/
370  | 		for(j = 0; j < nummods; j++) {
371  | 		    if( modlist[j])
372  | 			fprintf( newfileptr, " %s", modlist[j]);
373  | 		}
374  | 	    if( (g_flags & M_LOAD) && !(g_flags & M_PREPEND)) {
375  | 		/**
376  | 		 **  ADDING
377  | 		 **/
378  | 		for(i = 0; i < argc; i++)
379  | 		    fprintf( newfileptr, " %s", argv[i]);
380  | 	    }
381  | 	
382  | 	    FreeList( modlist, nummods);
383  | 
384  | 	} else { /** if( M_CLEAR) **/
385  | 	    /**
386  | 	     ** Clear out the list, but leave a "null"
387  | 	     **/
388  | 	    fprintf( newfileptr, " %s", "null");
389  | 	}
390  | 	
391  | 	/**
392  | 	 **  Restore any comments at the end of the line...
393  | 	 **/
394  | 	(void) Tcl_RegExpRange(modcmdPtr, 4, &startp, &endp);
395  | 	(void) out_substr(newfileptr, startp, endp);
396  | 
397  | 	/**
398  | 	 ** Complete copying the rest of the file...
399  | 	 **/
400  | 
401  | 	while( fgets( buffer, bufsiz, fileptr))
402  | 	    fputs( buffer, newfileptr);
403  | 
404  | 	/**
405  | 	 **  Don't need these any more
406  | 	 **/
407  | 
408  | 	if( EOF == fclose( fileptr))
409  | 	    if( OK != ErrorLogger( ERR_CLOSE, LOC, home_pathname, NULL))
410  | 		goto unwind3;
411  | 
412  | 	if( EOF == fclose( newfileptr))
413  | 	    if( OK != ErrorLogger( ERR_CLOSE, LOC, home_pathname, NULL))
414  | 		goto unwind3;
415  | 
416  | 	/**
417  | 	 **  Truncate -NEW from home_pathname and Create a -OLD name
418  | 	 **  Move ~/.startup to ~/.startup-OLD
419  | 	 **/
420  | 	home_pathname[ path_end] = '\0';
421  | 
422  | 	if ((char *) NULL == stringer( home_pathname2,homelen,
423  | 		home_pathname, "-OLD", NULL))
424  | 		if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
425  | 		    goto unwind3;
426  | 
427  | 	if( 0 > rename( home_pathname, home_pathname2))
428  | 	    if( OK != ErrorLogger(ERR_RENAME,LOC,home_pathname,home_pathname2,
429  | 		    NULL))
430  | 		goto unwind3;
431  | 
432  | 	/**
433  | 	 **  Create a -NEW name
434  | 	 **  Move ~/.startup-NEW to ~/.startup
435  | 	 **/
436  | 	if ((char *) NULL == stringer( home_pathname2,homelen,
437  | 		home_pathname, "-NEW", NULL))
438  | 		if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
439  | 		    goto unwind3;
440  | 
441  | 	if( 0 > rename( home_pathname2, home_pathname))
442  | 	    if( OK != ErrorLogger(ERR_RENAME,LOC,home_pathname2,home_pathname,
443  | 		NULL)) {
444  | 
445  | 		/**
446  | 		 **  Put the -OLD one back if I can't rename it
447  | 		 **/
448  | 		if ((char *) NULL == stringer( home_pathname2,homelen,
449  | 			home_pathname, "-OLD", NULL))
450  | 			if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
451  | 			    goto unwind3;
452  | 
453  | 		if( 0 > rename( home_pathname2, home_pathname)) 
454  | 		    ErrorLogger(ERR_RENAME,LOC,home_pathname2,home_pathname,
455  | 		    NULL);
456  | 
457  | 		goto unwind3;
458  | 	    }
459  | 
460  |     } /** while( shell_startups) **/
461  |   
462  |     /**
463  |      **  Free up internal I/O buffers
464  |      **/
465  |     null_free((void *) &buffer);
466  | 
467  |     /**
468  |      **  Create a -NEW name. This may conditionally be used for removing the
469  |      **  new files if the operation wasn't a success
470  |      **  Check the SWITCH command
471  |      **/
472  |     if ((char *) NULL == stringer( home_pathname2,homelen,
473  | 	home_pathname, "-NEW", NULL))
474  | 	if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
475  | 	    goto unwind2;
476  | 
477  | 
478  |     if((g_flags & M_SWITCH) && !sw_found)
479  | 	if( OK != ErrorLogger( ERR_LOCATE, LOC, argv[0], NULL)) {
480  | 	    if( 0 > unlink( home_pathname2))
481  | 		ErrorLogger( ERR_UNLINK, LOC, home_pathname2, NULL);
482  | 	    goto unwind2;
483  | 	}
484  | 	
485  |     /**
486  |      **  Check the REMOVE command
487  |      **/
488  | 
489  |     if((g_flags & M_REMOVE) && !rm_found)
490  | 	if( OK != ErrorLogger( ERR_LOCATE, LOC, NULL)) {
491  | 	    if( 0 > unlink( home_pathname2))
492  | 		ErrorLogger( ERR_UNLINK, LOC, home_pathname2, NULL);
493  | 	    goto unwind2;
494  | 	}
495  |     
496  |     if( !found_module_command)
497  | 	if( OK != ErrorLogger( ERR_INIT_STUP, LOC, shell_name, NULL)) 
498  | 	    goto unwind2;
499  | 
500  | #if WITH_DEBUGGING_MODULECMD
501  |     ErrorLogger( NO_ERR_END, LOC, _proc_ModuleCmd_Init, NULL);
502  | #endif
503  | 
504  |     /**
505  |      **  Free up memory
506  |      **/
507  |     null_free((void *) &home_pathname2);
508  |     null_free((void *) &home_pathname);
509  | 
510  | success0:
511  |     return( TCL_OK);			/** -------- EXIT (SUCCESS) -------> **/
512  | 
513  | unwind3:
514  |     null_free((void *) &buffer);
515  | unwind2:
516  |     null_free((void *) &home_pathname2);
517  | unwind1:
518  |     null_free((void *) &home_pathname);
519  | unwind0:
520  |     return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
521  | 
522  | } /** end of 'ModuleCmd_Init' **/