1    | /*****
2    |  ** ** Module Header ******************************************************* **
3    |  ** 									     **
4    |  **   Modules Revision 3.0						     **
5    |  **   Providing a flexible user environment				     **
6    |  ** 									     **
7    |  **   File:		Modulate_Avail.c				     **
8    |  **   First Edition:	1991/10/23					     **
9    |  ** 									     **
10   |  **   Authors:	John Furlan, jlf@behere.com				     **
11   |  **		Jens Hamisch, jens@Strawberry.COM			     **
12   |  ** 									     **
13   |  **   Description: 	This module command prints out the modulefiles that  **
14   |  **			are available in the directories listed in the	     **
15   |  **			MODULEPATH environment variable.		     **
16   |  ** 									     **
17   |  **   Exports:		ModuleCmd_Avail					     **
18   |  **			print_aligned_files				     **
19   |  **			check_dir					     **
20   |  **			get_dir						     **
21   |  **			dirlst_to_list					     **
22   |  **			delete_dirlst					     **
23   |  **			delete_cache_list				     **
24   |  ** 									     **
25   |  **   Notes:								     **
26   |  ** 									     **
27   |  ** ************************************************************************ **
28   |  ****/
29   | 
30   | /** ** Copyright *********************************************************** **
31   |  ** 									     **
32   |  ** Copyright 1991-1994 by John L. Furlan.                      	     **
33   |  ** see LICENSE.GPL, which must be provided, for details		     **
34   |  ** 									     ** 
35   |  ** ************************************************************************ **/
36   | 
37   | static char Id[] = "@(#)$Id: ModuleCmd_Avail.c.src.html,v 1.6 2006/01/18 05:35:11 rkowen Exp $";
38   | static void *UseId[] = { &UseId, Id };
39   | 
40   | /** ************************************************************************ **/
41   | /** 				      HEADERS				     **/
42   | /** ************************************************************************ **/
43   | 
44   | #include <time.h>
45   | #include "modules_def.h"
46   | 
47   | /** ************************************************************************ **/
48   | /** 				  LOCAL DATATYPES			     **/
49   | /** ************************************************************************ **/
50   | 
51   | /**
52   |  **  Structure for a linked list that stores directories to be listed.
53   |  **/
54   | 
55   | typedef struct _subdir_node {
56   |   fi_ent*              sd_dir;
57   |   struct _subdir_node* sd_next;
58   | } sd_node;
59   | 
60   | /** ************************************************************************ **/
61   | /** 				     CONSTANTS				     **/
62   | /** ************************************************************************ **/
63   | 
64   | /**
65   |  **  I tried having a test for isgraph() in the configuration file,
66   |  **  but it fails on AIX. This is the best I could come up with...
67   |  **/
68   | 
69   | #if !defined(isgraph) && defined(_P) && defined(_N)
70   | #define isgraph(c)	((_ctype_+1)[c]&(_P|_U|_L|_N))
71   | #endif
72   | 
73   | #define DIREST  50
74   | #define  CACHE_VERSION  "v3.0.0"
75   | 
76   | #if !defined(CACHE_UMASK)
77   | #define CACHE_UMASK	0
78   | #endif
79   | 
80   | /** ************************************************************************ **/
81   | /**				      MACROS				     **/
82   | /** ************************************************************************ **/
83   | 
84   | /** not applicable **/
85   | 
86   | /** ************************************************************************ **/
87   | /** 				    LOCAL DATA				     **/
88   | /** ************************************************************************ **/
89   | 
90   | #ifdef CACHE_AVAIL
91   | static	char	*namebuf = NULL;
92   | #endif
93   | static	char	 buffer[MOD_BUFSIZE];
94   | static	char	 buf[ LINELENGTH];
95   | static	char	 module_name[] = "ModuleCmd_Avail.c";	/** File name of this module **/
96   | 
97   | #if WITH_DEBUGGING_MODULECMD
98   | static	char	_proc_ModuleCmd_Avail[] = "ModuleCmd_Avail";
99   | #endif
100  | #if WITH_DEBUGGING_UTIL_1
101  | static	char	_proc_print_dir[] = "print_dir";
102  | static	char	_proc_print_aligned_files[] = "print_aligned_files";
103  | #endif
104  | #if WITH_DEBUGGING_UTIL_2
105  | static	char	_proc_check_dir[] = "check_dir";
106  | static	char	_proc_get_dir[] = "get_dir";
107  | static	char	_proc_dirlst_to_list[] = "dirlst_to_list";
108  | static	char	_proc_delete_dirlst[] = "delete_dirlst";
109  | static	char	_proc_store_files[] = "store_files";
110  | static	char	_proc_store_dirlst[] = "store_dirlst";
111  | static	char	_proc_store_file[] = "store_file";
112  | #ifdef CACHE_AVAIL
113  | static	char	_proc_create_cache_list[] = "create_cache_list";
114  | #endif
115  | static	char	_proc_delete_cache_list[] = "delete_cache_list";
116  | static	char	_proc_print_spaced_file[] = "print_spaced_file";
117  | static	char	_proc_mkdirnm[] = "mkdirnm";
118  | #endif
119  | 
120  | #if	WITH_DEBUGGING
121  | static	char	buffer1[ 80], buffer2[ 80];
122  | #endif
123  | 
124  | static	char	short_format[] = "%s";
125  | static	char	short_format_part[] = "%s/%s";
126  | static	char	short_format_full[] = "%s/%s(%s)";
127  | static	char	long_format[] = "%-39.39s  %-10.10s  %17s\n";
128  |  	char	long_header[] = "\
129  | - Package -----------------------------+- Versions -+- Last mod. ------\n";
130  | 
131  | /**
132  |  **  Terse file list buffer
133  |  **/
134  | 
135  | #define	FILE_LIST_SEGM_SIZE 100
136  | static	char	  _file_list_buffer[ 200];
137  | static	char	**_file_list_ptr = (char **) NULL;
138  | static	int	  _file_list_cnt = 0;
139  | static	int	  _file_list_wr_ndx = 0;
140  | static	int	  _file_list_rd_ndx = 0;
141  | 
142  | /** ************************************************************************ **/
143  | /**				    PROTOTYPES				     **/
144  | /** ************************************************************************ **/
145  | 
146  | static	int	  print_dir( Tcl_Interp*, char*, char*);
147  | #ifdef CACHE_AVAIL
148  | static	void	  store_dirlst( FILE*, FILE*, fi_ent*, int, char*);
149  | static	void	  store_files( fi_ent*, int, int, char*);
150  | static	void	  store_file( FILE*, char*, fi_ent*);
151  | #endif
152  | static	void	  print_spaced_file( char*, int, int, int);
153  | static	char	 *mkdirnm( char*, char*);
154  | static	int	  fi_ent_cmp( const void*, const void*);
155  | #ifdef CACHE_AVAIL
156  | static	int	  check_cache( char *dir);
157  | #endif
158  | static	void	  _init_file_list(void);
159  | static	void	  _add_file_list( char *name);
160  | static	char	 *_get_file_list(void);
161  | static	char	 *_pick_file_list( int ndx);
162  | static	void	  print_terse_files( int terminal_width, int len, char *header,
163  | 			int numbered);
164  | #ifdef CACHE_AVAIL
165  | static	char	**create_cache_list( FILE*, int*, char* );
166  | #endif
167  | 
168  | /*++++
169  |  ** ** Function-Header ***************************************************** **
170  |  ** 									     **
171  |  **   Function:		ModuleCmd_Avail					     **
172  |  ** 									     **
173  |  **   Description:	Execution of the 'module avail' command		     **
174  |  ** 									     **
175  |  **   First Edition:	1991/10/23					     **
176  |  ** 									     **
177  |  **   Parameters:	Tcl_Interp	*interp		Current Tcl Interpr. **
178  |  **			char		*argv[]		Arguments to the     **
179  |  **							command		     **
180  |  ** 									     **
181  |  **   Result:		int	TCL_OK		Successfull operation	     **
182  |  **				TCL_ERROR	Any failure		     **
183  |  ** 									     **
184  |  **   Attached Globals:	g_specified_module	The module name from the     **
185  |  **						command line.		     **
186  |  ** 									     **
187  |  ** ************************************************************************ **
188  |  ++++*/
189  | 
190  | int ModuleCmd_Avail(	Tcl_Interp	*interp,
191  | 			int		 argc,
192  |                 	char		*argv[])
193  | {
194  |     char	*dirname;
195  |     char	*modpath;
196  |     int		 Result = -TCL_ERROR;
197  |     
198  | #if WITH_DEBUGGING_MODULECMD
199  |     ErrorLogger( NO_ERR_START, LOC, _proc_ModuleCmd_Avail, NULL);
200  | #endif
201  | 
202  |     /**
203  |      **  If there's no MODULEPATH defined, we cannot output anything
204  |      **  We perform 1 level of env.var. expansion
205  |      **/
206  | 
207  |     if( !(modpath = (char *) xgetenv( "MODULEPATH")))
208  | 	if( OK != ErrorLogger( ERR_MODULE_PATH, LOC, NULL))
209  | 	    goto unwind0;
210  |  
211  | #ifdef CACHE_AVAIL
212  |     if( (char *) NULL == (namebuf = stringer(NULL, MOD_BUFSIZE, NULL)))
213  | 	if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
214  | 	    goto unwind1;
215  | #endif
216  | 
217  |     /**
218  |      **  If we're given a full-path, then we'll just check that directory.
219  |      **  Otherwise, we'll check every directory in MODULESPATH.
220  |      **/
221  | 
222  |     if( argc > 0 && **argv == '/') {
223  | 
224  | 	while( argc--) {
225  | 
226  | 	    /**
227  | 	     ** Set the name of the module specified on the command line
228  | 	     **/
229  | 
230  | 	    g_specified_module = *argv;
231  | 
232  | 	    if( !check_dir( *argv))
233  | 		if( OK != ErrorLogger( ERR_PARAM, LOC, NULL)) {
234  | 		    Result = TCL_ERROR;	/** --- EXIT PROCEDURE (FAILURE) --> **/
235  | 		}
236  | 	    else
237  | 		print_dir( interp, *argv, NULL);
238  | 
239  | 	    argv++;
240  | 	}
241  | 
242  |     } else {
243  | 
244  | 	/**
245  | 	 **  We're not given a full path. Tokenize the module path string and
246  | 	 **  print the contents of each directory specified (if it exists ;-)
247  | 	 **/
248  | 
249  | 	if( sw_format & SW_LONG)
250  | 	    fprintf( stderr, long_header);
251  | 
252  | 	/**
253  | 	 **  If a module category is specified check whether it is part
254  | 	 **  of the directory we're scanning at the moment.
255  | 	 **/
256  | 
257  | 	if( argc > 0) {  /* show sub directory */
258  | 	    while( argc--) {
259  | 		/**
260  | 		 ** Set the name of the module specified on the command line
261  | 		 **/
262  | 
263  | 		g_specified_module = *argv;
264  | 
265  | 		dirname = modpath;
266  | 		while( dirname && *dirname) {
267  | 
268  | 		    /**
269  | 		     **  We cannot use strtok here, because it interfers with
270  | 		     **  subsequent calls while printing the list
271  | 		     **/
272  | 
273  | 		    char *s;
274  | 		
275  | 		    if( s = strchr( dirname, ':'))
276  | 			*s++ = '\0';
277  | 
278  | 		    /**
279  | 		     **  Print the cathegory
280  | 		     **/
281  | 
282  | 		    if( check_dir( dirname))
283  | 			print_dir( interp, dirname, *argv);
284  | 		    dirname = s;
285  | 		}
286  | 
287  | 		argv++;
288  | 	    }
289  | 
290  | 	/**
291  | 	 **  Otherwise, if there's no category given, descend the current
292  | 	 **  directory and print its contents.
293  | 	 **/
294  | 
295  | 	} else {
296  | 
297  | 	    dirname = modpath;
298  | 	    while( dirname && *dirname) {
299  | 
300  | 		/**
301  | 		 **  We cannot use strtok here, because it interfers with
302  | 		 **  subsequent calls while printing the list
303  | 		 **/
304  | 
305  | 		char *s;
306  | 	    
307  | 		if( s = strchr( dirname, ':'))
308  | 		    *s++ = '\0';
309  | 
310  | 		/**
311  | 		 **  Second part of tokenization
312  | 		 **/
313  | 
314  | 		if( check_dir( dirname))
315  | 		    print_dir( interp, dirname, NULL);
316  | 		dirname = s;
317  | 	    }
318  | 
319  |         } /** for **/
320  |     } /** if( no full path name given) **/
321  | 
322  |     /**
323  |      **  Free up what has been allocated and exit from this procedure
324  |      **/
325  |     /* if got here via this path ... it must have been OK */
326  |     if(Result < 0) Result = TCL_OK;
327  | 
328  | unwind2:
329  | #ifdef CACHE_AVAIL
330  |     null_free((void *) &namebuf);
331  | #endif
332  | unwind1:
333  |     null_free((void *) &modpath);
334  | 
335  | unwind0:
336  | #if WITH_DEBUGGING_MODULECMD
337  |     ErrorLogger( NO_ERR_END, LOC, _proc_ModuleCmd_Avail, NULL);
338  | #endif
339  | 
340  |     /* if Result is negative here ... must have been an unwind */
341  |     if (Result < 0) Result = -Result;
342  | 
343  |     return( Result);		/** --- EXIT PROCEDURE (FAILURE/SUCCESS) --> **/
344  | 
345  | } /** End of 'ModuleCmd_Avail' **/
346  | 
347  | /*++++
348  |  ** ** Function-Header ***************************************************** **
349  |  ** 									     **
350  |  **   Function:		check_dir					     **
351  |  ** 									     **
352  |  **   Description:	Open and close the passed directory in order to check**
353  |  **			if it does exist and is readable		     **
354  |  ** 									     **
355  |  **   First Edition:	1991/10/23					     **
356  |  ** 									     **
357  |  **   Parameters:	char	*dirname	Name of the directory to be  **
358  |  **						checked			     **
359  |  ** 									     **
360  |  **   Result:		int	0	Not a directory or unreadable	     **
361  |  **				1	OK				     **
362  |  ** 									     **
363  |  **   Attached Globals:	-						     **
364  |  ** 									     **
365  |  ** ************************************************************************ **
366  |  ++++*/
367  | 
368  | int check_dir(	char	*dirname)
369  | {
370  |     DIR*   dirp;
371  | 
372  | #if WITH_DEBUGGING_UTIL_2
373  |     ErrorLogger( NO_ERR_START, LOC, _proc_check_dir, NULL);
374  | #endif
375  | 
376  |     if( !(dirp = opendir( dirname))) 
377  | 	return( 0);
378  | 
379  |     if( -1 == closedir( dirp))
380  | 	if( OK != ErrorLogger( ERR_CLOSEDIR, LOC, dirname, NULL))
381  | 	    return( 0);
382  | 
383  |     return( 1);
384  | 
385  | } /** End of 'check_dir' **/
386  | 
387  | /*++++
388  |  ** ** Function-Header ***************************************************** **
389  |  ** 									     **
390  |  **   Function:		print_dir					     **
391  |  ** 									     **
392  |  **   Description:	Print all files beyond the passed directory	     **
393  |  ** 									     **
394  |  **   First Edition:	1991/10/23					     **
395  |  ** 									     **
396  |  **   Parameters:	char	*dir		Directory to be scanned	     **
397  |  **			char	*module		A selcted module name or NULL**
398  |  ** 									     **
399  |  **   Result:		int	TCL_OK		Successfull operation	     **
400  |  ** 									     **
401  |  **   Attached Globals:	-						     **
402  |  ** 									     **
403  |  ** ************************************************************************ **
404  |  ++++*/
405  | 
406  | static	int	print_dir(	Tcl_Interp	*interp,
407  | 				char		*dir,
408  | 				char		*module)
409  | {
410  |     fi_ent	 *dirlst_head = NULL;	/** Directory list base pointer	     **/
411  |     int		  count = 0;		/** Number of elements in the top    **/
412  | 					/** level directory list	     **/
413  |     int		  tcount = 0;		/** Total number of files to print   **/
414  |     int	 	  start = 0;
415  |     int		  dirlen;
416  |     char	**cache_list = NULL;
417  |     char	 *selection, *s;
418  | 
419  | #ifdef CACHE_AVAIL
420  |     int		  usecache;
421  |     FILE	 *fi;
422  | #endif
423  | 
424  | #if WITH_DEBUGGING_UTIL_1
425  |     ErrorLogger( NO_ERR_START, LOC, _proc_print_dir, "dir='", dir, NULL);
426  | #endif
427  | 
428  |     /**
429  |      **  Print the directory name
430  |      **/
431  | 
432  |     if( (sw_format & (SW_PARSE | SW_TERSE | SW_LONG))
433  |     && !(sw_format & (SW_HUMAN | SW_LIST)) ) {
434  | 	/* char *base = strrchr( dir, '/');
435  | 	fprintf( stderr, "%s:\n", base ? ++base : dir);
436  | 	*/
437  | 	fprintf( stderr, "%s:\n", dir);
438  |     }
439  | 
440  |     if( dir)
441  | 	dirlen = strlen( dir) + 1;
442  |     else
443  | 	dirlen = 0;
444  | 
445  |     /**
446  |      **  If the is a module selection given, build the whole selected path
447  |      **/
448  | 
449  |     if( module) {
450  | 
451  | 	if( dir) {
452  | 	    if((char *) NULL == (selection = stringer(NULL, 0,
453  | 		dir,"/",module, NULL))) {
454  | 		ErrorLogger( ERR_STRING, LOC, NULL);
455  | 		return( TCL_ERROR);     /** --- EXIT (FAILURE) --------> **/
456  | 	    }
457  | 
458  | 	} else
459  | 	    selection = module;
460  | 
461  |     } else
462  | 	selection = (char *) NULL;
463  | 
464  | #ifdef CACHE_AVAIL
465  | 
466  |     /**
467  |      **  Ensure any files I create can be read and written by everyone
468  |      **/
469  | 
470  |     umask( CACHE_UMASK);
471  | 
472  |     /**
473  |      **  OK, if cache is to be used, go on reading the entire cache.
474  |      **  In case of success print the files. Otherwise read the files
475  |      **  from the file system and rebuild the cache.
476  |      **/
477  | 
478  |     if( usecache = check_cache( dir)) {
479  | 
480  | 	if( !sw_create) {
481  | 
482  | 	    if( (char *) NULL == stringer(namebuf, MOD_BUFSIZE,
483  | 		dir, "/.moduleavailcache", NULL))
484  | 		if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
485  | 		    goto unwind1;
486  | 
487  | 	    if( NULL == (fi = fopen( namebuf, "r"))) {
488  | 		if( OK != ErrorLogger( ERR_OPEN, LOC, namebuf, "reading", NULL))
489  | 		    goto unwind1;
490  | 
491  | 	    } else {
492  | 
493  | 		cache_list = create_cache_list( fi, &tcount, selection);
494  | 
495  | 		/**
496  | 		 **  Close the cache file
497  | 		 **/
498  | 
499  | 		if( EOF == fclose( fi))
500  | 		    if( OK != ErrorLogger( ERR_CLOSE, LOC, namebuf, NULL))
501  | 			goto unwind1;
502  | 	    }
503  | 
504  | 	} /** if( !create) **/
505  | 
506  |     }
507  | #endif
508  | 
509  |     if( !cache_list) {
510  | #ifdef CACHE_AVAIL
511  | 	usecache = 0;
512  | #endif
513  | 
514  | 	/**
515  | 	 **  Normal reading of the files
516  | 	 **/
517  | 
518  | 	if( NULL == (dirlst_head = get_dir( dir, NULL, &count, &tcount)))
519  | 	    if( OK != ErrorLogger( ERR_READDIR, LOC, dir, NULL))
520  | 		goto unwind1;
521  | 
522  | 	if( NULL == (cache_list = (char**) malloc( tcount * sizeof( char**))))
523  | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
524  | 		goto unwind1;
525  | 	(void) memset(cache_list, 0, tcount * sizeof( char **));
526  | 
527  | 	start=0;
528  | 	dirlst_to_list( cache_list, dirlst_head, count, &start, dir, selection);
529  | 
530  |     }
531  | #ifdef CACHE_AVAIL
532  | 
533  |     /**
534  |      **  Now open the files used for caching
535  |      **  In case of any error flush out the read files and exit
536  |      **/
537  | 
538  |     if( !usecache && sw_create)
539  | 	store_files( dirlst_head, count, tcount, dir);
540  | #endif
541  |     
542  |     /**
543  |      **  In case of any selection, we have to force all .modulrc's and .versions
544  |      **  on the path
545  |      **/
546  | 
547  |     if( dir) {
548  | 
549  | 	s = dir;
550  | 	while( s) {
551  | 	    if( s = strchr( s, '/'))
552  | 	    	*s = '\0';
553  | 	    else
554  | 		break;
555  | 
556  | 	    SourceRC( interp, dir, modulerc_file);
557  | 	    SourceVers( interp, dir, module);
558  | 
559  | 	    if( s)
560  | 		*s++ = '/';
561  | 	}
562  | 
563  | 	/**
564  | 	 **  Finally source the rc files in the directory itself
565  | 	 **/
566  | 
567  | 	SourceRC( interp, dir, modulerc_file);
568  | 	SourceVers( interp, dir, module);
569  |     }
570  | 
571  |     if( dir && selection)
572  | 	null_free((void *) &selection);
573  | 
574  |     /**
575  |      **  Print and remove the cache list
576  |      **/
577  | 
578  |     delete_dirlst( dirlst_head, count);
579  |     print_aligned_files( interp, dir, dir, cache_list, tcount,
580  | 	(sw_format & SW_LIST ? 1 : -1));
581  |     delete_cache_list( cache_list, start);
582  | 
583  |     if( sw_format & SW_LONG)
584  | 	fprintf( stderr, "\n");
585  |     return( TCL_OK);     		/** ------- EXIT (SUCCESS) --------> **/
586  | 
587  | unwind1:
588  |     if( dir && selection)
589  | 	null_free((void *) &selection);
590  | 
591  | unwind0:
592  |     return( TCL_ERROR);     		/** ------- EXIT (FAILURE) --------> **/
593  | 
594  | } /** End of 'print_dir' **/
595  | 
596  | /*++++
597  |  ** ** Function-Header ***************************************************** **
598  |  ** 									     **
599  |  **   Function:		check_cache					     **
600  |  ** 									     **
601  |  **   Description:	Check whether an avail cache exists and is not out   **
602  |  **			of date						     **
603  |  ** 									     **
604  |  **   First Edition:	1996/01/03					     **
605  |  ** 									     **
606  |  **   Parameters:	char	*dir		Directory to be checked	     **
607  |  ** 									     **
608  |  **   Result:		int	0	Do not use the cache		     **
609  |  **				1	Use the cache			     **
610  |  ** 									     **
611  |  **   Attached Globals:	-						     **
612  |  ** 									     **
613  |  ** ************************************************************************ **
614  |  ++++*/
615  | 
616  | #ifdef CACHE_AVAIL
617  | 
618  | static	int	check_cache( char *dir)
619  | {
620  |     time_t       dir_time=0, cache_time=0, info_time=0;
621  |     struct stat  dir_stats, cache_stats;
622  |     FILE	*cdir;
623  | 
624  |     /**
625  |      **  Check if a cache file exists. And if it does, check if it is
626  |      **  younger than the related directory.
627  |      **/
628  | 
629  |     if( (char *) NULL == stringer(namebuf, MOD_BUFSIZE,
630  | 	dir, "/.moduleavailcachedir", NULL))
631  |             return( 0);
632  | 
633  |     if( NULL != (cdir = fopen( namebuf, "r"))) {
634  |         if( stat( dir, &dir_stats) != -1) {
635  |             if( stat( namebuf, &cache_stats) != -1) {
636  |                 dir_time = dir_stats.st_mtime;
637  |                 cache_time = cache_stats.st_mtime;
638  |             }
639  |             if( dir_time > cache_time) {
640  |                 return( 0);
641  |             }
642  |         }
643  | 
644  | 	/**
645  | 	 **  Also check if the modification date of the cached files isn't
646  | 	 **  younger than the one derivered from the cache
647  | 	 **/
648  | 
649  |         while( !feof(cdir)) {
650  | 
651  | 	    if( fscanf( cdir, "%s %d\n", buf, (int *)&info_time) != 2)
652  | 	        continue;
653  | 
654  |             if( stat( buf, &dir_stats) != -1) {
655  |                 if( dir_stats.st_mtime <= info_time) 
656  |                     continue;
657  |             }
658  | 
659  |             return( 0);
660  |         }
661  | 
662  | 	/**
663  | 	 **  Close the cache file
664  | 	 **/
665  | 
666  |         if( EOF == fclose( cdir))
667  | 	    if( OK != ErrorLogger( ERR_CLOSE, LOC, namebuf, NULL))
668  | 		return( 0);		/** ------- EXIT (FAILURE) --------> **/
669  | 
670  | 	return( 1);
671  |     }
672  | 
673  |     return( 0);
674  | 
675  | } /** End of 'check_cache' **/
676  | 
677  | #endif
678  | 
679  | 
680  | static int	test_version_dir(	struct dirent	*dp)
681  | {
682  | }
683  | /*++++
684  |  ** ** Function-Header ***************************************************** **
685  |  ** 									     **
686  |  **   Function:		get_dir						     **
687  |  ** 									     **
688  |  **   Description:	Read in the passed directory and save every interes- **
689  |  **			ting item in the directory list			     **
690  |  **			skipping known version control directories:	     **
691  |  **				CVS RCS .svn				     **
692  |  **			unless they contain .version files		     **
693  |  ** 									     **
694  |  **   First Edition:	1991/10/23					     **
695  |  ** 									     **
696  |  **   Parameters:	char	*dir		Directory to be read	     **
697  |  **			char	*prefix		Directory prefix (path)	     **
698  |  **			int	*listcount	Buffer to store the number of**
699  |  **						elements in the current      **
700  |  **						directory list		     **
701  |  **			int 	*total_count	Buffer for the total number  **
702  |  **						of files read		     **
703  |  ** 									     **
704  |  **   Result:		fi_ent*		NULL	Failure			     **
705  |  **					else	Directory list base pointer  **
706  |  **			*listcount		Number of elements in the    **
707  |  **						top level directory list     **
708  |  **			*total_count		Total number of files read   **
709  |  ** 									     **
710  |  **   Attached Globals:	-						     **
711  |  ** 									     **
712  |  ** ************************************************************************ **
713  |  ++++*/
714  | 
715  | fi_ent	*get_dir(	char	*dir,
716  | 			char	*prefix,
717  | 			int	*listcount,
718  | 			int	*total_count)
719  | {
720  |     struct dirent	*dp;		/** Directory read pointer	     **/
721  |     DIR			*dirptr;	/** Directory handle		     **/
722  |     fi_ent		*dirlst_head,	/** Directory list pointers. Head,   **/
723  |     			*dirlst_cur,	/** current			     **/
724  |     			*dirlst_last;	/** and last			     **/
725  |     char		*dirname;	/** Expanded directory path name     **/
726  |     char		*tmp;		
727  |     int			 count = 0;
728  | 
729  | #if WITH_DEBUGGING_UTIL_2
730  |     ErrorLogger( NO_ERR_START, LOC, _proc_get_dir, NULL);
731  | #endif
732  | 
733  |     /**
734  |      **  Open the desired directiory
735  |      **/
736  | 
737  |     if( !(dirptr = opendir( dir))) {
738  | #if 0
739  | 	/* if you can't open a directory ... is that really an error? */
740  | 	if( OK != ErrorLogger( ERR_OPENDIR, LOC, dir, NULL))
741  | #endif
742  | 	    return( NULL);	/** ----------- EXIT (FAILURE) ------------> **/
743  |     }
744  | 
745  |     /**
746  |      **  Allocate memory for reading in the directory
747  |      **/
748  | 
749  |     if( NULL == (dirlst_cur = dirlst_head = (fi_ent*) calloc( DIREST,
750  | 	sizeof( fi_ent)))) {
751  | 	if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) {
752  | 	    if( -1 == closedir( dirptr))
753  | 		ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL);
754  | 	    goto unwind0;
755  | 	}
756  |     }
757  |     dirlst_last = dirlst_head + DIREST;
758  |   
759  |     /**
760  |      **  Read in the  contents of the directory. Ignore dotfiles
761  |      **		and version directories.
762  |      **/
763  | 
764  |     for( count = 0,  dp = readdir( dirptr); dp != NULL; dp = readdir( dirptr)) {
765  |         if( *dp->d_name == '.') continue;
766  | 
767  | 	/**
768  | 	 **  Conditionally double up the space allocated for reading the direc-
769  | 	 **  tory
770  | 	 **/
771  | 
772  |         if(dirlst_cur == dirlst_last) {
773  |             if( NULL == (dirlst_head = (fi_ent*) realloc( (char*) dirlst_head, 
774  | 		(count<<1) * sizeof( fi_ent)))) 
775  | 		if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) 
776  | 		    goto unwind0;
777  |             dirlst_cur = dirlst_head + count;
778  |             dirlst_last = dirlst_head + (count<<1);
779  | 	}
780  | 
781  | 	/**
782  | 	 **  Build the complete path name and get information about the file
783  | 	 **/
784  | 
785  |         if( !( dirname = mkdirnm( dir, dp->d_name)))
786  | 	    if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) {
787  | 		if( -1 == closedir( dirptr))
788  | 		    ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL);
789  | 		goto unwind1;
790  | 	    }
791  | 
792  |         if( stat( dirname, &(dirlst_cur->fi_stats)) < 0)
793  | 	    if( OK != ErrorLogger( ERR_DIRNOTFOUND, LOC, dirname, NULL)) {
794  | 		if( -1 == closedir( dirptr))
795  | 		    ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL);
796  | 		goto unwind1;
797  | 	    }
798  | 
799  | 	/**
800  | 	 **  If it is a directory, recursively delve into it ..
801  | 	 **/
802  | 
803  |         if(dirlst_cur->fi_stats.st_mode & S_IFDIR) {
804  |             char* np;
805  |             char* ndir;
806  |             int   tmpcount = 0;
807  | 
808  | 	    /**
809  | 	     **  Build the new base points for the recursion
810  | 	     **/
811  | 
812  |             if( !( tmp = mkdirnm( prefix, dp->d_name))) {
813  | 		if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) {
814  | 		    if( -1 == closedir( dirptr))
815  | 			ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL);
816  | 		    goto unwind1;
817  | 		}
818  | 	    } else {
819  | 		if( NULL == (np = strdup( tmp)))
820  | 		    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
821  | 			goto unwind1;
822  | 	    }
823  | 
824  |             if( !( tmp = mkdirnm( dir, dp->d_name))) {
825  | 		if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) {
826  | 		    if( -1 == closedir( dirptr))
827  | 			ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL);
828  | 		    goto unwind1;
829  | 		}
830  | 	    } else {
831  | 		if( NULL == (ndir = strdup( tmp)))
832  | 		    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) 
833  | 			goto unwind1;
834  | 	    }
835  | 
836  | 	    /**
837  | 	     **  What if it's a known version control directory
838  | 	     **  check if it has a .version file
839  | 	     **/
840  | 	    if (!strcmp("CVS",dp->d_name)
841  | 	    ||  !strcmp("RCS",dp->d_name)
842  | 	    ||  !strcmp(".svn",dp->d_name)) {
843  |     		FILE	*fi;
844  | 		if( (char *) NULL == stringer(buffer, MOD_BUFSIZE,
845  | 		    tmp, "/.version", NULL))
846  | 		    if( OK != ErrorLogger( ERR_STRING, LOC, NULL))
847  | 			goto unwind1;
848  | 		if( NULL == (fi = fopen( buffer, "r"))) {
849  | 			/* does not have a .version file */
850  | 			continue;
851  | 		} else {
852  | 			/* has a .version file ... assume to be module dir */
853  | 			fclose(fi);
854  | 		}
855  | 	    }
856  | 
857  | 	    /**
858  | 	     **  The recursion itself ...
859  | 	     **/
860  | 
861  |             dirlst_cur->fi_subdir = get_dir( ndir,np,&dirlst_cur->fi_listcount,
862  | 		&tmpcount);
863  | 
864  |             /**
865  |              **  Add the number of real modulefiles (i.e. not subdirs and 
866  |              **  not non-modulefiles) to our total number of modulefiles 
867  |              **  contained in the structure.
868  |              **/
869  | 
870  |             *total_count += tmpcount;
871  | 
872  |             /**
873  |              **  This means that it's an empty directory so the prefix is
874  | 	     **  never used
875  |              **/
876  | 
877  |             if( !dirlst_cur->fi_listcount)
878  | 		null_free((void *) &np);
879  |             null_free((void *) &ndir);
880  | 
881  | 	/**
882  | 	 **  if it is not a directory check the magic cookie of the file. Only
883  | 	 **  files with the modules magic cookie will be accepted. Also tem-
884  | 	 **  porary files are to be ignored.
885  | 	 **/
886  | 
887  |         } else if( dp->d_name[NLENGTH(dp)-1] == '~' ||
888  | 	    !check_magic( dirname, MODULES_MAGIC_COOKIE,
889  | 		MODULES_MAGIC_COOKIE_LENGTH)) {
890  | 	    continue;
891  | 	} else {
892  | 	    dirlst_cur->fi_subdir = NULL;
893  | 	}
894  | 
895  | 	/**
896  | 	 **  Put the name of the file on the directory list
897  | 	 **/
898  | 
899  | 	dirlst_cur->fi_prefix = prefix;
900  | 	if( NULL == (dirlst_cur->fi_name = strdup( dp->d_name)))
901  | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) 
902  | 		goto unwind1;
903  | 
904  | 	/**
905  | 	 **  Count even the number of elements in the current list as the
906  | 	 **  total number of elements read in so far.
907  | 	 **  Increment the list index to be prepared for the next entry.
908  | 	 **/
909  | 
910  | 	count++;
911  | 	(*total_count)++;
912  | 	dirlst_cur++;
913  | 
914  |     } /** for **/
915  | 
916  |     /**
917  |      **  Now sort alphabetically what has been read
918  |      **/
919  | 
920  |     if( count > 1)
921  | 	qsort( dirlst_head, count, sizeof(fi_ent), fi_ent_cmp);
922  | 
923  |     /**
924  |      **  Close the directory, set up return values
925  |      **/
926  | 
927  |     if( -1 == closedir( dirptr))
928  | 	if( OK != ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL))
929  | 	    goto unwind1;
930  | 
931  |     *listcount = count;
932  |     return( dirlst_head); 	/** ----------- EXIT (SUCCESS) ------------> **/
933  | 
934  | unwind1:
935  |     null_free((void *) &dirlst_cur);
936  | 
937  | unwind0:
938  |     return( NULL);	 	/** ----------- EXIT (FAILURE) ------------> **/
939  | } /** End of 'get_dir' **/
940  | 
941  | /*++++
942  |  ** ** Function-Header ***************************************************** **
943  |  ** 									     **
944  |  **   Function:		dirlst_to_list					     **
945  |  ** 									     **
946  |  **   Description:	Transform the passed nested directory list into a    **
947  |  **			flat list of strings				     **
948  |  ** 									     **
949  |  **   First Edition:	1991/10/23					     **
950  |  ** 									     **
951  |  **   Parameters:	char	**list		List to be created	     **
952  |  **			fi_ent	 *dirlst_head	Head of the directory list   **
953  |  **						to be transformed	     **
954  |  **			int	  count		Number of elements in the    **
955  |  **						directory list		     **
956  |  **			int	 *beginning	Index of the element in List **
957  |  **						to start appending the file- **
958  |  **						names at.		     **
959  |  **			char	 *path		prepend pathname to list     **
960  |  **			char	 *module	A search pattern	     **
961  |  **									     **
962  |  **   Result:		-						     **
963  |  ** 									     **
964  |  **   Attached Globals:	-						     **
965  |  ** 									     **
966  |  ** ************************************************************************ **
967  |  ++++*/
968  | 
969  | void	dirlst_to_list(	char	**list,
970  | 			fi_ent	 *dirlst_head,
971  | 			int	  count,
972  | 			int	 *beginning,
973  | 			char	 *path,
974  | 			char	 *module)
975  | {
976  |     fi_ent	*dirlst_cur;	
977  |     int 	 i;
978  |     char	*ptr;
979  |     int		 mlen;
980  | 
981  |     /**
982  |      **  If there's any selection given, figure out its length
983  |      **/
984  | 
985  |     if( module)
986  | 	mlen = strlen( module);
987  | 
988  |     /**
989  |      **  Put all files in the directory list at the end of the passed list
990  |      **  of character arrays
991  |      **/
992  | 
993  | #if WITH_DEBUGGING_UTIL_2
994  |     ErrorLogger( NO_ERR_START, LOC, _proc_dirlst_to_list, NULL);
995  | #endif
996  | 
997  |     for( i=0, dirlst_cur=dirlst_head;
998  | 	 i<count && dirlst_cur;
999  |          i++, dirlst_cur++) {
1000 | 
1001 |         if( dirlst_cur->fi_prefix) {
1002 | 
1003 | 	    if( path) {
1004 | 		if( (char *) NULL == stringer(buf, MOD_BUFSIZE,
1005 | 		    path,"/", dirlst_cur->fi_prefix,"/", dirlst_cur->fi_name,
1006 | 		    NULL))
1007 | 			return;
1008 | 	    } else {
1009 | 		if( (char *) NULL == stringer(buf, MOD_BUFSIZE,
1010 | 		    dirlst_cur->fi_prefix,"/", dirlst_cur->fi_name, NULL))
1011 | 			return;
1012 | 	    }
1013 | 
1014 | 	    ptr = buf;
1015 |         } else {
1016 | 	    if( path) {
1017 | 		if( (char *) NULL == stringer(buf, MOD_BUFSIZE,
1018 | 		    path,"/", dirlst_cur->fi_name, NULL))
1019 | 			return;
1020 | 		ptr = buf;
1021 | 
1022 | 	    } else
1023 | 		ptr = dirlst_cur->fi_name;
1024 |         }
1025 | 
1026 | 	/**
1027 | 	 **  Check whether this is part of the selected modules ...
1028 | 	 **/
1029 | 
1030 | 	if( !module || !strncmp( module, buf, mlen)) {
1031 | 
1032 | 	    /**
1033 | 	     **  Put this guy on the list
1034 | 	     **/
1035 | 
1036 | 	    if( NULL == (list[(*beginning)++] = strdup( ptr))) {
1037 | 		if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) {
1038 | 		    while( i--) 
1039 | 			null_free((void *) list + (--(*beginning)));
1040 | 		    return;		/** ------- EXIT (FAILURE) --------> **/
1041 | 		}
1042 | 	    }
1043 | 	}
1044 | 
1045 | 	/**
1046 | 	 **  recursively descend to subdirectories
1047 | 	 **/
1048 | 
1049 |         if( dirlst_cur->fi_subdir)
1050 |             dirlst_to_list( list, dirlst_cur->fi_subdir,
1051 | 		dirlst_cur->fi_listcount, beginning, path, module);
1052 |     } /** for **/
1053 | 
1054 | } /** end of 'dirlst_to_list' **/
1055 | 
1056 | /*++++
1057 |  ** ** Function-Header ***************************************************** **
1058 |  ** 									     **
1059 |  **   Function:		delete_dirlst					     **
1060 |  ** 									     **
1061 |  **   Description:	Delete an entire directory list including all sub-   **
1062 |  **			directory lists					     **
1063 |  ** 									     **
1064 |  **   First Edition:	1991/10/23					     **
1065 |  ** 									     **
1066 |  **   Parameters:	fi_ent	*dirlst_head	Head of the list to be re-   **
1067 |  **						moved			     **
1068 |  ** 									     **
1069 |  **   Result:		-						     **
1070 |  ** 									     **
1071 |  **   Attached Globals:	-						     **
1072 |  ** 									     **
1073 |  ** ************************************************************************ **
1074 |  ++++*/
1075 | 
1076 | void	delete_dirlst(	fi_ent	*dirlst_head,
1077 | 			int	 count)
1078 | {
1079 |     fi_ent	*dirlst_cur;
1080 |     int 	 i;
1081 | 
1082 | #if WITH_DEBUGGING_UTIL_2
1083 |     ErrorLogger( NO_ERR_START, LOC, _proc_delete_dirlst, NULL);
1084 | #endif
1085 | 
1086 |     if( !dirlst_head)
1087 | 	return;
1088 | 
1089 |     /**
1090 |      **  Free all filenames stored in the list
1091 |      **/
1092 | 
1093 |     for( i=0, dirlst_cur=dirlst_head;
1094 | 	 i<count && dirlst_cur;
1095 |          i++, dirlst_cur++) {
1096 | 
1097 |         null_free((void *) &(dirlst_cur->fi_name));
1098 | 
1099 | 	/**
1100 | 	 **  Recursivle decend to subdirectories
1101 | 	 **/
1102 | 
1103 |         if( dirlst_cur->fi_subdir) 
1104 |             delete_dirlst( dirlst_cur->fi_subdir, dirlst_cur->fi_listcount);
1105 |     } /** for **/
1106 | 
1107 |     /**
1108 |      **  Remove the entire list
1109 |      **/
1110 | 
1111 |     if( dirlst_head->fi_prefix)
1112 | 	null_free((void *) &(dirlst_head->fi_prefix));
1113 |     null_free((void *) &dirlst_head);
1114 | 
1115 | } /** End of 'delete_dirlst' **/
1116 | 
1117 | /*++++
1118 |  ** ** Function-Header ***************************************************** **
1119 |  ** 									     **
1120 |  **   Function:		store_files					     **
1121 |  ** 									     **
1122 |  **   Description:	Write a cache file using the given directory list    **
1123 |  ** 									     **
1124 |  **   First Edition:	1991/10/23					     **
1125 |  ** 									     **
1126 |  **   Parameters: 	fi_ent	*dirlist_head	List of files to be printed  **
1127 |  **			int	 count		Number of entries in the pas-**
1128 |  **						sed 'dirlist'		     **
1129 |  **			int	 tcount		Number of entries to write to**
1130 |  **						the cache file. This id the  **
1131 |  **						total number of files stores **
1132 |  **						in the nested directory lists**
1133 |  **			char	*dir		The current directory	     **
1134 |  **									     **
1135 |  **   Result:		-						     **
1136 |  ** 									     **
1137 |  **   Attached Globals:	-						     **
1138 |  ** 									     **
1139 |  ** ************************************************************************ **
1140 |  ++++*/
1141 | 
1142 | #ifdef CACHE_AVAIL
1143 | 
1144 | static	void	store_files(	fi_ent	*dirlst_head, 
1145 |             			int	 count,
1146 | 				int	 tcount,
1147 | 				char	*dir)
1148 | {
1149 |     FILE	*fi, *cdir;
1150 | 
1151 | #if WITH_DEBUGGING_UTIL_2
1152 |     ErrorLogger( NO_ERR_START, LOC, _proc_store_files, NULL);
1153 | #endif
1154 | 
1155 |     /**
1156 |      **  Open both, the cache info and the cache dir file
1157 |      **/
1158 | 
1159 |     /** CACHEINFO   **/
1160 |     if( (char *) NULL == stringer(namebuf, MOD_BUFSIZE,
1161 | 	dir, "/.moduleavailcache", NULL))
1162 |             return;
1163 |     if( NULL == (fi = fopen( namebuf, "w+")))
1164 | 	return;
1165 | 
1166 |     /** CACHEOUTPUT **/
1167 |     if( (char *) NULL == stringer(namebuf, MOD_BUFSIZE,
1168 | 	dir, "/.moduleavailcachedir", NULL))
1169 |             return;
1170 |     if( NULL == (cdir = fopen( namebuf, "w+"))) {
1171 | 	if( EOF == fclose( fi))
1172 | 	    ErrorLogger( ERR_CLOSE, LOC, NULL);
1173 | 	return;
1174 |     }
1175 | 
1176 |     /**
1177 |      **  Write the cache id
1178 |      **  Write the cache itsself
1179 |      **/
1180 | 
1181 |     fprintf( fi, "%s\n", CACHE_VERSION);
1182 |     fprintf( fi, "%d\n", tcount);
1183 |     store_dirlst( cdir, fi, dirlst_head, count, dir);
1184 | 
1185 |     /**
1186 |      **  Close the cache files again
1187 |      **/
1188 | 
1189 |     if( EOF == fclose( fi))
1190 | 	ErrorLogger( ERR_CLOSE, LOC, NULL);
1191 | 
1192 |     if( EOF == fclose( cdir))
1193 | 	ErrorLogger( ERR_CLOSE, LOC, namebuf, NULL);
1194 | 
1195 | } /** End of 'store_files' **/
1196 | 
1197 | /*++++
1198 |  ** ** Function-Header ***************************************************** **
1199 |  ** 									     **
1200 |  **   Function:		store_dirlst					     **
1201 |  ** 									     **
1202 |  **   Description:	Write the contents of a cache file		     **
1203 |  ** 									     **
1204 |  **   First Edition:	1991/10/23					     **
1205 |  ** 									     **
1206 |  **   Parameters:	FILE	*cacheoutput	Output stream to be used     **
1207 |  **			FILE	*cacheinfo	Cache log file to be written **
1208 |  **			fi_ent	*dirlist_head	List of files to be printed  **
1209 |  **			int	 count		Number of entries in the pas-**
1210 |  **						sed 'dirlist'		     **
1211 |  **   Result:		-						     **
1212 |  ** 									     **
1213 |  **   Attached Globals:	-						     **
1214 |  ** 									     **
1215 |  ** ************************************************************************ **
1216 |  ++++*/
1217 | 
1218 | static	void	store_dirlst(	FILE	*cacheinfo,
1219 | 				FILE	*cacheoutput,
1220 | 				fi_ent	*dirlst_head, 
1221 |              			int	 count,
1222 | 				char	*dir)
1223 | {
1224 |     fi_ent* dirlst_cur;
1225 |     int i;
1226 | 
1227 | #if WITH_DEBUGGING_UTIL_2
1228 |     ErrorLogger( NO_ERR_START, LOC, _proc_store_dirlst, NULL);
1229 | #endif
1230 | 
1231 |     for( i=0, dirlst_cur=dirlst_head;
1232 | 	 i<count && dirlst_cur;
1233 |          i++, dirlst_cur++) {
1234 | 
1235 | 	/**
1236 | 	 **  Flush the filename to the cache if it is a directory
1237 | 	 **  Only directories reside in the cache log ....
1238 | 	 **/
1239 | 
1240 |         if( dirlst_cur->fi_stats.st_mode & S_IFDIR) {
1241 |             if( dirlst_cur->fi_prefix) {
1242 |                 fprintf( cacheinfo, "%s/%s/%s %d\n", dir, dirlst_cur->fi_prefix,
1243 |                          dirlst_cur->fi_name, (int)dirlst_cur->fi_stats.st_mtime);
1244 |             } else {
1245 |                 fprintf( cacheinfo, "%s/%s %d\n", dir, dirlst_cur->fi_name, 
1246 |                          (int)dirlst_cur->fi_stats.st_mtime);
1247 |             }
1248 |         }
1249 | 
1250 | 	/**
1251 | 	 **  Flush out the filename
1252 | 	 **/
1253 | 
1254 |         store_file( cacheoutput, dir, dirlst_cur);
1255 | 
1256 | 	/**
1257 | 	 **  Recursively descent into directories
1258 | 	 **/
1259 | 
1260 |         if( dirlst_cur->fi_subdir) 
1261 |             store_dirlst( cacheinfo, cacheoutput, dirlst_cur->fi_subdir, 
1262 |                           dirlst_cur->fi_listcount, dir);
1263 |     } /** for **/
1264 | 
1265 |     /**
1266 |      **  Free up everything that has been allocated for the directory
1267 |      **  list
1268 |      **/
1269 | 
1270 |     if( dirlst_head->fi_prefix)
1271 | 	null_free((void *) &(dirlst_head->fi_prefix));
1272 |     null_free((void *) &dirlst_head);
1273 | 
1274 | } /** End of 'store_dirlst' **/
1275 | 
1276 | /*++++
1277 |  ** ** Function-Header ***************************************************** **
1278 |  ** 									     **
1279 |  **   Function:		store_file					     **
1280 |  ** 									     **
1281 |  **   Description:	Store the name of the file passed as 'file entry' to **
1282 |  **			the specified output stream if it isn't a temp file  **
1283 |  ** 									     **
1284 |  **   First Edition:	1991/10/23					     **
1285 |  ** 									     **
1286 |  **   Parameters:	FILE	*cacheoutput	Output stream to be used     **
1287 |  **			char	*dir		The current directory	     **
1288 |  **			fi_ent	*file		According file		     **
1289 |  ** 									     **
1290 |  **   Result:		-						     **
1291 |  ** 									     **
1292 |  **   Attached Globals:	-						     **
1293 |  ** 									     **
1294 |  ** ************************************************************************ **
1295 |  ++++*/
1296 | 
1297 | static	void	store_file(	FILE	*cacheoutput,
1298 | 				char	*dir,
1299 | 				fi_ent	*file)
1300 | {
1301 |     int filelen;		/** Length of the filename		     **/
1302 | 
1303 | #if WITH_DEBUGGING_UTIL_2
1304 |     ErrorLogger( NO_ERR_START, LOC, _proc_store_file, NULL);
1305 | #endif
1306 | 
1307 |     /**
1308 |      **  Turn any weird characters into ? marks and calculate the length
1309 |      **  of the filename
1310 |      **/
1311 | 
1312 |     chk4spch( file->fi_name);
1313 |     filelen = strlen( file->fi_name);
1314 | 
1315 |     /**
1316 |      **  Don't print termporary files which are supposed to end on '~'
1317 |      **/
1318 | 
1319 |     if( file->fi_name[ filelen-1] != '~') {
1320 | 	fprintf( cacheoutput, "%s/", dir);
1321 | 	if( file->fi_prefix)
1322 | 	    fprintf( cacheoutput, "%s/", file->fi_prefix);
1323 | 	fprintf( cacheoutput, "%s\n", file->fi_name);
1324 |     }
1325 | 
1326 |     /**
1327 |      **  Finally free up the memory that has been used to store the filename
1328 |      **/
1329 | 
1330 |     null_free((void *) &(file->fi_name));
1331 | 
1332 | } /** End of 'store_file' **/
1333 | 
1334 | 
1335 | /*++++
1336 |  ** ** Function-Header ***************************************************** **
1337 |  ** 									     **
1338 |  **   Function:		create_cache_list				     **
1339 |  ** 									     **
1340 |  **   Description:	Read the passed cache-file and create a list of file-**
1341 |  **			names out of it					     **
1342 |  ** 									     **
1343 |  **   First Edition:	1991/10/23					     **
1344 |  ** 									     **
1345 |  **   Parameters:	FILE	*cacheinput	Opened cache file	     **
1346 |  **			int	*count		Buffer to save the number of **
1347 |  **						filename to		     **
1348 |  **			char	*module		A module pattern ...	     **
1349 |  ** 									     **
1350 |  **   Result:		char**	NULL		Abort on failure	     **
1351 |  **				else		Pointer to the just created  **
1352 |  **						list			     **
1353 |  **			*count			Number of elements in the    **
1354 |  **						list			     **
1355 |  ** 									     **
1356 |  **   Attached Globals:	-						     **
1357 |  ** 									     **
1358 |  ** ************************************************************************ **
1359 |  ++++*/
1360 | 
1361 | static	char	**create_cache_list(	FILE	*cacheinput,
1362 | 					int	*count,
1363 | 					char	*module)
1364 | {
1365 |     char	**list;		/** Resulting list 			     **/
1366 |     int      	  i;		/** Loop counter			     **/
1367 |     int		  mlen;
1368 | 
1369 | #if WITH_DEBUGGING_UTIL_2
1370 |     ErrorLogger( NO_ERR_START, LOC, _proc_create_cache_list, NULL);
1371 | #endif
1372 | 
1373 |     /**
1374 |      **  Check the version of the passed cache file at first
1375 |      **/
1376 | 
1377 |     if( 1 != fscanf( cacheinput, "%s", buf)) 
1378 | 	if( OK != ErrorLogger( ERR_READ, LOC, "cache", NULL))
1379 | 	    return( NULL);      /** ----------- EXIT (I/O error) ----------> **/
1380 | 
1381 |     if( strcmp( buf, CACHE_VERSION)) 
1382 | 	if( OK != ErrorLogger( ERR_CACHE_INVAL, LOC, buf, NULL))
1383 | 	    return( NULL);	/** -- EXIT (invalid cache file version) --> **/
1384 |     
1385 |     /**
1386 |      **  Read the number of entries in the cache file and allocate enough
1387 |      **  memory for the resulting list.
1388 |      **/
1389 | 
1390 |     if( 1 != fscanf( cacheinput, "%d", count)) 
1391 |         if( OK != ErrorLogger( ERR_READ, LOC, "cache", NULL))
1392 | 	    return( NULL);	/** ----------- EXIT (I/O error) ----------> **/
1393 | 
1394 |     if( NULL == (list = (char**) malloc( *count * sizeof(char**)))) 
1395 |         if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
1396 | 	    return( NULL);	/** ------------ EXIT (FAILURE) -----------> **/
1397 | 
1398 |     /**
1399 |      **  zero the cache
1400 |      **/
1401 | 	(void) memset((void *) list, 0, *count * sizeof(char**));
1402 | 
1403 |     /**
1404 |      **  Some selection given?
1405 |      **/
1406 | 
1407 |     if( module)
1408 | 	mlen = strlen( module);
1409 | 
1410 |     /**
1411 |      **  Now read the cache ...
1412 |      **/
1413 | 
1414 | #if WITH_DEBUGGING_UTIL_2
1415 |     ErrorLogger( NO_ERR_DEBUG, LOC, "Read the cache", NULL);
1416 | #endif
1417 | 
1418 |     for( i=0; i<*count; i++) {
1419 | 	if( 1 != fscanf( cacheinput, "%s", buf)) {
1420 | 	    if( OK != ErrorLogger( ERR_READ, LOC, "cache", NULL)) {
1421 | 		while( --i)
1422 | 		    null_free((void *) list + i);
1423 | 		null_free((void *) &list);
1424 | 		return( NULL);	/** ----------- EXIT (I/O error) ----------> **/
1425 | 	    }
1426 | 	}
1427 | 
1428 | 	/**
1429 | 	 **  Check whether this is part of the selected modules ...
1430 | 	 **/
1431 | 
1432 | 	if( module && strncmp( module, buf, mlen)) {
1433 | 	    --i; --*count;
1434 | 	    continue;
1435 | 	}
1436 | 
1437 | 	/**
1438 | 	 **  Save this guy
1439 | 	 **/
1440 | 
1441 |         if( NULL == (list[ i] = strdup( buf))) {
1442 | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) {
1443 | 		while( --i)
1444 | 		    null_free((void *) list + i);
1445 | 		return( NULL);  /** ------------ EXIT (FAILURE) -----------> **/
1446 | 	    }
1447 | 	}
1448 |     }
1449 | 
1450 |     /**
1451 |      **  Success. Return the list created before
1452 |      **/
1453 | 
1454 |     return( list);
1455 | 
1456 | } /** End of 'create_cache_list' **/
1457 | 
1458 | #endif  /** CACHE_AVAIL **/
1459 | 
1460 | /*++++
1461 |  ** ** Function-Header ***************************************************** **
1462 |  ** 									     **
1463 |  **   Function:		delete_cache_list				     **
1464 |  ** 									     **
1465 |  **   Description:	Remove an entire list of allocated strings and free  **
1466 |  **			up the used memory				     **
1467 |  ** 									     **
1468 |  **   First Edition:	1991/10/23					     **
1469 |  ** 									     **
1470 |  **   Parameters:	char	**list		List of filenames to be print**
1471 |  **			int	  tcount	Size ofd the list in elements**
1472 |  ** 									     **
1473 |  **   Result:		-						     **
1474 |  ** 									     **
1475 |  **   Attached Globals:	-						     **
1476 |  ** 									     **
1477 |  ** ************************************************************************ **
1478 |  ++++*/
1479 | 
1480 | void delete_cache_list(	char	**list,
1481 | 			    int	  tcount)
1482 | {
1483 |     int i;
1484 | 
1485 | #if WITH_DEBUGGING_UTIL_2
1486 |     ErrorLogger( NO_ERR_START, LOC, _proc_delete_cache_list, NULL);
1487 | #endif
1488 | 
1489 |     for( i=0; i<tcount; i++)
1490 |         null_free((void *) (list + i));
1491 |     
1492 |     null_free((void *)&list);
1493 | 
1494 | } /** End of 'delete_cache_list' **/
1495 | 
1496 | /*++++
1497 |  ** ** Function-Header ***************************************************** **
1498 |  ** 									     **
1499 |  **   Function:		print_aligned_files				     **
1500 |  ** 									     **
1501 |  **   Description:	Print out the filenames passed in a sorted array     **
1502 |  **			column by column taking care of the order being re-  **
1503 |  **			flected to the single columns			     **
1504 |  ** 									     **
1505 |  **   First Edition:	1991/10/23					     **
1506 |  ** 									     **
1507 |  **   Parameters:	char	**list		List of filenames to print   **
1508 |  **			char	 *path		common path		     **
1509 |  **			char	 *header	List header		     **
1510 |  **			int	  tcount	Size of the list in elements **
1511 |  **			int	  numbered	Controls printing of numbers **
1512 |  ** 						set to -1 for none	     **
1513 |  ** 									     **
1514 |  **   Result:		-						     **
1515 |  ** 									     **
1516 |  **   Attached Globals:	g_current_module	The module which is handled  **
1517 |  **						by the current command	     **
1518 |  ** 									     **
1519 |  ** ************************************************************************ **
1520 |  ++++*/
1521 | 
1522 | void print_aligned_files(	Tcl_Interp	 *interp,
1523 | 				char		 *path,
1524 | 				char		 *header,
1525 | 				char		**list,
1526 | 				int		  tcount,
1527 | 				int		  numbered)
1528 | {
1529 |     struct stat	 stats;
1530 |     struct tm	*tm;
1531 |     char 	*symbols, *module, *release;
1532 |     char	 buffer[ 20];
1533 |     char	 modulefile[ MOD_BUFSIZE];
1534 |     char	 modulename[ MOD_BUFSIZE];
1535 |     char	*timestr;
1536 |     char	*s;
1537 |     int		 t;
1538 |     int		 terminal_width = 80;
1539 |     int 	 maxlen = 0;
1540 |     char	*modpath = NULL;
1541 | 
1542 | #if WITH_DEBUGGING_UTIL_1
1543 |     ErrorLogger( NO_ERR_START, LOC, _proc_print_aligned_files, NULL);
1544 | #endif
1545 | 
1546 |     /**
1547 |      **  In case of terse, human output we need to obtain the size of 
1548 |      **  the tty
1549 |      **/ 
1550 | 
1551 |     if( sw_format & (SW_HUMAN | SW_LONG) ) {
1552 | 	struct winsize window_size;
1553 | 	int fd_err = fileno( stderr);
1554 | 
1555 | 	if( isatty( fd_err))
1556 | 	    if( ioctl( fd_err, TIOCGWINSZ, &window_size) != -1)
1557 | 		terminal_width = (window_size.ws_col == 0) ?
1558 | 		    80 : window_size.ws_col;
1559 |     }
1560 | 
1561 |     if (! path) {
1562 | 	modpath = (char *) xgetenv( "MODULEPATH");
1563 | 	if (! modpath) {
1564 | 	    if( OK != ErrorLogger( ERR_MODULE_PATH, LOC, NULL)) {
1565 | 		return;
1566 | 	    }
1567 | 	}
1568 |     }
1569 | 
1570 |     /**
1571 |      **  Scan all entries of the passed list
1572 |      **/
1573 | 
1574 |     _init_file_list();
1575 |     while( list && tcount-- && *list) {
1576 | 	/**
1577 | 	 ** find module[/version] in filename
1578 | 	 **/
1579 | 	if( g_current_module = s = strrchr( *list, '/')) {
1580 | 		*s = 0;
1581 | 		g_current_module++;
1582 | 		if (TCL_ERROR == Locate_ModuleFile(interp, g_current_module,
1583 | 			modulename, modulefile)) {
1584 | 			g_current_module = strrchr(*list, '/');
1585 | 			g_current_module++;
1586 | 		}
1587 | 		*s = '/';
1588 | 	}
1589 | 	if( !stat( *list, &stats)) {
1590 | 
1591 | 	    /**
1592 | 	     **  If the file is a directory, try to source the .modulerc
1593 | 	     **  file and skip to the next file
1594 | 	     **/
1595 | 
1596 | 	    if( S_ISDIR( stats.st_mode)) {
1597 | 		SourceRC( interp, *list, modulerc_file);
1598 | 		SourceVers( interp, *list, g_current_module);
1599 | 		g_current_module = (char *) NULL;
1600 | 		list++;
1601 | 		continue;
1602 | 	    }
1603 | 
1604 | 	    /**
1605 | 	     **  get a copy of the current item to print in order not to
1606 | 	     **  change the function input
1607 | 	     **/
1608 | 
1609 | 	    if(path == (char *)NULL) {
1610 | 		int maxPrefixLength = 0;
1611 | 
1612 | 		if (modpath) {
1613 | 		    /**
1614 | 		     ** try to find the longest prefix from the module path
1615 | 		     ** Huge hack!
1616 | 		     **/
1617 | 
1618 | 		    int prefixLength;
1619 | 		    char *colon;
1620 | 		    char *prefix = modpath;
1621 | 
1622 | 		    while (prefix != (char *) NULL && *prefix != '\0') {
1623 | 			colon = strchr(prefix, ':');
1624 | 			prefixLength = colon == NULL ? strlen(prefix) :
1625 | 						       colon - prefix;
1626 | 			while (prefix[prefixLength - 1] == '/') {
1627 | 			    prefixLength -= 1;
1628 | 			}
1629 | 			if (prefixLength > maxPrefixLength &&
1630 | 			    ! strncmp(*list, prefix, prefixLength) &&
1631 | 			    (*list)[prefixLength] == '/')
1632 | 			{
1633 | 			    maxPrefixLength = prefixLength;
1634 | 			}
1635 | 
1636 | 			if (colon != NULL) {
1637 | 			    colon += 1;
1638 | 			}
1639 | 		        prefix = colon;
1640 | 		    }
1641 | 
1642 | 		    /**
1643 | 		     ** Skip over '/'
1644 | 		     **/
1645 | 		    if (maxPrefixLength > 0) {
1646 | 			maxPrefixLength += 1;
1647 | 		    }
1648 | 		}
1649 | 
1650 | 		module = strdup(*list + maxPrefixLength);
1651 | 	    } else {
1652 | 		t = strlen(path);
1653 | 		if (*(*list + t) == '/') t++;
1654 | 		module = strdup(*list + t);
1655 | 	    }
1656 | 	    if((char *) NULL == module) {
1657 | 		if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
1658 | 		    break;
1659 | 		else
1660 | 		    continue;
1661 | 	    }
1662 | 
1663 | 	    /**
1664 | 	     **  Expand the symbols and get the version of the module
1665 | 	     **/
1666 | 
1667 | 	    if((char *) NULL == (symbols = ExpandVersions( module)))
1668 | 		symbols = "";
1669 | 
1670 | 	    if((sw_format & SW_LONG)
1671 | 		|| (char *) NULL == (release = strchr( module, '/')))
1672 | 		release = "";		/* no release info */
1673 | 	    else
1674 | 		*release++ = '\0';
1675 | 
1676 | 	    /**
1677 | 	     **  Long or short format
1678 | 	     **/
1679 | 
1680 | 	    if(sw_format & (SW_TERSE|SW_PARSE|SW_HUMAN)) {/** short format **/
1681 | 		int tmp_len;
1682 | 
1683 | 		if( sw_format & SW_PARSE ) {
1684 | 			sprintf( _file_list_buffer, short_format_full,
1685 | 				module, release, symbols);
1686 | 		} else {	/* assume a human readable format */
1687 | 			if (*symbols) {
1688 | 				sprintf( _file_list_buffer, short_format_full,
1689 | 					module, release, symbols);
1690 | 			} else {
1691 | 				if (*release) {
1692 | 					sprintf( _file_list_buffer,
1693 | 						short_format_part,
1694 | 						module, release);
1695 | 				} else {
1696 | 					sprintf( _file_list_buffer,
1697 | 						short_format, module);
1698 | 				}
1699 | 			}
1700 | 		}
1701 | 		_add_file_list( _file_list_buffer);
1702 | 	
1703 | 		tmp_len = strlen( _file_list_buffer);
1704 | 		if( tmp_len > maxlen) 
1705 | 		    maxlen = tmp_len;
1706 | 
1707 | 	    } else if ( sw_format & SW_LONG) {		/** long format **/
1708 | 
1709 | 		/**
1710 | 		 **  Get the time of last modification
1711 | 		 **/
1712 | 
1713 | 		if((struct tm *) NULL != (tm = gmtime( &stats.st_mtime))) {
1714 | 		    sprintf( buffer, "%04d/%02d/%02d %2d:%02d:%02d",
1715 | 			1900+tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
1716 | 			tm->tm_hour, tm->tm_min, tm->tm_sec);
1717 | 		    timestr = buffer;
1718 | 
1719 | 		} else
1720 | 		    timestr = "";
1721 | 
1722 | 		/**
1723 | 		 **  Now print and free what we've allocated
1724 | 		 **/
1725 | 
1726 | 		fprintf( stderr, long_format, module, symbols,
1727 | 		    timestr);
1728 | 
1729 | 	    }
1730 | 
1731 | 	    null_free((void *) &module);
1732 | 
1733 | 	} /** if( !stat) **/
1734 | 
1735 | 	list++;
1736 | 
1737 |     } /** while **/
1738 | 
1739 |     /**
1740 |      **  In case of terse output we have to flush our buffer
1741 |      **/
1742 | 
1743 |     if( !(sw_format & SW_LONG) ) {
1744 | 	if( _file_list_wr_ndx > 0) 
1745 | 	    print_terse_files( terminal_width, maxlen, header, numbered);
1746 |     }
1747 | 
1748 |     if (! modpath) {
1749 | 	null_free((void *)&modpath);
1750 |     }
1751 | 
1752 | #if WITH_DEBUGGING_UTIL_1
1753 |     ErrorLogger( NO_ERR_END, LOC, _proc_print_aligned_files, NULL);
1754 | #endif
1755 | 
1756 | } /** End of 'print_aligned_files' **/
1757 | 
1758 | /*++++
1759 |  ** ** Function-Header ***************************************************** **
1760 |  ** 									     **
1761 |  **   Function:		print_terse_files				     **
1762 |  ** 									     **
1763 |  **   Description:	Print out the filenames in the _file_list array in   **
1764 |  **			case of terse output 				     **
1765 |  ** 									     **
1766 |  **   First Edition:	1991/10/23					     **
1767 |  ** 									     **
1768 |  **   Parameters:	int	  terminal_width	Terminal size	     **
1769 |  **			int	  len			max. filename length **
1770 |  **			char	 *header		header to print	     **
1771 |  **			int	  number		value to start number**
1772 |  ** 							use -1 for none	     **
1773 |  ** 									     **
1774 |  **   Result:		-						     **
1775 |  ** 									     **
1776 |  **   Attached Globals:	-						     **
1777 |  ** 									     **
1778 |  ** ************************************************************************ **
1779 |  ++++*/
1780 | 
1781 | static	void	print_terse_files(  int terminal_width,
1782 | 				    int len,
1783 | 				    char *header,
1784 | 				    int numbered)
1785 | {
1786 |     char	*module;
1787 |     char	*moduleright;
1788 | 
1789 |     /**
1790 |      **  Print human readable lists
1791 |      **/
1792 | 
1793 |     len += (numbered != -1 ? 6 : 1);
1794 |     if( sw_format & SW_HUMAN ) {
1795 | 	int columns = (terminal_width - 1) / len;
1796 | 	int col_ndx, row_ndx;
1797 | 	int rows;
1798 |         int mod_ndx;
1799 |         
1800 | 	/**
1801 | 	 **  Print the header line
1802 | 	 **/
1803 | 
1804 | 	if( header) {
1805 | 	    int lin_len = terminal_width - strlen( header) - 2;
1806 | 	    int i;
1807 | 
1808 | 	    fprintf( stderr, "\n");
1809 | 
1810 | 	    if( lin_len >= 2) 
1811 | 		for( i = 0; i < lin_len / 2; i++)
1812 | 		    fprintf( stderr, "-");
1813 | 
1814 | 	    fprintf( stderr, " %s ", header);
1815 | 
1816 | 	    if( lin_len >= 2)
1817 | 		for( i = 0; i < (lin_len+1) / 2; i++)
1818 | 		    fprintf( stderr, "-");
1819 | 
1820 | 	    fprintf( stderr, "\n");
1821 | 	}
1822 | 
1823 | 	/**
1824 | 	 **  Print the columns
1825 | 	 **/
1826 | 
1827 |         
1828 | 	if( !columns)
1829 | 	    columns = 1;
1830 | 	rows = (_file_list_wr_ndx + columns - 1) / columns;
1831 | 
1832 |         for( row_ndx = 0; row_ndx < rows; row_ndx++) {
1833 |           for( col_ndx = 0; col_ndx < columns; col_ndx++) { 
1834 |             
1835 |             mod_ndx = row_ndx + col_ndx * rows;
1836 |             
1837 |             if( module = _pick_file_list( mod_ndx)) {
1838 |               moduleright = _pick_file_list( row_ndx + (col_ndx+1)* rows);
1839 | 
1840 |               print_spaced_file( module, len,
1841 |                                  ( (col_ndx == columns - 1)
1842 |                                    || (moduleright == (char *) NULL)
1843 |                                    ? 0 : 1 ),
1844 |                                   ( (numbered == -1) ? numbered : ++mod_ndx) );
1845 | 		}
1846 | 	    }
1847 | 	    fprintf( stderr, "\n");
1848 | 	}
1849 |     }
1850 | 
1851 |     /**
1852 |      **  Print parseable lists
1853 |      **/
1854 | 
1855 |     else {
1856 | 	while( module = _get_file_list()) {
1857 | 	    fprintf( stderr, "%s\n", module);
1858 | 	}
1859 |     }
1860 | }
1861 | 
1862 | /*++++
1863 |  ** ** Function-Header ***************************************************** **
1864 |  ** 									     **
1865 |  **   Function:		_add_file_list   				     **
1866 |  **			_init_file_list					     **
1867 |  **			_get_file_list					     **
1868 |  **			_pick_file_list					     **
1869 |  ** 									     **
1870 |  **   Description:	File list functions for terse module display mode    **
1871 |  ** 									     **
1872 |  **   First Edition:	1991/10/23					     **
1873 |  ** 									     **
1874 |  **   Parameters:	char	*name		Name to be stored	     **
1875 |  ** 									     **
1876 |  **   Result:		-						     **
1877 |  ** 									     **
1878 |  **   Attached Globals:	-						     **
1879 |  ** 									     **
1880 |  ** ************************************************************************ **
1881 |  ++++*/
1882 | 
1883 | static	void _init_file_list()
1884 | {
1885 |     if( _file_list_ptr && !_file_list_cnt) {
1886 | 	null_free((void *) &_file_list_ptr);
1887 | 	_file_list_cnt = 0;
1888 |     }
1889 | 
1890 |     _file_list_wr_ndx = 0;
1891 |     _file_list_rd_ndx = 0;
1892 | }
1893 | 
1894 | static	void _add_file_list( char *name)
1895 | {
1896 |     /**
1897 |      **  Parameter check
1898 |      **/
1899 | 
1900 |     if( !name || !*name)
1901 | 	return;
1902 | 
1903 |     /**
1904 |      **  Reallocate if the current array is to small
1905 |      **/
1906 | 
1907 |     if( _file_list_cnt <= _file_list_wr_ndx) {
1908 | 	_file_list_cnt += FILE_LIST_SEGM_SIZE;
1909 | 
1910 | 	if( !_file_list_ptr) 
1911 | 	    _file_list_ptr = (char **) malloc(_file_list_cnt * sizeof(char *));
1912 | 	else
1913 | 	    _file_list_ptr = (char **) realloc( _file_list_ptr,
1914 | 		_file_list_cnt * sizeof(char *));
1915 | 
1916 |     }
1917 | 
1918 |     /**
1919 |      **  Save the passed name, if the allocation succeeded
1920 |      **/
1921 | 
1922 |     if( !_file_list_ptr) {
1923 | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
1924 | 	_file_list_cnt = 0;
1925 | 	_file_list_wr_ndx = 0;
1926 | 	_file_list_rd_ndx = 0;
1927 | 
1928 |     } else {
1929 | 	_file_list_ptr[ _file_list_wr_ndx++] = strdup( name);
1930 |     }
1931 | }
1932 | 
1933 | static	char *_get_file_list()
1934 | {
1935 |     return((_file_list_rd_ndx < _file_list_wr_ndx) ?
1936 | 	 _file_list_ptr[ _file_list_rd_ndx++] : (char *) NULL);
1937 | }
1938 | 
1939 | static	char *_pick_file_list( int ndx)
1940 | {
1941 |     return((ndx < _file_list_wr_ndx) ? _file_list_ptr[ ndx] : (char *) NULL);
1942 | }
1943 | 
1944 | /*++++
1945 |  ** ** Function-Header ***************************************************** **
1946 |  ** 									     **
1947 |  **   Function:		print_spaced_file				     **
1948 |  ** 									     **
1949 |  **   Description:	Print out the passed filename and fill the output    **
1950 |  **			area up to the passed number of characters	     **
1951 |  ** 									     **
1952 |  **   First Edition:	1991/10/23					     **
1953 |  ** 									     **
1954 |  **   Parameters:	char	*name		Name to be printed	     **
1955 |  **			int	 maxwidth	With of the output field to  **
1956 |  **						be filled up		     **
1957 |  **			int	 space		Boolean value controlling if **
1958 |  **						the output area should be    **
1959 |  **						filled up with spaces or not **
1960 |  **			int	 number		value to start number list   **
1961 |  ** 						use -1 for none		     **
1962 |  ** 									     **
1963 |  **   Result:		-						     **
1964 |  ** 									     **
1965 |  **   Attached Globals:	-						     **
1966 |  ** 									     **
1967 |  ** ************************************************************************ **
1968 |  ++++*/
1969 | 
1970 | static	void print_spaced_file(	char	*name,
1971 | 				int	 maxwidth,
1972 | 				int	 space,
1973 | 				int	 number)
1974 | {
1975 |     int filelen;		/** Length of the filename to print	     **/
1976 | 
1977 | #if WITH_DEBUGGING_UTIL_2
1978 |     ErrorLogger( NO_ERR_START, LOC, _proc_print_spaced_file, NULL);
1979 | #endif
1980 | 
1981 |     chk4spch( name);		/** turn any weird characters into ? marks   **/
1982 | 
1983 |     /**
1984 |      **  Print the name and calculate its length
1985 |      **/
1986 | 
1987 |     filelen = strlen( name);
1988 |     if( -1 != number) {
1989 | 	fprintf( stderr, "%3d) ", number);
1990 | 	filelen += 5;
1991 |     }
1992 | 
1993 |     fprintf(stderr, "%s",  name);
1994 | 
1995 |     /**
1996 |      **  Conditionally fill the output area with spaces
1997 |      **/
1998 | 
1999 |     if( space) {
2000 | 	putc(' ', stderr);
2001 | 	while( ++filelen < maxwidth)
2002 | 	    putc(' ', stderr);
2003 |     }
2004 | 
2005 | } /** end of 'print_spaced_file' **/
2006 | 
2007 | /*++++
2008 |  ** ** Function-Header ***************************************************** **
2009 |  ** 									     **
2010 |  **   Function:		mkdirnm						     **
2011 |  ** 									     **
2012 |  **   Description:	Build a full pathname out of the passed directory    **
2013 |  **			and file					     **
2014 |  ** 									     **
2015 |  **   First Edition:	1991/10/23					     **
2016 |  ** 									     **
2017 |  **   Parameters:	char	*dir		The directory to be used     **
2018 |  **			char	*file		The filename w/o path	     **
2019 |  ** 									     **
2020 |  **   Result:		char*	NULL		Compound filename to long    **
2021 |  **				else		Pointer to the full path     **
2022 |  ** 									     **
2023 |  **   Attached Globals:	-						     **
2024 |  ** 									     **
2025 |  ** ************************************************************************ **
2026 |  ++++*/
2027 | 
2028 | static	char *mkdirnm(	char	*dir,
2029 | 			char	*file)
2030 | {
2031 |     static char  dirbuf[ MOD_BUFSIZE];	/** Buffer for path creation	     **/
2032 | 
2033 | #if WITH_DEBUGGING_UTIL_2
2034 |     ErrorLogger( NO_ERR_START, LOC, _proc_mkdirnm, ", dir='", dir, ", file='",
2035 | 	file, "'", NULL);
2036 | #endif
2037 | 
2038 |     /**
2039 |      **  If only a file is given, or the file is in the current directory
2040 |      **  return just the file.
2041 |      **/
2042 | 
2043 |     if( dir == NULL || *dir == '\0' || !strcmp(dir,"."))
2044 | 	return( strcpy( dirbuf, file));
2045 | 
2046 |     /**
2047 |      **  Check whether the full path fits into the buffer
2048 |      **/
2049 | 
2050 |     if( (int) ( strlen( dir) + 1 + strlen( file) + 1 ) > MOD_BUFSIZE) {
2051 | 	if( OK != ErrorLogger( ERR_NAMETOLONG, LOC, dir, file, NULL))
2052 | 	    return( NULL);
2053 |     }
2054 | 
2055 |     /**
2056 |      **  Copy directory and file into the buffer taking care that there will
2057 |      **  be no double slash ...
2058 |      **/
2059 | 
2060 |     strcpy( dirbuf, dir);
2061 |     if( dir[ strlen( dir) - 1] != '/' && file[0] != '/')
2062 | 	strcat( dirbuf, "/");
2063 |     return( strcat( dirbuf, file));
2064 | 
2065 | } /** End of 'mkdirnm' **/
2066 | 
2067 | /*++++
2068 |  ** ** Function-Header ***************************************************** **
2069 |  ** 									     **
2070 |  **   Function:		fi_ent_cmp					     **
2071 |  ** 									     **
2072 |  **   Description:	compares two file entry structures		     **
2073 |  **			Different cmdline arguments (i.e. -u, -c, -t, -z)    **
2074 |  **			will change what value is compared. As a default,    **
2075 |  **			the name is used.				     **
2076 |  **									     **
2077 |  **   Notes:		This procedure is used as comparison function for    **
2078 |  **			qsort()					 	     **
2079 |  ** 									     **
2080 |  **   First Edition:	1991/10/23					     **
2081 |  ** 									     **
2082 |  **   Parameters:	const void *fi1		First file entry	     **
2083 |  **			const void *fi2		Second one to compare	     **
2084 |  ** 									     **
2085 |  **   Result:		int	1 	fi2 > fi1			     **
2086 |  **    				-1	fi2 < fi1			     **
2087 |  **	  			0	fi2 == fi1			     **
2088 |  ** 									     **
2089 |  **   Attached Globals:							     **
2090 |  ** 									     **
2091 |  ** ************************************************************************ **
2092 |  ++++*/
2093 | 
2094 | static	int fi_ent_cmp(	const void	*fi1,
2095 | 			const void	*fi2)
2096 | {
2097 | 
2098 | #ifdef DEF_COLLATE_BY_NUMBER
2099 |   return colcomp( ((fi_ent*)fi1)->fi_name, ((fi_ent*)fi2)->fi_name);
2100 | #else
2101 |   return strcmp( ((fi_ent*)fi1)->fi_name, ((fi_ent*)fi2)->fi_name);
2102 | #endif
2103 | }