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:	1991/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.6 2006/01/18 05:35:11 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:	1991/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  | 		  final_list_num = 0,
139  | 		  nummods, bufsiz = 8192,
140  | 		  new_file,
141  | 		  homelen, home_end, path_end;
142  | 
143  | #if WITH_DEBUGGING_MODULECMD
144  |     ErrorLogger(NO_ERR_START, LOC, _proc_ModuleCmd_Init, NULL);
145  | #endif
146  | 
147  |     /**
148  |      **  If called with no arguments and the flags don't say that there's some-
149  |      **  thing to do - exit now!
150  |      **/
151  |     if (argc < 1 && !(g_flags & (M_DISPLAY | M_CLEAR)))
152  | 	goto success0;
153  | 
154  |     /**
155  |      **  Parameter check for the initswitch command
156  |      **/
157  |     if (g_flags & M_SWITCH) {
158  | 	argc--;
159  | 	if (argc != 1)
160  | 	    if (OK != ErrorLogger(ERR_USAGE, LOC,
161  | 				  "initswitch oldmodule newmodule", NULL))
162  | 		goto unwind0;
163  |     }
164  | 
165  |     /**
166  |      **  Where's my HOME?
167  |      **/
168  |     if ((char *) NULL == (home = (char *) getenv("HOME")))
169  | 	if (OK != ErrorLogger(ERR_HOME, LOC, NULL))
170  | 	    goto unwind1;
171  | 
172  |     /**
173  |      **  Put HOME into a buffer and store a slash where the end of HOME is
174  |      **  for quick concatination of the shell startup files.
175  |      **/
176  |     homelen = strlen(home) + 40;
177  |     if ((char *) NULL ==
178  | 	(home_pathname = stringer(NULL, homelen, home, "/", NULL)))
179  | 	if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
180  | 	    goto unwind0;
181  | 
182  |     if ((char *) NULL == (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  | 	new_file = 1;
203  | 	found_modload_flag = 0;
204  | 
205  | 	if ((char *) NULL == stringer(home_pathname + home_end, 40,
206  | 				      shell_startups[shell_num], NULL))
207  | 	    if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
208  | 		goto unwind3;
209  | 
210  | 	if (NULL == (fileptr = fopen(home_pathname, "r")))
211  | 	    goto unwhile0; 	/** while( shell_startups) ...	     **/
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  | 	if (!(g_flags & M_DISPLAY) &&
224  | 	    ((FILE *) NULL == (newfileptr = fopen(home_pathname, "w")))) {
225  | 	    (void) ErrorLogger(ERR_OPEN, LOC, home_pathname, "init", NULL);
226  | 	    goto unwhile0; 	/** while( shell_startups) ...	     **/
227  | 	}
228  | 
229  | 	/**
230  | 	 **  Seek for a modules load|add command within the shell startup file
231  | 	 **  Copy the shell input file to the new one until the magic cookie
232  | 	 **  is found.
233  | 	 **/
234  | 	while (fgets(buffer, bufsiz, fileptr)) {
235  | 	    if (Tcl_RegExpExec(interp, modcmdPtr, buffer, buffer)) {
236  | 		found_modload_flag = 1;
237  | 		/**
238  | 		 **  ... module load|add found ...
239  | 		 **/
240  | 		found_module_command = 1;
241  | 
242  | 		/* print out the "module" part */
243  | 		(void) Tcl_RegExpRange(modcmdPtr, 1,
244  | 				       (CONST84 char **) &startp,
245  | 				       (CONST84 char **) &endp);
246  | 		if (!(g_flags & M_DISPLAY))
247  | 		    (void) out_substr(newfileptr, startp, endp);
248  | 
249  | 		/* print out the "add/load" part */
250  | 		(void) Tcl_RegExpRange(modcmdPtr, 2,
251  | 				       (CONST84 char **) &startp,
252  | 				       (CONST84 char **) &endp);
253  | 		if (!(g_flags & M_DISPLAY))
254  | 		    (void) out_substr(newfileptr, startp, endp);
255  | 
256  | 		if (!(g_flags & M_CLEAR)) {
257  | 		    /* look at the "module list" part */
258  | 		    (void) Tcl_RegExpRange(modcmdPtr, 3,
259  | 					   (CONST84 char **) &startp,
260  | 					   (CONST84 char **) &endp);
261  | 		    /* save the end character & set to 0 */
262  | 		    if (endp) {
263  | 			ch = *endp;
264  | 			*endp = '\0';
265  | 		    }
266  | 
267  | 		    if ((char **) NULL ==
268  | 			(modlist = SplitIntoList(interp, startp, &nummods)))
269  | 			continue; /** while(fgets) **/
270  | 
271  | 		    /* restore the list end character */
272  | 		    if (endp)
273  | 			*endp = ch;
274  | 
275  | 		    if (g_flags & M_DISPLAY) {
276  | 			if (modlist[0] == NULL) {
277  | 			    fprintf(stderr,
278  | 	    "\nNo modules are loaded in %s's initialization file "
279  | 				    "$HOME/%s\n", shell_name,
280  | 				    shell_startups[shell_num]);
281  | 			} else {
282  | 			    if (new_file) {
283  | 				fprintf(stderr,
284  | 	    "\n%s initialization file $HOME/%s loads modules:\n\t",
285  | 				    shell_name, shell_startups[shell_num]);
286  | 		    		(void) out_substr(stderr, startp, endp);
287  | 				fputs("\n",stderr);
288  | 				new_file = 0;
289  | 			    } else {
290  | 				fputs("\t",stderr);
291  | 		    		(void) out_substr(stderr, startp, endp);
292  | 				fputs("\n",stderr);
293  | 			    }
294  | 			}
295  | 
296  | 			FreeList(modlist, nummods);
297  | 			continue; /** while(fgets) **/
298  | 		    }
299  | 
300  | 		    for (i = 0; i < argc; i++) {
301  | 		    /**
302  | 		     ** Search through the modlist of modules that are currently
303  | 		     ** in the ~/.startup.  If one is found, it handles removing
304  | 		     ** it, switching it, etc.
305  | 		     **/
306  | 			for (j = 0; j < nummods; j++) {
307  | 			    if (modlist[j] && !strcmp(modlist[j], argv[i])) {
308  | 				if (g_flags & (M_LOAD | M_REMOVE)) {
309  | 				/**
310  | 				 **  If removing, adding, prepending it,
311  | 				 **  NULL it off the list.
312  | 				 **/
313  | 				    if (g_flags & M_REMOVE)
314  | 					fprintf(stderr, "Removed %s\n",
315  | 						modlist[j]);
316  | 				    else if ((g_flags & M_LOAD)
317  | 					     && !(g_flags & M_PREPEND))
318  | 					fprintf(stderr, "Moving %s to end\n",
319  | 						modlist[j]);
320  | 				    else if (g_flags & M_PREPEND)
321  | 					fprintf(stderr,
322  | 						"Moving %s to beginning\n",
323  | 						modlist[j]);
324  | 				    null_free((void *) (modlist + j));
325  | 
326  | 				} else if (g_flags & M_SWITCH) {
327  | 				/**
328  | 				 **  If switching it, swap the old string with
329  | 				 **  the new string in the list.
330  | 				 **/
331  | 				    fprintf(stderr, "Switching %s to %s\n",
332  | 					    modlist[j], argv[i + 1]);
333  | 				    null_free((void *) (modlist + j));
334  | 				    modlist[j] = strdup(argv[i + 1]);
335  | 				}
336  | 			    } /** if **/
337  | 			} /** for(j) **/
338  | 		    } /** for(i) **/
339  | 		/**
340  | 		 **  Ok, if we're removing it, prepending it, or switching it, 
341  | 		 **  the modlist contains what needs to be put where...
342  | 		 **/
343  | 		    if ((new_file) && (g_flags & M_PREPEND)) {
344  | 		    /**
345  | 		     **  PREPENDING
346  | 		     **/
347  | 			for (i = 0; i < argc; i++) {
348  | 			    fprintf(newfileptr, " %s", argv[i]);
349  | 			    final_list_num++;
350  | 			}
351  | 		    }
352  | 
353  | 		    if ((g_flags & (M_LOAD | M_REMOVE | M_SWITCH))) {
354  | 		    /**
355  | 		     **  DUMP LIST
356  | 		     **/
357  | 			for (j = 0; j < nummods; j++) {
358  | 			    if (modlist[j]) {
359  | 				fprintf(newfileptr, " %s", modlist[j]);
360  | 				final_list_num++;
361  | 			    }
362  | 			}
363  | 		    }
364  | 		    if ((new_file) && (g_flags & M_LOAD)
365  | 		    && !(g_flags & M_PREPEND)) {
366  | 		    /**
367  | 		     **  ADDING
368  | 		     **/
369  | 			for (i = 0; i < argc; i++) {
370  | 			    fprintf(newfileptr, " %s", argv[i]);
371  | 			    final_list_num++;
372  | 			}
373  | 		    }
374  | 		    /* always place a null if an empty list */
375  | 		    if (!final_list_num)
376  | 			fprintf(newfileptr, " %s", "null");
377  | 
378  | 		    FreeList(modlist, nummods);
379  | 
380  | 		} else { /** if( M_CLEAR) **/
381  | 		/**
382  | 		 ** Clear out the list, but leave a "null"
383  | 		 **/
384  | 		    fprintf(newfileptr, " %s", "null");
385  | 		}
386  | 	/**
387  | 	 **  Restore any comments at the end of the line...
388  | 	 **/
389  | 		(void) Tcl_RegExpRange(modcmdPtr, 4,
390  | 				       (CONST84 char **) &startp,
391  | 				       (CONST84 char **) &endp);
392  | 		(void) out_substr(newfileptr, startp, endp);
393  | 		new_file = 0;
394  | 	    } else {		/* not module load line */
395  | 		if (!(g_flags & M_DISPLAY))
396  | 		    fputs(buffer, newfileptr);
397  | 	    }
398  | 	} /** while (fgets) **/
399  | 	if (g_flags & M_DISPLAY) {
400  | 	    fputs("\n",stderr);
401  | 	}
402  | 
403  | 	if (!found_modload_flag) {
404  | 	    /**
405  | 	     **  If not found...
406  | 	     **/
407  | 	    if (EOF == fclose(fileptr))
408  | 		if (OK != ErrorLogger(ERR_CLOSE, LOC, home_pathname, NULL))
409  | 		    goto unwind3;
410  | 
411  | 	    if (!(g_flags & M_DISPLAY)) {
412  | 		if (EOF == fclose(newfileptr))
413  | 		    if (OK != ErrorLogger(ERR_CLOSE, LOC, home_pathname, NULL))
414  | 			goto unwind3;
415  | 
416  | 		if (0 > unlink(home_pathname))
417  | 		    if (OK != ErrorLogger(ERR_UNLINK, LOC, home_pathname, NULL))
418  | 			goto unwind3;
419  | 	    }
420  | 	} else {		/* found_modload_flag */
421  | 	    /**
422  | 	     **  Don't need these any more
423  | 	     **/
424  | 	    if (EOF == fclose(fileptr))
425  | 		if (OK != ErrorLogger(ERR_CLOSE, LOC, home_pathname, NULL))
426  | 		    goto unwind3;
427  | 
428  | 	    if (g_flags & M_DISPLAY)
429  | 	        goto unwhile0; 	/** while( shell_startups) ...	     **/
430  | 
431  | 	    if (EOF == fclose(newfileptr))
432  | 		if (OK != ErrorLogger(ERR_CLOSE, LOC, home_pathname, NULL))
433  | 		    goto unwind3;
434  | 
435  | 	    /**
436  | 	     **  Truncate -NEW from home_pathname and Create a -OLD name
437  | 	     **  Move ~/.startup to ~/.startup-OLD
438  | 	     **/
439  | 	    home_pathname[path_end] = '\0';
440  | 
441  | 	    if ((char *) NULL == stringer(home_pathname2, homelen,
442  | 					  home_pathname, "-OLD", NULL))
443  | 		if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
444  | 		    goto unwind3;
445  | 
446  | 	    if (0 > rename(home_pathname, home_pathname2))
447  | 		if (OK !=
448  | 		    ErrorLogger(ERR_RENAME, LOC, home_pathname, home_pathname2,
449  | 				NULL))
450  | 		    goto unwind3;
451  | 
452  | 	    /**
453  | 	     **  Create a -NEW name
454  | 	     **  Move ~/.startup-NEW to ~/.startup
455  | 	     **/
456  | 	    if ((char *) NULL == stringer(home_pathname2, homelen,
457  | 					  home_pathname, "-NEW", NULL))
458  | 		if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
459  | 		    goto unwind3;
460  | 
461  | 	    if (0 > rename(home_pathname2, home_pathname)) {
462  | 		if (OK !=
463  | 		    ErrorLogger(ERR_RENAME, LOC, home_pathname2, home_pathname,
464  | 				NULL)) {
465  | 		    /**
466  | 		     **  Put the -OLD one back if I can't rename it
467  | 		     **/
468  | 		    if ((char *) NULL == stringer(home_pathname2, homelen,
469  | 						  home_pathname, "-OLD", NULL))
470  | 			if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
471  | 			    goto unwind3;
472  | 
473  | 		    if (0 > rename(home_pathname2, home_pathname))
474  | 			ErrorLogger(ERR_RENAME, LOC, home_pathname2,
475  | 				    home_pathname, NULL);
476  | 
477  | 		    goto unwind3;
478  | 		}
479  | 	    }
480  | 
481  | 	    /**
482  | 	     **  So far we're successful so
483  | 	     **  Create a -OLD name
484  | 	     **  Unlink ~/.startup-OLD
485  | 	     **/
486  | 	    if ((char *) NULL == stringer(home_pathname2, homelen,
487  | 					  home_pathname, "-OLD", NULL))
488  | 		if (OK != ErrorLogger(ERR_STRING, LOC, NULL))
489  | 		    goto unwind3;
490  | 
491  | 	    if ((g_flags & (M_CLEAR | M_LOAD | M_REMOVE | M_SWITCH)))
492  | 		if (0 > unlink(home_pathname2)) {
493  | 		    ErrorLogger(ERR_UNLINK, LOC, home_pathname2, NULL);
494  | 		    goto unwind3;
495  | 		}
496  | 	}
497  |     unwhile0:
498  | 	shell_num++;
499  |     } /** while( shell_startups) **/
500  | 
501  |     /**
502  |      **  Free up internal I/O buffers
503  |      **/
504  |     null_free((void *) &buffer);
505  | 
506  |     if (!found_module_command)
507  | 	if (OK != ErrorLogger(ERR_INIT_STUP, LOC, shell_name, NULL))
508  | 	    goto unwind2;
509  | 
510  | #if WITH_DEBUGGING_MODULECMD
511  |     ErrorLogger(NO_ERR_END, LOC, _proc_ModuleCmd_Init, NULL);
512  | #endif
513  | 
514  |     /**
515  |      **  Free up memory
516  |      **/
517  |     null_free((void *) &home_pathname2);
518  |     null_free((void *) &home_pathname);
519  | 
520  | success0:
521  |     return (TCL_OK);			/** -------- EXIT (SUCCESS) -------> **/
522  | 
523  | unwind3:
524  |     null_free((void *) &buffer);
525  | unwind2:
526  |     null_free((void *) &home_pathname2);
527  | unwind1:
528  |     null_free((void *) &home_pathname);
529  | unwind0:
530  |     return (TCL_ERROR);			/** -------- EXIT (FAILURE) -------> **/
531  | 
532  | } /** end of 'ModuleCmd_Init' **/