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