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