1 /*****
2  ** ** Module Header ******************************************************* **
3  ** 									     **
4  **   Modules Revision 3.0						     **
5  **   Providing a flexible user environment				     **
6  ** 									     **
7  **   File:		main.c						     **
8  **   First Edition:	1991/10/23					     **
9  ** 									     **
10  **   Authors:	John Furlan, jlf@behere.com				     **
11  **		Jens Hamisch, jens@Strawberry.COM			     **
12  ** 									     **
13  **   Description:	The main routine of Tcl Modules including all of     **
14  **			the global data.				     **
15  ** 									     **
16  **   Exports:		main		Main program			     **
17  **			module_usage	Module usage information	     **
18  **			Tcl_AppInit	Tcl Application initialization	     **
19  ** 									     **
20  **   Notes:								     **
21  ** 									     **
22  ** ************************************************************************ **
23  ****/
24 
25 /** ** Copyright *********************************************************** **
26  ** 									     **
27  ** Copyright 1991-1994 by John L. Furlan.                      	     **
28  ** see LICENSE.GPL, which must be provided, for details		     **
29  ** 									     **
30  ** ************************************************************************ **/
31 
32 static char Id[] = "@(#)$Id: 938a2d20aaa98af116c70f9d7fc4b5708e417231 $";
33 static void *UseId[] = { &UseId, Id };
34 
35 /** ************************************************************************ **/
36 /** 				      HEADERS				     **/
37 /** ************************************************************************ **/
38 
39 #include "modules_def.h"
40 #include "getopt.h"
41 
42 /** ************************************************************************ **/
43 /** 				  LOCAL DATATYPES			     **/
44 /** ************************************************************************ **/
45 
46 /** not applicable **/
47 
48 /** ************************************************************************ **/
49 /** 				     CONSTANTS				     **/
50 /** ************************************************************************ **/
51 
52 /** not applicable **/
53 
54 /** ************************************************************************ **/
55 /**				      MACROS				     **/
56 /** ************************************************************************ **/
57 
58 /** not applicable **/
59 
60 /** ************************************************************************ **/
61 /** 				    GLOBAL DATA				     **/
62 /** ************************************************************************ **/
63 
64 char	 *g_current_module = NULL,	/** The module which is handled by   **/
65 					/** the current command		     **/
66 	 *g_specified_module = NULL,	/** The module that was specified    **/
67 					/** on the command line		     **/
68 	 *g_module_path = NULL,		/** The path to the module	     **/
69 	 *shell_name,			/** Name of the shell		     **/
70 					/** (first parameter to modulcmd)    **/
71 	 *shell_derelict,		/** Shell family (sh, csh, etc)	     **/
72 	 *shell_init,			/** Shell init script name	     **/
73 	 *shell_cmd_separator;		/** Shell command separator char     **/
74 int	  g_flags = 0,			/** Control what to do at the moment **/
75 					/** The posible values are defined in**/
76 					/** module_def.h		     **/
77 	  g_retval = 0,			/** exit return value		     **/
78 	  g_output = 0,			/** Has output been generated	     **/
79 	  append_flag = 0;		/** only used by the 'use' command   **/
80 
81 char	  _default[] = "default";	/** id string for default versions   **/
82 char	  _colon[]   = ":";		/** directory separator		     **/
83 
84 /**
85  **  Name of the rc files
86  **  PREFIX points to the location where modules is going to be installed.
87  **  It comes from the Makefile
88  **/
89 
90 char	*instpath = PREFIX,
91 	*rc_file = RCFILE,
92 	*modulerc_file = MODULERCFILE,
93 	*version_file = VERSIONFILE;
94 
95 /**
96  **  pointers for regular expression evaluations
97  **/
98 char
99     *addRE      = "^(add|load)", 		/** 'module add <file>'	     **/
100     *rmRE       = "^(rm|del|era|remov|unload)",	/** 'module unload <file>'   **/
101     *swRE       = "^sw",			/** 'module switch <file>'   **/
102     *dispRE     = "^(disp|show)", 		/** 'module display <file>'  **/
103     *listRE     = "^li", 			/** 'module list <file>'     **/
104     *availRE    = "^av",			/** 'module avail <file>'    **/
105     *helpRE     = "^(help|\\?)",		/** 'module help <file>'     **/
106     *initRE     = "^init",			/** 'module init'	     **/
107     *useRE      = "^use",			/** 'module use <file>'	     **/
108     *unuseRE    = "^unuse",			/** 'module unuse <file>'    **/
109     *updateRE   = "^update",			/** 'module update'	     **/
110     *purgeRE    = "^purge",			/** 'module purge'	     **/
111     *clearRE    = "^clear",			/** 'module clear'	     **/
112     *whatisRE   = "^wh",			/** 'module whatis'	     **/
113     *aproposRE  = "^(apr|key)",			/** 'module apropos'	     **/
114     *refreshRE  = "^refr";			/** 'module refresh'	     **/
115 
116   /**
117    **  Hash-Tables for all changes to the environment.
118 
119 /**
120  **  Hash-Tables for all changes to the environment.
121  **  ??? What do we save here, the old or the new setup ???
122  **/
123 
124 Tcl_HashTable	*setenvHashTable,
125 		*unsetenvHashTable,
126 		*aliasSetHashTable,
127 		*aliasUnsetHashTable,
128 		*markVariableHashTable,
129 		*markAliasHashTable;
130 
131 /**
132  **  A buffer for reading a single line
133  **/
134 
135 char	*line = NULL;
136 
137 /**
138  **  Flags influenced by the command line switches
139  **/
140 
141 int	sw_force = 0,
142 	sw_detach = 0,
143 	sw_format = 0,
144 	sw_verbose = 0,
145 	sw_create = 0,
146 	sw_userlvl = UL_ADVANCED,
147 	sw_icase = 0;
148 
149 /** ************************************************************************ **/
150 /** 				    LOCAL DATA				     **/
151 /** ************************************************************************ **/
152 
153 static	char	module_name[] = "main.c";	/** File name of this module **/
154 
155 #if WITH_DEBUGGING
156 static	char	_proc_main[] = "main";
157 #endif
158 #if WITH_DEBUGGING_MODULECMD
159 static	char	_proc_Module_Usage[] = "Module_Usage";
160 #endif
161 #if WITH_DEBUGGING_INIT
162 static	char	_proc_Check_Switches[] = "Check_Switches";
163 static	char	_proc_Tcl_AppInit[] = "Tcl_AppInit";
164 #endif
165 
166 /** ************************************************************************ **/
167 /**				    PROTOTYPES				     **/
168 /** ************************************************************************ **/
169 
170 static int	Check_Switches( int *argc, char *argv[]);
171 static void	version (FILE *output);
172 
173 /*++++
174  ** ** Function-Header ***************************************************** **
175  ** 									     **
176  **   Function:		main						     **
177  ** 									     **
178  **   Description:	Main program					     **
179  ** 									     **
180  **   First Edition:	1991/10/23					     **
181  ** 									     **
182  **   Parameters:	int	argc		Number of parameters	     **
183  **			char	*argv[]		Command line arguments	     **
184  **			char	*environ[]	Pointer to the process' en-  **
185  **						vironment.		     **
186  **   Result:		int	1		Usage information printed    **
187  **				TCL_OK		Successful completion	     **
188  **				other		Return value of the module   **
189  **			 			subcomand		     **
190  ** 									     **
191  **   Attached Globals:	*Ptr	 	by InitializeTcl		     **
192  **			*HashTable	by InitializeTcl	 	     **
193  ** 									     **
194  ** ************************************************************************ **
195  ++++*/
196 
main(int argc,char * argv[],char * environ[])197 int	main( int argc, char *argv[], char *environ[]) {
198 
199     Tcl_Interp	*interp;
200     int          return_val = 0;
201     char	*rc_name;
202     char	*rc_path;
203 
204 #if WITH_DEBUGGING
205     ErrorLogger( NO_ERR_START, LOC, _proc_main, NULL);
206 #endif
207     /**
208      ** check if first argument is --version or -V then output the
209      ** version to stdout.  This is a special circumstance handled
210      ** by the regular options.
211      **/
212     if (argc > 1 && *argv[1] == '-') {
213         if (!strcmp("-V", argv[1]) || !strcmp("--version", argv[1])) {
214 	    version(stdout);
215 	    return 0;
216         }
217     }
218     /**
219      **  Initialization.
220      **  Check the command line syntax. There will be no return from the
221      **  initialization function in case of invalid command line arguments.
222      **/
223 
224     if( TCL_OK != Initialize_Tcl( &interp, argc, argv, environ))
225 	goto unwind0;
226 
227     if( TCL_OK != Setup_Environment( interp))
228 	goto unwind0;
229 
230     /**
231      **  Check for command line switches
232      **/
233 
234     if( TCL_OK != Check_Switches( &argc, argv))
235 	goto unwind0;
236 
237     /**
238      **  Figure out, which global RC file to use. This depends on the environ-
239      **  ment variable 'MODULERCFILE', which can be set to one of the following:
240      **
241      **		<filename>	-->	PREFIX/etc/<filename>
242      **		<dir>/		-->	<dir>/RC_FILE
243      **		<dir>/<file>	-->	<dir>/<file>
244      **  Use xgetenv to expand 1 level of env.vars.
245      **/
246 
247     if((rc_name = xgetenv( "MODULERCFILE"))) {
248 	/* found something in MODULERCFILE */
249 	if((char *) NULL == (rc_path = stringer(NULL,0,rc_name,NULL))) {
250 	    if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
251 		goto unwind1;
252 	    else
253 		null_free((void *) &rc_name);
254 	} else {
255 	    null_free((void *) &rc_name);
256 	    if((char *) NULL == (rc_name = strrchr( rc_path, '/'))) {
257 		rc_name = rc_path;
258 		rc_path = instpath;
259 	    } else
260 		*rc_name++ = '\0';
261 	    if( !*rc_name) {
262 		rc_name = rc_file;
263 	    }
264 	}
265     } else {
266 	rc_path = instpath;
267 	null_free((void *) &rc_name);
268 	rc_name = rc_file;
269     }
270 
271     /**
272      **  Finally we have to change PREFIX -> PREFIX/etc
273      **/
274 
275     if( rc_path == instpath) {
276 	if((char *) NULL == (rc_path = stringer(NULL,0, instpath,"/etc",NULL))){
277 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
278 		goto unwind1;
279 	    else
280 		rc_path = NULL;
281 
282 	}
283     }
284 
285     /**
286      **  Source the global and the user defined RC file
287      **/
288 
289     g_current_module = (char *) NULL;
290 
291     if( TCL_ERROR == SourceRC( interp, rc_path, rc_name) ||
292 	TCL_ERROR == SourceRC( interp, getenv( "HOME"), modulerc_file))
293 	exit( 1);
294 
295     if( rc_path)
296 	null_free((void *) &rc_path);
297 
298     /**
299      **  Invocation of the module command as specified in the command line
300      **/
301 
302     g_flags = 0;
303     return_val = cmdModule((ClientData) 0,interp,(argc-1),
304 	(CONST84 char **) (argv + 1));
305 
306     /**
307      **  If we were doing some operation that has already flushed its output,
308      **  then we don't need to re-flush the output here.
309      **
310      **  Also, if we've had an error here, then the whole modulecmd failed
311      **  and not just the values for a single modulefile.  So, we'll pass in
312      **  a NULL here to indicate that any error message should say that
313      **  absolutely NO changes were made to the environment.
314      **/
315 
316     if( TCL_OK == return_val) {
317 	Output_Modulefile_Changes( interp);
318 #ifdef HAS_X11LIBS
319 	xresourceFinish( 1);
320 #endif
321     } else {
322 	Unwind_Modulefile_Changes( interp, NULL);
323 #ifdef HAS_X11LIBS
324 	xresourceFinish( 0);
325 #endif
326     }
327 
328     /**
329      **  Finally clean up. Delete the required hash tables and conditionally
330      **  allocated areas.
331      **/
332 
333     Delete_Global_Hash_Tables();
334 
335     if( line)
336 	null_free((void *) &line);
337     if( error_line)
338 	null_free((void *) &error_line);
339 
340     /**
341      **  This return value may be evaluated by the calling shell
342      **/
343 #if WITH_DEBUGGING
344     ErrorLogger( NO_ERR_END, LOC, _proc_main, NULL);
345 #endif
346 
347     OutputExit();
348     return ( return_val ? return_val : g_retval);
349 
350 unwind2:
351     null_free((void *) &rc_path);
352 unwind1:
353     null_free((void *) &rc_name);
354 unwind0:
355 
356     /* an error occurred of some type */
357     g_retval = (g_retval ? g_retval : 1);
358     OutputExit();
359     return (g_retval);
360 
361 } /** End of 'main' **/
362 
363 /*++++
364  ** ** Function-Header ***************************************************** **
365  ** 									     **
366  **   Function:		module_usage					     **
367  ** 									     **
368  **   Description:	Lists out the helpful usage info that we've all come **
369  ** 			to expect from unix commands.			     **
370  ** 									     **
371  **   First Edition:	2002/10/13					     **
372  ** 									     **
373  **   Parameters:	FILE	*output		Where the output goes	     **
374  ** 									     **
375  **   Result:		void			No return values	     **
376  ** 									     **
377  **   Attached Globals:							     **
378  ** 			version_string		Current module version	     **
379  ** 			date_string		Current module date	     **
380  ** 									     **
381  ** ************************************************************************ **
382  ++++*/
383 
module_usage(FILE * output)384 void module_usage(FILE *output)
385 {
386     /**
387      **  General help wanted.
388      **/
389 
390 #if WITH_DEBUGGING_MODULECMD
391     ErrorLogger( NO_ERR_START, LOC, _proc_Module_Usage, NULL);
392 #endif
393 
394 	fprintf(output,
395 		"\n  Modules Release %s %s (Copyright GNU GPL v2 1991):\n\n",
396                 version_string,date_string);
397 
398 	fprintf(output,
399 "  Usage: module [ switches ] [ subcommand ] [subcommand-args ]\n\n"
400 "Switches:\n"
401 "	-H|--help		this usage info\n"
402 "	-V|--version		modules version & configuration options\n"
403 "	-f|--force		force active dependency resolution\n"
404 "	-t|--terse		terse    format avail and list format\n"
405 "	-l|--long		long     format avail and list format\n"
406 "	-h|--human		readable format avail and list format\n"
407 "	-v|--verbose		enable  verbose messages\n"
408 "	-s|--silent		disable verbose messages\n"
409 "	-c|--create		create caches for avail and apropos\n"
410 "	-i|--icase		case insensitive\n"
411 "	-u|--userlvl <lvl>	set user level to (nov[ice],exp[ert],adv[anced])\n"
412 "  Available SubCommands and Args:\n"
413 "	+ add|load		modulefile [modulefile ...]\n"
414 "	+ rm|unload		modulefile [modulefile ...]\n"
415 "	+ switch|swap		[modulefile1] modulefile2\n"
416 "	+ display|show		modulefile [modulefile ...]\n"
417 "	+ avail			[modulefile [modulefile ...]]\n"
418 "	+ use [-a|--append]	dir [dir ...]\n"
419 "	+ unuse			dir [dir ...]\n"
420 #ifdef BEGINENV
421 "	+ update\n"
422 #endif
423 "	+ refresh\n"
424 "	+ purge\n"
425 "	+ list\n"
426 "	+ clear\n"
427 "	+ help			[modulefile [modulefile ...]]\n"
428 "	+ whatis		[modulefile [modulefile ...]]\n"
429 "	+ apropos|keyword	string\n"
430 "	+ initadd		modulefile [modulefile ...]\n"
431 "	+ initprepend		modulefile [modulefile ...]\n"
432 "	+ initrm		modulefile [modulefile ...]\n"
433 "	+ initswitch		modulefile1 modulefile2\n"
434 "	+ initlist\n"
435 "	+ initclear\n\n");
436 
437 } /** End of 'module_usage' **/
438 
439 /*++++
440  ** ** Function-Header ***************************************************** **
441  ** 									     **
442  **   Function:		Tcl_AppInit					     **
443  ** 									     **
444  **   Description:	This is needed if you use shared TCL libraries.	     **
445  **			It won't be called, but the linker complains if it   **
446  **		   	doesn't exist.					     **
447  ** 									     **
448  **   First Edition:	1991/10/23					     **
449  ** 									     **
450  **   Parameters:	Tcl_Interp	*interp		Tcl interpreter to   **
451  **							be initialized	     **
452  **   Result:		int		TCL_OK		Initialization succ. **
453  **   Attached Globals:	-						     **
454  ** 									     **
455  ** ************************************************************************ **
456  ++++*/
457 
Tcl_AppInit(Tcl_Interp * interp)458 int Tcl_AppInit(Tcl_Interp *interp)
459 {
460 
461 #if WITH_DEBUGGING_INIT
462     ErrorLogger( NO_ERR_START, LOC, _proc_Tcl_AppInit, NULL);
463 #endif
464 
465     return( TCL_OK);
466 
467 } /** End of 'Tcl_AppInit' **/
468 
469 /*++++
470  ** ** Function-Header ***************************************************** **
471  ** 									     **
472  **   Function:		Check_Switches					     **
473  ** 									     **
474  **   Description:	Check for command line switches and set internal     **
475  **			control variable according to them. Command line     **
476  **			switches are defined to appear between the shell and **
477  **			the module command. They begin on a dash and may     **
478  **			appear in long and short format. 		     **
479  **									     **
480  **			The following switches are defined:		     **
481  **									     **
482  **			    --force, -f		Force prerequired actions    **
483  **			    --terse, -t		Terse, parseable messages    **
484  **			    --human, -h		Human readable form          **
485  **			    --long, -l		Long messages		     **
486  **			    --verbose, -v	Verbose mode on		     **
487  **			    --silent, -s	Verbose mode off	     **
488  **			    --create, -c	Create a cache while execu-  **
489  **						ting the command	     **
490  **			    --userlvl, -u	Change the user level	     **
491  **			    --icase, -i		Ignore case of modulefile    **
492  **						names			     **
493  **			    --help, -H		Helpful usage info	     **
494  **			    --version, -V	Report version only	     **
495  ** 									     **
496  **   First Edition:	1995/12/20					     **
497  ** 									     **
498  **   Parameters:	int	*argc		Number of parameters	     **
499  **			char	*argv[]		Command line arguments	     **
500  **									     **
501  **   Result:		int	TCL_OK		Successful completion	     **
502  **				TCL_ERROR	Unknown switch found	     **
503  **			*argc, *argv		All switches are removed     **
504  **						from the argv vector	     **
505  ** 									     **
506  **   Attached Globals:	sw_force		--force, -f		     **
507  **			sw_format		-t, -l, -h, -p               **
508  **			sw_verbose		--verbose, -v, --silent, -s  **
509  **			sw_create		--create, -c		     **
510  **			sw_userlvl		--userlvl, -u		     **
511  **			sw_icase		--icase, -i		     **
512  ** 									     **
513  ** ************************************************************************ **
514  ++++*/
515 
Check_Switches(int * argc,char * argv[])516 static int	Check_Switches( int *argc, char *argv[])
517 {
518 
519     int c;
520 
521     /**
522      **  These are the options we do provide
523      **/
524 
525     const struct option longopts[] = {
526 	{ "force", no_argument, NULL, 'f' },
527 	{ "terse", no_argument, NULL, 't' },
528 	{ "long", no_argument, NULL, 'l' },
529 	{ "human", no_argument, NULL, 'h' },
530 	{ "parseable", no_argument, NULL, 'p' },
531 	{ "parse", no_argument, NULL, 'p' },
532 	{ "verbose", no_argument, NULL, 'v' },
533 	{ "silent", no_argument, NULL, 's' },
534 	{ "create", no_argument, NULL, 'c' },
535 	{ "icase", no_argument, NULL, 'i' },
536 	{ "userlvl", required_argument, NULL, 'u'},
537 	{ "append", no_argument, NULL, 'a' },
538 	{ "help", no_argument, NULL, 'H' },
539 	{ "version", no_argument, NULL, 'V' },
540 	{ NULL, no_argument, NULL, 0 }
541     };
542 
543 #if WITH_DEBUGGING_INIT
544     ErrorLogger( NO_ERR_START, LOC, _proc_Check_Switches, NULL);
545 #endif
546 
547     /**
548      **  Scan the command line for options defined in the longopt table.
549      **  Skip the very first argument, which is the shell to be used
550      **/
551 
552     if( *argc > 1) {
553 
554 	while( EOF != (c = getopt_long( *argc-1, &argv[1], "hpftlvsciu:aHV",
555 	    longopts, NULL))) {
556 
557 	    switch( c) {
558 
559 		/**
560 		 **  Force
561 		 **/
562 
563 		case 'f':			/* force */
564 		    sw_force = 1;
565 		    break;
566 
567 		/**
568 		 **  Format of the messages
569 		 **/
570 
571 		case 't':			/* terse */
572 		    sw_format |= (SW_SET | SW_TERSE);
573 		    sw_format &= ~ SW_LONG;
574 		    break;
575 
576 		case 'l':			/* long */
577 		    sw_format |= (SW_SET | SW_LONG);
578 		    sw_format &= ~ SW_TERSE;
579 		    break;
580 
581 		case 'h':			/* human */
582 		    sw_format |= (SW_SET | SW_HUMAN);
583 		    sw_format &= ~ SW_PARSE;
584 		    break;
585 
586 		case 'p':			/* parseable */
587 		    sw_format |= (SW_SET | SW_PARSE);
588 		    sw_format &= ~ SW_HUMAN;
589 		    break;
590 
591 		/**
592 		 **  Verbosity
593 		 **/
594 
595 		case 'v':			/* verbose */
596 		    sw_verbose = 1;
597 		    break;
598 
599 		case 's':			/* silent */
600 		    sw_detach = 1;
601 		    break;
602 
603 		/**
604 		 **  Caching control
605 		 **/
606 
607 		case 'c':			/* create */
608 		    sw_create = 1;
609 		    break;
610 
611 		/**
612 		 **  Locating
613 		 **/
614 
615 		case 'i':			/* icase */
616 		    sw_icase = 1;
617 		    break;
618 
619 		/**
620 		 **  The user level comes as a string argument to the -u option
621 		 **/
622 
623 		case 'u':			/* userlvl */
624 		    cmdModuleUser_sub( optarg);
625 		    break;
626 
627 		/**
628 		 **  a special purpose flag for 'use' only
629 		 **/
630 		case 'a':			/* --append */
631 		    append_flag = 1;
632 		    break;
633 
634 		case 'H':			/* helpful info */
635 		    module_usage(stderr);
636 		    return ~TCL_OK;
637 
638 		case 'V':			/* version */
639 		    version(stderr);
640 		    return ~TCL_OK;
641 
642 		/**
643 		 **  All remaining options will influence their flags as defined
644 		 **  in the optlong table above.
645 		 **/
646 
647 		case 0:
648 		    break;
649 
650 		/**
651 		 **  Error messages for unknown options will be printed by
652 		 **  getopt ...
653 		 **/
654 
655 		case '?':
656 		    break;
657 
658 		/**
659 		 **  Well, this seems to be an internal error
660 		 **/
661 
662 		default:
663 		    if( OK != ErrorLogger( ERR_GETOPT, LOC, NULL))
664 			return( TCL_ERROR);	/** --- EXIT (FAILURE) ----> **/
665 		    break;
666 
667 	    }  /** switch() **/
668 	}  /** while() **/
669     } /** if( argc) **/
670 
671     /**
672      **  Special things to be dine for the 'silent' option: Pipe stderr
673      **  output to /dev/null
674      **/
675 
676     if( sw_detach) {
677 	sw_verbose = 0;
678 	if (!ttyname(2)) {
679 	    int temp_fd = open("/dev/null", O_RDWR);
680 
681 	    close(2);
682 	    dup2(temp_fd, 2);
683 	}
684     }
685 
686     /**
687      **  Finally remove all options from the command line stream
688      **/
689 
690     c = optind - 1;
691     if( optind < *argc && c > 0) {
692 	while( optind < *argc) {
693 	    argv[ optind-c] = argv[ optind];
694 	    optind++;
695 	}
696 	*argc -= c;
697     }
698 
699     /**
700      **  Exit on success
701      **/
702 
703 #if WITH_DEBUGGING_INIT
704     ErrorLogger( NO_ERR_END, LOC, _proc_Check_Switches, NULL);
705 #endif
706 
707     return( TCL_OK);
708 
709 } /** End of 'Check_Switches' **/
710 
711 /*++++
712  ** ** Function-Header ***************************************************** **
713  ** 									     **
714  **   Function:		dup2						     **
715  ** 									     **
716  **   Description:	Duplicate file descriptor			     **
717  ** 									     **
718  **   First Edition:	1996/02/08					     **
719  ** 									     **
720  **   Parameters:	int	old		Old file descriptor	     **
721  **			int	new		New file descriptor	     **
722  **									     **
723  **   Result:		int	-1		any error		     **
724  **				other		new file descriptor	     **
725  ** 									     **
726  ** ************************************************************************ **
727  ++++*/
728 
729 #ifndef HAVE_DUP2
dup2(int old,int new)730 int dup2( int old, int new)
731 {
732     int fd;
733 
734     close(new);
735     fd = dup(old);
736     if (fd != new) {
737 	close( fd);
738 	errno = EMFILE;
739 	fd = -1;
740     }
741 
742     return( fd);
743 }
744 #endif
745 
746 /*++++
747  ** ** Function-Header ***************************************************** **
748  ** 									     **
749  **   Function:		version						     **
750  ** 									     **
751  **   Description:	Outputs the Modules version and features	     **
752  ** 									     **
753  **   First Edition:	2002/06/13					     **
754  ** 									     **
755  **   Parameters:	FILE *	output		All input is from defined    **
756  **						macros			     **
757  **   Result:		void			no return value		     **
758  **						All output is to output	     **
759  ** 									     **
760  **   Attached Globals:							     **
761  ** 			version_string		Current module version	     **
762  ** 			date_string		Current module date	     **
763  **									     **
764  ** ************************************************************************ **
765  ++++*/
766 
767 #define str(a) #a
768 #define isdefined(a,b)	{if (strcmp(str(a),b)) x=str(a); else x="undef"; \
769 			fprintf(output,format,b,x);}
770 
version(FILE * output)771 static void version (FILE *output) {
772 	char	*x,
773 		*format = "%s=%s\n";
774 
775 	fprintf(output, format, "VERSION", version_string);
776 	fprintf(output, format, "DATE", date_string);
777 	fprintf(output, "\n");
778 	isdefined(AUTOLOADPATH,str(AUTOLOADPATH));
779 	isdefined(BASEPREFIX,str(BASEPREFIX));
780 	isdefined(BEGINENV,str(BEGINENV));
781 	isdefined(CACHE_AVAIL,str(CACHE_AVAIL));
782 	isdefined(DEF_COLLATE_BY_NUMBER,str(DEF_COLLATE_BY_NUMBER));
783 	isdefined(DOT_EXT,str(DOT_EXT));
784 	isdefined(EVAL_ALIAS,str(EVAL_ALIAS));
785 	isdefined(HAS_BOURNE_FUNCS,str(HAS_BOURNE_FUNCS));
786 	isdefined(HAS_BOURNE_ALIAS,str(HAS_BOURNE_ALIAS));
787 	isdefined(HAS_TCLXLIBS,str(HAS_TCLXLIBS));
788 	isdefined(HAS_X11LIBS,str(HAS_X11LIBS));
789 	isdefined(LMSPLIT_SIZE,str(LMSPLIT_SIZE));
790 	isdefined(MODULEPATH,str(MODULEPATH));
791 	isdefined(MODULES_INIT_DIR,str(MODULES_INIT_DIR));
792 	isdefined(PREFIX,str(PREFIX));
793 	isdefined(TCL_VERSION,str(TCL_VERSION));
794 	isdefined(TCL_PATCH_LEVEL,str(TCL_PATCH_LEVEL));
795 	isdefined(TMP_DIR,str(TMP_DIR));
796 	isdefined(USE_FREE,str(USE_FREE));
797 	isdefined(VERSION_MAGIC,str(VERSION_MAGIC));
798 	isdefined(VERSIONPATH,str(VERSIONPATH));
799 	isdefined(WANTS_VERSIONING,str(WANTS_VERSIONING));
800 	isdefined(WITH_DEBUG_INFO,str(WITH_DEBUG_INFO));
801 
802 	fprintf(output, "\n");
803 }
804 
805 #undef str
806 #undef isdefined
807