1    | /*****
2    |  ** ** Module Header ******************************************************* **
3    |  ** 									     **
4    |  **   Modules Revision 3.0						     **
5    |  **   Providing a flexible user environment				     **
6    |  ** 									     **
7    |  **   File:		cmdVersion.c					     **
8    |  **   First Edition:	95/12/28					     **
9    |  ** 									     **
10   |  **   Authors:	Jens Hamisch, jens@Strawberry.COM			     **
11   |  ** 									     **
12   |  **   Description:	The Tcl module-version routine which provides the    **
13   |  **			definition of symbolic version names and the module- **
14   |  **			alias command providing the definition of module and **
15   |  **			version aliases					     **
16   |  ** 									     **
17   |  **   Exports:		cmdModuleVersion				     **
18   |  **			cmdModuleAlias					     **
19   |  **			CleanupVersion					     **
20   |  **			AliasLookup					     **
21   |  **			ExpandVersions					     **
22   |  ** 									     **
23   |  **   Notes:	This module defines the callback functions for the defi-     **
24   |  **		nition of symbolic module names and module aliases. The      **
25   |  **		syntax of the according commands is defined as:		     **
26   |  ** 									     **
27   |  **	    Module-Versions:						     **
28   |  **		module-version <module>/<version> <name> [ <name> ... ]	     **
29   |  **		module-version /<version> <name> [ <name> ... ]		     **
30   |  **		module-version <module> <name> [ <name> ... ]		     **
31   |  **		module-version <alias> <name> [ <name> ... ]		     **
32   |  ** 									     **
33   |  **	    Module-Alias:						     **
34   |  **		module-alias <alias> <module>/<version>			     **
35   |  **		module-alias <alias> /<version>				     **
36   |  **		module-alias <alias> <module>				     **
37   |  **		module-alias <alias> <alias>				     **
38   |  ** 									     **
39   |  ** 									     **
40   |  ** ************************************************************************ **
41   |  ****/
42   | 
43   | /** ** Copyright *********************************************************** **
44   |  ** 									     **
45   |  ** Copyright 1991-1994 by John L. Furlan.                      	     **
46   |  ** see LICENSE.GPL, which must be provided, for details		     **
47   |  ** 									     ** 
48   |  ** ************************************************************************ **/
49   | 
50   | static char Id[] = "@(#)$Id: cmdVersion.c.src.html,v 1.2 2005/11/25 20:09:37 rkowen Exp $";
51   | static void *UseId[] = { &UseId, Id };
52   | 
53   | /** ************************************************************************ **/
54   | /** 				      HEADERS				     **/
55   | /** ************************************************************************ **/
56   | 
57   | #include "modules_def.h"
58   | 
59   | /** ************************************************************************ **/
60   | /** 				  LOCAL DATATYPES			     **/
61   | /** ************************************************************************ **/
62   | 
63   | /** ************************************************************************ **/
64   | /**									     **/
65   | /**   The whole thing is handled in memory. The structure is build of module **/
66   | /**   and name records. There are 3 types of name records: version, name     **/
67   | /**   and alias. 							     **/
68   | /**									     **/
69   | /**         |                                                    |	     **/
70   | /**     +---+---+<-------------------------------+           +---+---+	     **/
71   | /**     | module| ------------------------+      |           | alias |	     **/
72   | /**     +---+---+ --------+               |      |           +-------+	     **/
73   | /**         |   ^    +----+----+          |      |               |	     **/
74   | /**         |   +--- | version |       +--+--+   |           +---+---+	     **/
75   | /**         |   |    +----+----+       | name|---+     <-----| alias |	     **/
76   | /**         |   |         |            +--+--+   |           +---+---+	     **/
77   | /**         |   |    +----+----+          |      |               |	     **/
78   | /**         |   +--- | version |------>+--+--+   |           +---+---+	     **/
79   | /**         |   |    +----+----+<-+--- | name|---+           | alias |	     **/
80   | /**         |   |         |       | +- +--+--+   |           +---+---+	     **/
81   | /**         |   |    +----+----+  | |     |      |               |	     **/
82   | /**         |   +--- | version |  | |  +--+--+   |           +---+---+	     **/
83   | /**         |   |    +----+----+  | |  | name|---+     <-----| alias |	     **/
84   | /**         |   |         |       | |  +--+--+   |           +---+---+	     **/
85   | /**         |                     | |     |      |               |	     **/
86   | /**         |                     | +->+--+--+   |           +---+---+	     **/
87   | /**     +---+---+                 +--- | name|---+           | alias |	     **/
88   | /**     | module|                      +--+--+   |           +---+---+	     **/
89   | /**     +---+---+                         |      |               |	     **/
90   | /**         |								     **/
91   | /**			       alphabetic ordered     alphabtic ordered	     **/
92   | /**			    list of names depending    list of aliases	     **/
93   | /**			    to a single module file			     **/
94   | /**									     **/
95   | /**   Each module name points to a list of symbolic names and versions.	     **/
96   | /**   The versions themselfes can be symbolic names and therefore are of the **/
97   | /**   same record type as the names.					     **/
98   | /**   The name and the version list is alphabetically sorted (even the       **/
99   | /**   module list is). A version record points to a related name record	     **/
100  | /**   containing a symbolic name for the version. Starting at this record,   **/
101  | /**   the name records built a queue of symbolic names for the version.	     **/
102  | /**   Both, the version and the name record do have a backward pointer to    **/
103  | /**   the module record.						     **/
104  | /**									     **/
105  | /**   The alias list builds a alphabetic ordered list of defined aliases.    **/
106  | /**   Each alias record points to the related name record.		     **/
107  | /**									     **/
108  | /** ************************************************************************ **/
109  | 
110  | typedef	struct	_mod_module	{
111  |     struct _mod_module	*next;		/** alphabetic queue		     **/
112  |     struct _mod_name	*version;	/** version queue   		     **/
113  |     struct _mod_name	*name;		/** name queue      		     **/
114  |     char		*module;	/** the name itsself		     **/
115  | } ModModule;
116  | 
117  | typedef	struct	_mod_name	{
118  |     struct _mod_name	*next;		/** alphabetic queue		     **/
119  |     struct _mod_name	*ptr;		/** logical next    		     **/
120  |     struct _mod_name	*version;	/** backwards version pointer	     **/
121  |     struct _mod_module	*module;	/** related module  		     **/
122  |     char		*name;		/** the name itsself		     **/
123  | } ModName;
124  | 
125  | /** ************************************************************************ **/
126  | /** 				     CONSTANTS				     **/
127  | /** ************************************************************************ **/
128  | 
129  | #define	HISTTAB	100
130  | 
131  | /** ************************************************************************ **/
132  | /**				      MACROS				     **/
133  | /** ************************************************************************ **/
134  | 
135  | /** not applicable **/
136  | 
137  | /** ************************************************************************ **/
138  | /** 				    LOCAL DATA				     **/
139  | /** ************************************************************************ **/
140  | 
141  | static	char	module_name[] = "cmdVersion.c";	/** File name of this module **/
142  | #if WITH_DEBUGGING_CALLBACK
143  | static	char	_proc_cmdModuleVersion[] = "cmdModuleVersion";
144  | static	char	_proc_cmdModuleAlias[] = "cmdModuleAlias";
145  | #endif
146  | #if WITH_DEBUGGING_UTIL_2
147  | static	char	_proc_CleanupVersion[] = "CleanupVersion";
148  | #endif
149  | #if WITH_DEBUGGING_UTIL_1
150  | static	char	_proc_AddModule[] = "AddModule";
151  | static	char	_proc_FindModule[] = "FindModule";
152  | static	char	_proc_AddName[] = "AddName";
153  | static	char	_proc_FindName[] = "FindName";
154  | #endif
155  | 
156  | /**
157  |  **  The module and aliases list
158  |  **/
159  | 
160  | static	ModModule	*modlist = (ModModule *) NULL;
161  | static	ModName		*aliaslist = (ModName *) NULL;
162  | 
163  | /** ************************************************************************ **/
164  | /**				    PROTOTYPES				     **/
165  | /** ************************************************************************ **/
166  | 
167  | static	void		 CleanupVersionSub(	ModModule	 *ptr);
168  | 
169  | static	void		 CleanupName(		ModName		 *ptr);
170  | 
171  | static	ModModule	*AddModule(		char		 *name);
172  | 
173  | static	ModModule	*FindModule(		char		 *name,
174  | 						ModModule	**prev);
175  | 
176  | static	ModName		*AddName(		char		 *name,
177  | 						ModName		**start,
178  | 						ModModule	 *module);
179  | 
180  | static	ModName		*FindName(		char		 *name,
181  | 						ModName		 *start,
182  | 						ModName		**prev);
183  | 
184  | static	char		*CheckModuleVersion(	char 		 *name);
185  | 
186  | static	char		*scan_versions(		char 		 *buffer,
187  | 						char		 *base,
188  | 						ModName 	 *ptr,
189  | 						ModModule 	 *modptr);
190  | 
191  | /*++++
192  |  ** ** Function-Header ***************************************************** **
193  |  ** 									     **
194  |  **   Function:		cmdModuleVersion				     **
195  |  ** 									     **
196  |  **   Description:	Callback function for 'version'			     **
197  |  ** 									     **
198  |  **   First Edition:	95/12/28					     **
199  |  ** 									     **
200  |  **   Parameters:	ClientData	 client_data			     **
201  |  **			Tcl_Interp	*interp		According Tcl interp.**
202  |  **			int		 argc		Number of arguments  **
203  |  **			char		*argv[]		Argument array	     **
204  |  ** 									     **
205  |  **   Result:		int	TCL_OK		Successfull completion	     **
206  |  **				TCL_ERROR	Any error		     **
207  |  ** 									     **
208  |  **   Attached Globals:	modlist		List containing all version names    **
209  |  **   			g_flags		These are set up accordingly before  **
210  |  **					this function is called in order to  **
211  |  **					control everything		     **
212  |  ** 									     **
213  |  ** ************************************************************************ **
214  |  ++++*/
215  | 
216  | int	cmdModuleVersion(	ClientData	 client_data,
217  | 	      			Tcl_Interp	*interp,
218  | 	      			int		 argc,
219  | 	      			char		*argv[])
220  | {
221  |     char	*version, *module;
222  |     ModModule	*modptr;
223  |     ModName	*versptr, *nameptr, *tmp, *ptr;
224  |     int 	 i;
225  | 
226  | #if WITH_DEBUGGING_CALLBACK
227  |     ErrorLogger( NO_ERR_START, LOC, _proc_cmdModuleVersion, NULL);
228  | #endif
229  | 
230  |     /**
231  |      **  Whatis mode?
232  |      **/
233  | 
234  |     if( g_flags & M_WHATIS) 
235  |         return( TCL_OK);		/** ------- EXIT PROCEDURE -------> **/
236  | 	
237  |     /**
238  |      **  Parameter check
239  |      **/
240  | 
241  |     if( argc < 3) {
242  | 	if( OK != ErrorLogger( ERR_USAGE, LOC, argv[0], " modulename ",
243  | 	    " symbolic-version [symbolic-version ...] ", NULL))
244  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
245  |     }
246  | 
247  |     if((char *) NULL == (module = CheckModuleVersion( argv[1]))) {
248  | 	ErrorLogger( ERR_BADMODNAM, LOC, argv[1], NULL);
249  | 	return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
250  |     }
251  | 
252  |     /**
253  |      **  Display mode?
254  |      **/
255  | 
256  |     if( g_flags & M_DISPLAY) {
257  | 	fprintf( stderr, "%s\t ", argv[ 0]);
258  | 	for( i=1; i<argc; i++)
259  | 	    fprintf( stderr, "%s ", argv[ i]);
260  | 	fprintf( stderr, "\n");
261  |     }
262  | 
263  |     /**
264  |      **  get the version from the argument
265  |      **/
266  | 
267  |     if((char *) NULL == (version = strrchr( module, '/'))) {
268  | 	if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL))
269  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
270  |     }
271  |     *version++ = '\0';
272  | 
273  |     /**
274  |      **  Now we have a module and a version.
275  |      **  Check wheter it exists (cond. create them). Check both, the version
276  |      **  and the name queue in order to locate the desired version ...
277  |      **/
278  | 
279  |     if((ModModule *) NULL == (modptr = AddModule( module))) {
280  | 	ErrorLogger( ERR_BADMODNAM, LOC, argv[1], NULL);
281  | 	return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
282  |     }
283  | 
284  |     if((ModName *) NULL == (ptr = FindName( version, modptr->version, &tmp))) {
285  | 	if((ModName *) NULL == (ptr = FindName( version, modptr->name, &tmp))) 
286  | 	    versptr = AddName( version, &modptr->version, modptr);
287  | 	else
288  | 	    versptr = ptr->version;
289  |     } else
290  | 	versptr = ptr;
291  | 
292  |     /**
293  |      **  Check all symbolic names now and allocate a name record for them
294  |      **/
295  |     
296  |     for( i=2; i<argc; i++) {
297  | 
298  | 	if( FindName( argv[ i], modptr->name, &tmp)) {
299  | 	    if( OK != ErrorLogger( ERR_DUP_SYMVERS, LOC, argv[ i], NULL))
300  | 		break;
301  | 	    else
302  | 		continue;
303  | 	}
304  | 
305  | 	if((ModName *) NULL == (nameptr = AddName( argv[ i], &modptr->name,
306  | 	    modptr))) {
307  | 	    if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL))
308  | 		break;
309  | 	    else
310  | 		continue;
311  | 	}
312  | 
313  | 	/**
314  | 	 **  Concat the new element at the beginning of the name queue ...
315  | 	 **/
316  | 
317  | 	nameptr->ptr = versptr->ptr;
318  | 	versptr->ptr = nameptr;
319  | 	nameptr->version = versptr;
320  |     }
321  | 
322  | #if WITH_DEBUGGING_CALLBACK
323  |     ErrorLogger( NO_ERR_END, LOC, _proc_cmdModuleVersion, NULL);
324  | #endif
325  | 
326  |     return( TCL_OK);
327  | 
328  | } /** End of 'cmdModuleVersion' **/
329  | 
330  | /*++++
331  |  ** ** Function-Header ***************************************************** **
332  |  ** 									     **
333  |  **   Function:		ExpandVersions					     **
334  |  ** 									     **
335  |  **   Description:	Callback function for 'version'			     **
336  |  ** 									     **
337  |  **   First Edition:	95/12/28					     **
338  |  ** 									     **
339  |  **   Parameters:	char	*name		Name to be expanded	     **
340  |  ** 									     **
341  |  **   Result:		char*	NULL		No symbols found	     **
342  |  **				Otherwise	Pointer to the list string   **
343  |  ** 									     **
344  |  ** ************************************************************************ **
345  |  ++++*/
346  | 
347  | char	*ExpandVersions( char	*name)
348  | {
349  |     char	*version, *module, *s;
350  |     static char	 buffer[ BUFSIZ];
351  |     ModModule	*modptr, *tmp1;
352  |     ModName	*ptr, *tmp2;
353  | 
354  | #if WITH_DEBUGGING_CALLBACK
355  |     ErrorLogger( NO_ERR_START, LOC, _proc_cmdModuleVersion, NULL);
356  | #endif
357  | 
358  |     /**
359  |      **  Parameter check
360  |      **/
361  | 
362  |     if((char *) NULL == (module = CheckModuleVersion( name))) 
363  | 	return((char *) NULL );		/** -------- EXIT (FAILURE) -------> **/
364  | 
365  |     if((char *) NULL == (version = strrchr( module, '/'))) {
366  | 	if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL))
367  | 	    return((char *) NULL );	/** -------- EXIT (FAILURE) -------> **/
368  |     }
369  | 
370  |     *version++ = '\0';
371  | 
372  |     /**
373  |      **  Now we have a module and a version.
374  |      **  Check wheter it exists
375  |      **/
376  | 
377  |     if((ModModule *) NULL == (modptr = FindModule( module, &tmp1)))
378  | 	return((char *) NULL );		/** -------- EXIT (FAILURE) -------> **/
379  | 
380  |     if((ModName *) NULL == (ptr = FindName( version, modptr->version, &tmp2))) {
381  | 	if((ModName *) NULL == (ptr = FindName( version, modptr->name, &tmp2))) 
382  | 	    return((char *) NULL );	/** -------- EXIT (FAILURE) -------> **/
383  | 	ptr = ptr->version;
384  |     }
385  | 
386  |     if( !ptr->ptr)
387  | 	return((char *) NULL );		/** -------- EXIT (FAILURE) -------> **/
388  | 
389  |     /**
390  |      **  Now scan in all the symbolic version names
391  |      **/
392  |  
393  |     *buffer = '\0';
394  |     if( s = scan_versions( buffer, buffer, ptr->ptr, modptr)) 
395  | 	*--s = '\0';			/** remove trailing ':'		     **/
396  | 
397  | #if WITH_DEBUGGING_CALLBACK
398  |     ErrorLogger( NO_ERR_END, LOC, _proc_cmdModuleVersion, NULL);
399  | #endif
400  | 
401  |     return( buffer);
402  | 
403  | } /** End of 'ExpandVersions' **/
404  | 
405  | /*++++
406  |  ** ** Function-Header ***************************************************** **
407  |  ** 									     **
408  |  **   Function:		scan_versions					     **
409  |  ** 									     **
410  |  **   Description:	Scan all symbolic versions pointed to be the passed  **
411  |  **			ModName pointer and print them as a list into the    **
412  |  **			passed buffer.					     **
413  |  ** 									     **
414  |  **   First Edition:	95/12/28					     **
415  |  ** 									     **
416  |  **   Parameters:	char	*buffer		Buffer for printing in	     **
417  |  **			ModName	*ptr		Name structure pointer	     **
418  |  **			ModModule  *modptr	Assigned module name	     **
419  |  ** 									     **
420  |  **   Result:		char*	NULL		Nothing printed into the     **
421  |  **						buffer			     **
422  |  **				Otherwise	Pointer to the end of the    **
423  |  **						string in the buffer	     **
424  |  ** 									     **
425  |  ** ************************************************************************ **
426  |  ++++*/
427  | 
428  | static	char	*scan_versions( char		 *buffer,
429  | 				char		 *base,
430  | 				ModName		 *ptr,
431  | 				ModModule	 *modptr)
432  | {
433  |     ModName     *tmp, *vers;
434  |     char 	*s;
435  | 
436  |     /**
437  |      **  Recursively print the queue of names
438  |      **/
439  | 
440  |     if( !ptr)
441  | 	return((char *) NULL);			/** ------ EXIT (END) -----> **/
442  | 
443  |     if( !ptr->name) {
444  | 	if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL))
445  | 	    return((char *) NULL);		/** ---- EXIT (FAILURE) ---> **/
446  | 
447  |     } else {
448  | 
449  | 	/**
450  | 	 **  Prevent endless loops
451  | 	 **/
452  | 
453  | 	if( strstr( base, ptr->name)) {
454  | 	    ErrorLogger( ERR_SYMLOOP, LOC, ptr->name, NULL);
455  | 	    return((char *) NULL);		/** ---- EXIT (FAILURE) ---> **/
456  | 	}
457  | 
458  | 	/**
459  | 	 **  Now print ...
460  | 	 **/
461  | 
462  | 	/* sprintf( buffer, "%s:", ptr->name); */
463  | 	strcpy( buffer, ptr->name);
464  | 	strcat( buffer, ":");
465  | 	buffer += strlen( buffer);
466  | 
467  | 	/**
468  | 	 **  Check wheter this is a version name again ...
469  | 	 **  This is a recursion, too
470  | 	 **/
471  | 
472  | 	if((ModName *) NULL != (vers = FindName( ptr->name, modptr->version,
473  | 	    &tmp))) {
474  | 	    if( s = scan_versions( buffer, base, vers->ptr, modptr))
475  | 		buffer = s;
476  | 	}
477  |     }
478  | 
479  |     /**
480  |      **  This is the recursion. Preserve the buffer end pointer
481  |      **/
482  | 
483  |     if( s = scan_versions( buffer, base, ptr->ptr, modptr))
484  | 	buffer = s;
485  | 
486  |     return( buffer);
487  | 
488  | } /** End of 'scan_versions' **/
489  | 
490  | /*++++
491  |  ** ** Function-Header ***************************************************** **
492  |  ** 									     **
493  |  **   Function:		CheckModuleVersion				     **
494  |  ** 									     **
495  |  **   Description:	Reduce the passed module name into a <mod>/<vers>    **
496  |  **			string						     **
497  |  ** 									     **
498  |  **   First Edition:	95/12/28					     **
499  |  ** 									     **
500  |  **   Parameters:	char	*name		name to be checked	     **
501  |  ** 									     **
502  |  **   Result:		char*	NULL		any error		     **
503  |  **				Otherwise	Pointer to a <mod>/<vers>    **
504  |  **						string			     **
505  |  ** 									     **
506  |  **   Attached Globals:	modlist		List containing all version names    **
507  |  **			aliaslist	List containing all alises	     **
508  |  **			g_current_module	The module which is handled  **
509  |  **						by the current command	     **
510  |  ** 									     **
511  |  ** ************************************************************************ **
512  |  ++++*/
513  | 
514  | static	char	*CheckModuleVersion( char *name)
515  | {
516  |     static char	 buffer[ BUFSIZ];
517  |     char	*s, *t;
518  | 
519  |     /**
520  |      **  Check the first parameter and extract modulename and version
521  |      **/
522  | 
523  |     if( '/' == *name) {			/** only the version specified	     **/
524  | 
525  | 	/**
526  | 	 **  get the module name from the current module ...
527  | 	 **/
528  | 
529  | 	if( !g_current_module)
530  | 	    return((char *) NULL);
531  | 
532  | 	strcpy( buffer, g_current_module);
533  | 	if((char *) NULL == (t = strrchr( buffer, '/')))
534  | 	    t = buffer + strlen( buffer);
535  | 	*t++ = '/';
536  | 	*t = '\0';
537  | 
538  | 	/**
539  | 	 **  The version has been specified as a parameter
540  | 	 **/
541  | 
542  | 	if( s = strrchr( name, '/')) {
543  | 	    s++;
544  | 	} else {
545  | 	    ErrorLogger( ERR_INTERAL, LOC, NULL);
546  | 	    return((char *) NULL);
547  | 	}
548  | 
549  | 	strcpy( t, s);
550  | 
551  |     } else {				/** Maybe an alias or a module	     **/
552  | 
553  | 	strcpy( buffer, name);
554  | 	if( !strrchr( buffer, '/')) {
555  | 
556  | 	    /**
557  | 	     **  Check wheter this is an alias ...
558  | 	     **/
559  | 
560  | 	    if( AliasLookup( buffer, &s, &t)) {
561  | 
562  | 		/* sprintf( buffer, "%s/%s", s, t); */
563  | 		strcpy( buffer, s);
564  | 		strcat( buffer, "/");
565  | 		strcat( buffer, t);
566  | 
567  | 	    } else {
568  | 
569  | 		/**
570  | 		 **  The default version is being selected
571  | 		 **/
572  | 
573  | 		t = buffer + strlen( buffer);
574  | 		if( '/' != *t)
575  | 		    *t++ = '/';
576  | 		strcpy( t, _default);
577  | 	    }
578  | 	}
579  |     }
580  | 
581  |     /**
582  |      **  Pass the buffer reference to the caller
583  |      **/
584  | 
585  |     return( buffer);
586  | 
587  | } /** End of 'CheckModuleVersion' **/
588  | 
589  | /*++++
590  |  ** ** Function-Header ***************************************************** **
591  |  ** 									     **
592  |  **   Function:		cmdModuleAlias					     **
593  |  ** 									     **
594  |  **   Description:	Callback function for 'alias'			     **
595  |  ** 									     **
596  |  **   First Edition:	95/12/28					     **
597  |  ** 									     **
598  |  **   Parameters:	ClientData	 client_data			     **
599  |  **			Tcl_Interp	*interp		According Tcl interp.**
600  |  **			int		 argc		Number of arguments  **
601  |  **			char		*argv[]		Argument array	     **
602  |  ** 									     **
603  |  **   Result:		int	TCL_OK		Successfull completion	     **
604  |  **				TCL_ERROR	Any error		     **
605  |  ** 									     **
606  |  **   Attached Globals:	aliaslist	List containing all alises	     **
607  |  **   			g_flags		These are set up accordingly before  **
608  |  **					this function is called in order to  **
609  |  **					control everything		     **
610  |  ** 									     **
611  |  ** ************************************************************************ **
612  |  ++++*/
613  | 
614  | int	cmdModuleAlias(	ClientData	 client_data,
615  | 	      		Tcl_Interp	*interp,
616  | 	      		int		 argc,
617  | 	      		char		*argv[])
618  | {
619  |     ModName	*tmp, *ptr;
620  |     char	*version, *module;
621  |     ModName	*trg_alias;
622  |     ModModule	*modptr;
623  | 
624  | #if WITH_DEBUGGING_CALLBACK
625  |     ErrorLogger( NO_ERR_START, LOC, _proc_cmdModuleAlias, NULL);
626  | #endif
627  | 
628  |     /**
629  |      **  Parameter check
630  |      **/
631  | 
632  |     if( argc != 3) {
633  | 	if( OK != ErrorLogger( ERR_USAGE, LOC, argv[0], " aliasname ",
634  | 	    "modulename", NULL))
635  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
636  |     }
637  | 
638  |     /**
639  |      **  Whatis mode?
640  |      **/
641  | 
642  |     if( g_flags & M_WHATIS) 
643  |         return( TCL_OK);		/** ------- EXIT PROCEDURE -------> **/
644  | 
645  |     if( g_flags & M_DISPLAY) {
646  | 	fprintf( stderr, "%s\t %s %s\n", argv[ 0], argv[ 1], argv[ 2]);
647  |     }
648  | 	
649  |     /**
650  |      **  Check if the target is an alias ...
651  |      **  Conditionally split up the passed <module>/<version> pair.
652  |      **/
653  | 
654  |     trg_alias = FindName( argv[ 2], aliaslist, &tmp);
655  |     if( !trg_alias) {
656  | 
657  |     	if((char *) NULL == (module = CheckModuleVersion( argv[2])))
658  | 	    module = argv[ 2];
659  | 
660  |     	if((char *) NULL != (version = strrchr( module, '/')))
661  | 	    *version++ = '\0';
662  |     }
663  | 
664  |     /**
665  |      **  Any alias record existing with this name?
666  |      **  If it does, we're finished ...
667  |      **/
668  | 
669  |     if( ptr = FindName( argv[ 1], aliaslist, &tmp)) {
670  | 
671  | 	if( !ptr->ptr || !ptr->ptr->name ||
672  | 	    !trg_alias && (!ptr->ptr->module || !ptr->ptr->module->module) ) {
673  | 	    ErrorLogger( ERR_INTERAL, LOC, NULL);
674  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
675  | 	}
676  | 
677  | 	if( trg_alias && !strcmp( ptr->ptr->name, argv[ 2]) ||
678  | 	    !trg_alias && !strcmp( ptr->ptr->name, version) &&
679  | 		!strcmp( ptr->ptr->module->module, module))
680  | 	    return( TCL_OK);		/** -------- EXIT (SUCCESS) -------> **/
681  | 
682  | 	if( OK != ErrorLogger( ERR_DUP_ALIAS, LOC, argv[1], NULL))
683  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
684  | 
685  |     } else {
686  | 
687  | 	/**
688  | 	 **  We have to allocate a new alias entry
689  | 	 **/
690  | 
691  | 	if((ModName *) NULL == (ptr = AddName( argv[ 1], &aliaslist, NULL))) {
692  | 	    ErrorLogger( ERR_INTERAL, LOC, NULL);
693  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
694  | 	}
695  |     }
696  | 
697  |     /**
698  |      **  Now ptr points to the affected module alias record ...
699  |      **  Conditionally we have to create the module and the version record now.
700  |      **/
701  | 
702  |     if( trg_alias) {
703  | 	ptr->ptr = trg_alias;
704  | 
705  |     } else {
706  | 	if((ModModule *) NULL == (modptr = AddModule( module))) {
707  | 	    ErrorLogger( ERR_BADMODNAM, LOC, argv[2], NULL);
708  | 	    ptr->ptr = (ModName *) NULL;
709  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
710  | 	}
711  | 	ptr->ptr = AddName( (version ? version : _default), &modptr->version,
712  | 	    modptr);
713  |     }
714  | 
715  | #if WITH_DEBUGGING_CALLBACK
716  |     ErrorLogger( NO_ERR_END, LOC, _proc_cmdModuleAlias, NULL);
717  | #endif
718  | 
719  |     return( TCL_OK);
720  | 
721  | } /** End of 'cmdModuleAlias' **/
722  | 
723  | /*++++
724  |  ** ** Function-Header ***************************************************** **
725  |  ** 									     **
726  |  **   Function:		AliasLookup					     **
727  |  ** 									     **
728  |  **   Description:	Resolves a given alias to a module/version string    **
729  |  ** 									     **
730  |  **   First Edition:	95/12/28					     **
731  |  ** 									     **
732  |  **   Parameters:	char	*alias		Name of the alias to be re-  **
733  |  **						solved			     **
734  |  **			char	**module	Buffer for the module name   **
735  |  **			char	**version	Buffer for the module version**
736  |  ** 									     **
737  |  **   Result:		int	1		Success, value in the buffer **
738  |  **						is valid		     **
739  |  **				0		Any error, or not found	     **
740  |  ** 									     **
741  |  **   Attached Globals:	aliaslist	List containing all alises	     **
742  |  ** 									     **
743  |  ** ************************************************************************ **
744  |  ++++*/
745  | 
746  | int	AliasLookup(	char	*alias,
747  | 			char	**module,
748  | 			char	**version)
749  | {
750  |     ModName	*ptr, *tmp, *oldptr = NULL;
751  | 
752  |     while( 1) {
753  | 
754  | 	/**
755  | 	 **  Lokate the alias entry and check intergrity
756  | 	 **/
757  | 
758  | 	if((ModName *) NULL == (ptr = FindName( alias, aliaslist, &tmp)))
759  | 	    return( 0);			/** ------- EXIT (not found) ------> **/
760  | 
761  | 	if( ptr == oldptr || !ptr->ptr || !ptr->ptr->name ) {
762  | 	    ErrorLogger( ERR_INTERAL, LOC, NULL);
763  | 	    return( 0);			/** -------- EXIT (FAILURE) -------> **/
764  | 	}
765  | 
766  | 	/**
767  | 	 **  Do we have to loop? Another alias has no module reference ...
768  | 	 **/
769  | 
770  |         if( !ptr->ptr->module) {
771  | 	    alias = ptr->ptr->name;
772  | 	    oldptr = ptr;
773  | 	    continue;
774  | 	}
775  | 
776  | 	/**
777  | 	 **  Got it. Get the module name and the version from the found
778  | 	 **  entry.
779  | 	 **  Dereference symbolic module versions
780  | 	 **/
781  | 
782  | 	*module = ptr->ptr->module->module;
783  | 	*version = ptr->ptr->name;
784  | 
785  | 	if((ModName *) NULL != (ptr = FindName( *version,
786  | 	    ptr->ptr->module->name, &tmp))) {
787  | 	    if( !ptr->version || !ptr->version->name) {
788  | 		if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL))
789  | 		    return( 0);
790  | 	    } else 
791  | 		*version = ptr->version->name;
792  | 	}
793  | 
794  | 	break;
795  | 
796  |     } /** while **/
797  | 
798  |     return( 1);
799  | 
800  | } /** End of 'AliasLookup' **/
801  | 
802  | /*++++
803  |  ** ** Function-Header ***************************************************** **
804  |  ** 									     **
805  |  **   Function:		VersionLookup					     **
806  |  ** 									     **
807  |  **   Description:	Resolves a given alias to a module/version string    **
808  |  ** 									     **
809  |  **   First Edition:	95/12/28					     **
810  |  ** 									     **
811  |  **   Parameters:	char	*alias		Name of the alias to be re-  **
812  |  **						solved			     **
813  |  **			char	**module	Buffer for the module name   **
814  |  **			char	**version	Buffer for the module version**
815  |  ** 									     **
816  |  **   Result:		int	1		Success, value in the buffer **
817  |  **						is valid		     **
818  |  **				0		Any error, or not found	     **
819  | 
820  |  **   Attached Globals:	g_current_module	The module which is handled  **
821  |  **						by the current command	     **
822  |  ** 									     **
823  |  ** ************************************************************************ **
824  |  ++++*/
825  | 
826  | int	VersionLookup(	char *name, char **module, char **version)
827  | {
828  |     static char  buffer[ BUFSIZ];
829  |     ModModule	*mptr, *mtmp;
830  |     ModName	*vptr, *vtmp;
831  |     ModName	**history;
832  |     char	*s, *t;
833  |     int		 histsize = 0, histndx = 0, i;
834  | 
835  |     /**
836  |      **  Check whether this is an alias ...
837  |      **  BTW: Alias lookups return the FQMN (full qualifed module name ;-)
838  |      **/
839  | 
840  |     if( '/' == *name) {
841  | 	strcpy( buffer, g_current_module);
842  | 	if( s = strrchr( buffer, '/'))
843  | 	    *s = '\0';
844  | 	*module = buffer;
845  | 	*version = name + 1;
846  |     
847  |     } else {
848  | 
849  | 	strcpy( buffer, name);
850  | 	*module = buffer;
851  | 
852  | 	if((char *) NULL == (*version = strrchr( buffer, '/'))) {
853  | 
854  | 	    if( AliasLookup( buffer, &s, &t)) {
855  | 		*module = s; *version = t;
856  | 
857  | 	    } else
858  | 		*version = _default;
859  | 
860  | 	} else 
861  | 	    *(*version)++ = '\0';
862  |     }
863  | 
864  |     /**
865  |      **  Look up modulename ...
866  |      **  We call it success, if we do not find a registerd name.
867  |      **  In this case <module>/<version> will be returned as passed.
868  |      **/
869  |     if((ModModule *) NULL == (mptr = FindModule( *module, &mtmp))) {
870  | 	return( 1);			/** -------- EXIT (SUCCESS) -------> **/
871  |     }
872  | 
873  |     /**
874  |      **  This is for preventing from endless loops
875  |      **/
876  |     histsize = HISTTAB;
877  |     histndx = 0;
878  | 
879  |     if((ModName **) NULL == (history = (ModName **) malloc( histsize * 
880  | 	sizeof( ModName *)))) {
881  | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
882  | 	return( 0);			/** -------- EXIT (FAILURE) -------> **/
883  |     }
884  | 
885  |     /**
886  |      **  Now look up the version name. Check symbolic names first. If some-
887  |      **  thing is found, check if the related version record itsself relates
888  |      **  to a name record ...
889  |      **/
890  |     while( 1) {
891  | 
892  | 	/**
893  | 	 **  Check the symbolic names ...
894  | 	 **/
895  | 	if((ModName *) NULL != (vptr = FindName( *version, mptr->name, &vtmp))){
896  | 	    if( !vptr->version || !vptr->version->name) {
897  | 		if( OK != ErrorLogger( ERR_INTERAL, LOC, NULL)) 
898  | 		    *version = (char *) NULL;
899  | 		break;
900  | 	    }
901  | 
902  | 	    *version = vptr->version->name;
903  | 
904  | 	    /**
905  | 	     **  Prevent from looping ...
906  | 	     **/
907  | 	    for( i=0; i<histndx; i++) {
908  | 		if( history[ i] == vptr) {		/** That's the loop  **/
909  | 		    ErrorLogger( ERR_SYMLOOP, LOC, *version, NULL);
910  | 		    *version = (char *) NULL;
911  | 		    break;
912  | 		}
913  | 	    }
914  | 
915  | 	    if( !*version)
916  | 		break;
917  | 
918  | 	    if( histndx >= histsize) {
919  | 		histsize += HISTTAB;
920  | 
921  | 		if((ModName **) NULL == (history = (ModName **) realloc(
922  | 		    history, histsize * sizeof( ModName *)))) {
923  | 		    ErrorLogger( ERR_ALLOC, LOC, NULL);
924  | 		    return( 0);		/** -------- EXIT (FAILURE) -------> **/
925  | 		}
926  | 	    }
927  | 
928  | 	    history[ histndx++] = vptr;
929  | 
930  | 	} else {
931  | 	    break;
932  | 
933  | 	} /** if( FindName) **/
934  |     } /** while( 1) **/
935  | 
936  |     /**
937  |      **  Free the loop preventing list
938  |      **  If version is NULL now, something went wrong in the lookup loop above
939  |      **/
940  |     null_free((void *) &history);
941  |     return((char *) NULL != *version);
942  | 
943  | } /** End of 'VersionLookup' **/
944  | 
945  | /*++++
946  |  ** ** Function-Header ***************************************************** **
947  |  ** 									     **
948  |  **   Function:		CleanupVersion					     **
949  |  ** 									     **
950  |  **   Description:	Cleanup the version structure			     **
951  |  ** 									     **
952  |  **   First Edition:	95/12/28					     **
953  |  ** 									     **
954  |  **   Parameters:	-						     **
955  |  ** 									     **
956  |  **   Result:		-						     **
957  |  ** 									     **
958  |  **   Attached Globals:	modlist		List containing all version names    **
959  |  **			aliaslist	List containing all alises	     **
960  |  ** 									     **
961  |  ** ************************************************************************ **
962  |  ++++*/
963  | 
964  | void	CleanupVersion(ModModule *ptr)
965  | {
966  | #if WITH_DEBUGGING_UTIL_2
967  |     ErrorLogger( NO_ERR_START, LOC, _proc_CleanupVersion, NULL);
968  | #endif
969  | 
970  |     CleanupVersionSub( modlist);
971  |     modlist = (ModModule *) NULL;
972  | 
973  |     CleanupName( aliaslist);
974  |     aliaslist = (ModName *) NULL;
975  | 
976  | } /** End of 'CleanupVersion' **/
977  | 
978  | static void	CleanupVersionSub( ModModule *ptr)
979  | {
980  |     /**
981  |      **  Recursion
982  |      **/
983  | 
984  |     if( !ptr)
985  | 	return;
986  | 
987  |     CleanupVersion( ptr->next);
988  | 
989  |     /**
990  |      **  Cleanup everything that relates to this record
991  |      **/
992  | 
993  |     CleanupName( ptr->version);
994  |     CleanupName( ptr->name);
995  |     null_free((void *) &(ptr->module));
996  | 
997  | } /** End of 'CleanupVersionSub' **/
998  | 
999  | static void	CleanupName( ModName *ptr)
1000 | {
1001 |     /**
1002 |      **  Recursion
1003 |      **/
1004 | 
1005 |     if( !ptr)
1006 | 	return;
1007 | 
1008 |     CleanupName( ptr->next);
1009 | 
1010 |     /**
1011 |      **  Cleanup everything that relates to this record
1012 |      **/
1013 | 
1014 |     null_free((void *) &(ptr->name));
1015 | 
1016 | } /** End of 'CleanupName' **/
1017 | 
1018 | /*++++
1019 |  ** ** Function-Header ***************************************************** **
1020 |  ** 									     **
1021 |  **   Function:		AddModule					     **
1022 |  ** 									     **
1023 |  **   Description:	Add a new entry to the modules queue		     **
1024 |  ** 									     **
1025 |  **   First Edition:	95/12/28					     **
1026 |  ** 									     **
1027 |  **   Parameters:	char	*name		Name of the new module	     **
1028 |  ** 									     **
1029 |  **   Result:		ModModule*	NULL	Any error                    **
1030 |  **					Else	Pointer to the new record    **
1031 |  ** 									     **
1032 |  **   Attached Globals:	modlist		List containing all version names    **
1033 |  ** 									     **
1034 |  ** ************************************************************************ **
1035 |  ++++*/
1036 | 
1037 | static	ModModule	*AddModule(	char	*name)
1038 | {
1039 |     ModModule	*app_ptr, *ptr;
1040 | 
1041 | #if WITH_DEBUGGING_UTIL_1
1042 |     ErrorLogger( NO_ERR_START, LOC, _proc_AddModule, NULL);
1043 | #endif
1044 | 
1045 |     /**
1046 |      **  We do not trust in NULL module names
1047 |      **/
1048 | 
1049 |     if( !name || !*name)
1050 | 	return((ModModule *) NULL);
1051 | 
1052 |     /**
1053 |      **  Check if the module name already exists and save the 'prev' pointer
1054 |      **  for appending the new one.
1055 |      **/
1056 | 
1057 |     if( ptr = FindModule( name, &app_ptr))
1058 | 	return( ptr);
1059 | 
1060 |     /**
1061 |      **  Allocate a new guy
1062 |      **/
1063 | 
1064 |     if((ModModule *) NULL == (ptr = (ModModule *) malloc( sizeof(ModModule)))) {
1065 | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
1066 | 	return((ModModule *) NULL);
1067 |     }
1068 | 
1069 |     /**
1070 |      **  Fill the name in and put it in the queue
1071 |      **/
1072 | 
1073 |     if((char *) NULL == (ptr->module = strdup( name))) {
1074 | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
1075 | 	null_free((void *) &ptr);
1076 | 	return((ModModule *) NULL);
1077 |     }
1078 | 
1079 |     if( app_ptr) {
1080 | 	ptr->next = app_ptr->next;
1081 | 	app_ptr->next = ptr;
1082 |     } else {
1083 | 	ptr->next = modlist;
1084 | 	modlist = ptr;
1085 |     }
1086 | 
1087 |     ptr->version = (ModName *) NULL;
1088 |     ptr->name = (ModName *) NULL;
1089 | 
1090 |     /**
1091 |      **  Pass back the pointer to the new entry
1092 |      **/
1093 | 
1094 | #if WITH_DEBUGGING_UTIL_1
1095 |     ErrorLogger( NO_ERR_END, LOC, _proc_AddModule, NULL);
1096 | #endif
1097 | 
1098 |     return( ptr);
1099 | 
1100 | } /** End of 'AddModule' **/
1101 | 
1102 | /*++++
1103 |  ** ** Function-Header ***************************************************** **
1104 |  ** 									     **
1105 |  **   Function:		FindModule					     **
1106 |  ** 									     **
1107 |  **   Description:	Find a new entry in the modules queue		     **
1108 |  ** 									     **
1109 |  **   First Edition:	95/12/28					     **
1110 |  ** 									     **
1111 |  **   Parameters:	char		*name	Name of be found	     **
1112 |  **			ModModule	**prev	Buffer for the 'previous'    **
1113 |  **						pointer			     **
1114 |  ** 									     **
1115 |  **   Result:		ModModule*	NULL	Any error or not found       **
1116 |  **					Else	Pointer to the record	     **
1117 |  ** 									     **
1118 |  **   Attached Globals:	modlist		List containing all version names    **
1119 |  ** 									     **
1120 |  ** ************************************************************************ **
1121 |  ++++*/
1122 | 
1123 | static	ModModule	*FindModule(	char		 *name,
1124 | 					ModModule	**prev)
1125 | {
1126 |     ModModule	*ptr = modlist;
1127 |     int		 cmp = 1;
1128 | 
1129 | #if WITH_DEBUGGING_UTIL_1
1130 |     ErrorLogger( NO_ERR_START, LOC, _proc_FindModule, NULL);
1131 | #endif
1132 | 
1133 |     *prev = (ModModule *) NULL;
1134 |     while( ptr && 0 < (cmp = strcmp( name, ptr->module))) {
1135 | 	*prev = ptr;
1136 | 	ptr = ptr->next;
1137 |     }
1138 | 
1139 | #if WITH_DEBUGGING_UTIL_1
1140 |     ErrorLogger( NO_ERR_END, LOC, _proc_FindModule, NULL);
1141 | #endif
1142 | 
1143 |     return( cmp ? (ModModule *) NULL : ptr);
1144 | 
1145 | } /** End of 'FindModule' **/
1146 | 
1147 | /*++++
1148 |  ** ** Function-Header ***************************************************** **
1149 |  ** 									     **
1150 |  **   Function:		AddName						     **
1151 |  ** 									     **
1152 |  **   Description:	Add a new entry to the name queue		     **
1153 |  ** 									     **
1154 |  **   First Edition:	95/12/28					     **
1155 |  ** 									     **
1156 |  **   Parameters:	char	 *name		Name of the new entry	     **
1157 |  **			ModName	**start		Start of the queue	     **
1158 |  **			ModModule *module	Parent module record pointer **
1159 |  ** 									     **
1160 |  **   Result:		ModName*	NULL	Any error                    **
1161 |  **					Else	Pointer to the new record    **
1162 |  ** 									     **
1163 |  ** ************************************************************************ **
1164 |  ++++*/
1165 | 
1166 | static	ModName	*AddName(	char	 *name,
1167 | 				ModName	**start,
1168 | 				ModModule *module)
1169 | {
1170 |     ModName	*app_ptr, *ptr;
1171 | 
1172 | #if WITH_DEBUGGING_UTIL_1
1173 |     ErrorLogger( NO_ERR_START, LOC, _proc_AddName, NULL);
1174 | #endif
1175 | 
1176 |     /**
1177 |      **  Check if the name already exists and save the 'prev' pointer
1178 |      **  for appending the new one.
1179 |      **/
1180 | 
1181 |     if( ptr = FindName( name, *start, &app_ptr))
1182 | 	return( ptr);
1183 | 
1184 |     /**
1185 |      **  Allocate a new guy
1186 |      **/
1187 | 
1188 |     if((ModName *) NULL == (ptr = (ModName *) malloc( sizeof(ModName)))) {
1189 | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
1190 | 	return((ModName *) NULL);
1191 |     }
1192 | 
1193 |     /**
1194 |      **  Fill the name in and put it in the queue
1195 |      **/
1196 | 
1197 |     if((char *) NULL == (ptr->name = strdup( name))) {
1198 | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
1199 | 	null_free((void *) &ptr);
1200 | 	return((ModName *) NULL);
1201 |     }
1202 | 
1203 |     if( app_ptr) {
1204 | 	ptr->next = app_ptr->next;
1205 | 	app_ptr->next = ptr;
1206 |     } else {
1207 | 	ptr->next = *start;
1208 | 	*start = ptr;
1209 |     }
1210 | 
1211 |     ptr->module = module;
1212 |     ptr->version = ptr->ptr = (ModName *) NULL;
1213 | 
1214 |     /**
1215 |      **  Pass back the pointer to the new entry
1216 |      **/
1217 | 
1218 | #if WITH_DEBUGGING_UTIL_1
1219 |     ErrorLogger( NO_ERR_END, LOC, _proc_AddName, NULL);
1220 | #endif
1221 | 
1222 |     return( ptr);
1223 | 
1224 | } /** End of 'AddName' **/
1225 | 
1226 | /*++++
1227 |  ** ** Function-Header ***************************************************** **
1228 |  ** 									     **
1229 |  **   Function:		FindName					     **
1230 |  ** 									     **
1231 |  **   Description:	Find a new entry in the modules queue		     **
1232 |  ** 									     **
1233 |  **   First Edition:	95/12/28					     **
1234 |  ** 									     **
1235 |  **   Parameters:	char	 *name		Name of be found	     **
1236 |  **			ModName  *start		Start of the name queue      **
1237 |  **			ModName	**prev		Buffer for the 'previous'    **
1238 |  **						pointer			     **
1239 |  ** 									     **
1240 |  **   Result:		ModName*	NULL	Any error or not found       **
1241 |  **					Else	Pointer to the record	     **
1242 |  ** 									     **
1243 |  ** ************************************************************************ **
1244 |  ++++*/
1245 | 
1246 | static	ModName	*FindName(	char	 *name,
1247 | 				ModName  *start,
1248 | 				ModName	**prev)
1249 | {
1250 |     ModName	*ptr = start;
1251 |     int		 cmp = 1;
1252 | 
1253 | #if WITH_DEBUGGING_UTIL_1
1254 |     ErrorLogger( NO_ERR_START, LOC, _proc_FindName, NULL);
1255 | #endif
1256 | 
1257 |     *prev = (ModName *) NULL;
1258 |     while( ptr && 0 < (cmp = strcmp( name, ptr->name))) {
1259 | 	*prev = ptr;
1260 | 	ptr = ptr->next;
1261 |     }
1262 | 
1263 | #if WITH_DEBUGGING_UTIL_1
1264 |     ErrorLogger( NO_ERR_END, LOC, _proc_FindName, NULL);
1265 | #endif
1266 | 
1267 |     return( cmp ? (ModName *) NULL : ptr);
1268 | 
1269 | } /** End of 'FindName' **/