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' **/