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