Annotation of src/usr.bin/make/targ.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: targ.c,v 1.5 1995/06/14 15:20:08 christos Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
! 5: * Copyright (c) 1988, 1989 by Adam de Boor
! 6: * Copyright (c) 1989 by Berkeley Softworks
! 7: * All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to Berkeley by
! 10: * Adam de Boor.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the University of
! 23: * California, Berkeley and its contributors.
! 24: * 4. Neither the name of the University nor the names of its contributors
! 25: * may be used to endorse or promote products derived from this software
! 26: * without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 38: * SUCH DAMAGE.
! 39: */
! 40:
! 41: #ifndef lint
! 42: /* from: static char sccsid[] = "@(#)targ.c 5.9 (Berkeley) 3/1/91"; */
! 43: static char *rcsid = "$Id: targ.c,v 1.5 1995/06/14 15:20:08 christos Exp $";
! 44: #endif /* not lint */
! 45:
! 46: /*-
! 47: * targ.c --
! 48: * Functions for maintaining the Lst allTargets. Target nodes are
! 49: * kept in two structures: a Lst, maintained by the list library, and a
! 50: * hash table, maintained by the hash library.
! 51: *
! 52: * Interface:
! 53: * Targ_Init Initialization procedure.
! 54: *
! 55: * Targ_End Cleanup the module
! 56: *
! 57: * Targ_NewGN Create a new GNode for the passed target
! 58: * (string). The node is *not* placed in the
! 59: * hash table, though all its fields are
! 60: * initialized.
! 61: *
! 62: * Targ_FindNode Find the node for a given target, creating
! 63: * and storing it if it doesn't exist and the
! 64: * flags are right (TARG_CREATE)
! 65: *
! 66: * Targ_FindList Given a list of names, find nodes for all
! 67: * of them. If a name doesn't exist and the
! 68: * TARG_NOCREATE flag was given, an error message
! 69: * is printed. Else, if a name doesn't exist,
! 70: * its node is created.
! 71: *
! 72: * Targ_Ignore Return TRUE if errors should be ignored when
! 73: * creating the given target.
! 74: *
! 75: * Targ_Silent Return TRUE if we should be silent when
! 76: * creating the given target.
! 77: *
! 78: * Targ_Precious Return TRUE if the target is precious and
! 79: * should not be removed if we are interrupted.
! 80: *
! 81: * Debugging:
! 82: * Targ_PrintGraph Print out the entire graphm all variables
! 83: * and statistics for the directory cache. Should
! 84: * print something for suffixes, too, but...
! 85: */
! 86:
! 87: #include <stdio.h>
! 88: #include <time.h>
! 89: #include "make.h"
! 90: #include "hash.h"
! 91: #include "dir.h"
! 92:
! 93: static Lst allTargets; /* the list of all targets found so far */
! 94: static Lst allGNs; /* List of all the GNodes */
! 95: static Hash_Table targets; /* a hash table of same */
! 96:
! 97: #define HTSIZE 191 /* initial size of hash table */
! 98:
! 99: static int TargPrintOnlySrc __P((ClientData, ClientData));
! 100: static int TargPrintName __P((ClientData, ClientData));
! 101: static int TargPrintNode __P((ClientData, ClientData));
! 102: static void TargFreeGN __P((ClientData));
! 103:
! 104: /*-
! 105: *-----------------------------------------------------------------------
! 106: * Targ_Init --
! 107: * Initialize this module
! 108: *
! 109: * Results:
! 110: * None
! 111: *
! 112: * Side Effects:
! 113: * The allTargets list and the targets hash table are initialized
! 114: *-----------------------------------------------------------------------
! 115: */
! 116: void
! 117: Targ_Init ()
! 118: {
! 119: allTargets = Lst_Init (FALSE);
! 120: Hash_InitTable (&targets, HTSIZE);
! 121: }
! 122:
! 123: /*-
! 124: *-----------------------------------------------------------------------
! 125: * Targ_End --
! 126: * Finalize this module
! 127: *
! 128: * Results:
! 129: * None
! 130: *
! 131: * Side Effects:
! 132: * All lists and gnodes are cleared
! 133: *-----------------------------------------------------------------------
! 134: */
! 135: void
! 136: Targ_End ()
! 137: {
! 138: Lst_Destroy(allTargets, NOFREE);
! 139: if (allGNs)
! 140: Lst_Destroy(allGNs, TargFreeGN);
! 141: Hash_DeleteTable(&targets);
! 142: }
! 143:
! 144: /*-
! 145: *-----------------------------------------------------------------------
! 146: * Targ_NewGN --
! 147: * Create and initialize a new graph node
! 148: *
! 149: * Results:
! 150: * An initialized graph node with the name field filled with a copy
! 151: * of the passed name
! 152: *
! 153: * Side Effects:
! 154: * The gnode is added to the list of all gnodes.
! 155: *-----------------------------------------------------------------------
! 156: */
! 157: GNode *
! 158: Targ_NewGN (name)
! 159: char *name; /* the name to stick in the new node */
! 160: {
! 161: register GNode *gn;
! 162:
! 163: gn = (GNode *) emalloc (sizeof (GNode));
! 164: gn->name = strdup (name);
! 165: gn->path = (char *) 0;
! 166: if (name[0] == '-' && name[1] == 'l') {
! 167: gn->type = OP_LIB;
! 168: } else {
! 169: gn->type = 0;
! 170: }
! 171: gn->unmade = 0;
! 172: gn->make = FALSE;
! 173: gn->made = UNMADE;
! 174: gn->childMade = FALSE;
! 175: gn->mtime = gn->cmtime = 0;
! 176: gn->iParents = Lst_Init (FALSE);
! 177: gn->cohorts = Lst_Init (FALSE);
! 178: gn->parents = Lst_Init (FALSE);
! 179: gn->children = Lst_Init (FALSE);
! 180: gn->successors = Lst_Init (FALSE);
! 181: gn->preds = Lst_Init (FALSE);
! 182: gn->context = Lst_Init (FALSE);
! 183: gn->commands = Lst_Init (FALSE);
! 184: gn->suffix = NULL;
! 185:
! 186: if (allGNs == NULL)
! 187: allGNs = Lst_Init(FALSE);
! 188: Lst_AtEnd(allGNs, (ClientData) gn);
! 189:
! 190: return (gn);
! 191: }
! 192:
! 193: /*-
! 194: *-----------------------------------------------------------------------
! 195: * TargFreeGN --
! 196: * Destroy a GNode
! 197: *
! 198: * Results:
! 199: * None.
! 200: *
! 201: * Side Effects:
! 202: * None.
! 203: *-----------------------------------------------------------------------
! 204: */
! 205: static void
! 206: TargFreeGN (gnp)
! 207: ClientData gnp;
! 208: {
! 209: GNode *gn = (GNode *) gnp;
! 210:
! 211:
! 212: free(gn->name);
! 213: if (gn->path)
! 214: free(gn->path);
! 215:
! 216: Lst_Destroy(gn->iParents, NOFREE);
! 217: Lst_Destroy(gn->cohorts, NOFREE);
! 218: Lst_Destroy(gn->parents, NOFREE);
! 219: Lst_Destroy(gn->children, NOFREE);
! 220: Lst_Destroy(gn->successors, NOFREE);
! 221: Lst_Destroy(gn->preds, NOFREE);
! 222: Lst_Destroy(gn->context, NOFREE);
! 223: Lst_Destroy(gn->commands, NOFREE);
! 224: free((Address)gn);
! 225: }
! 226:
! 227:
! 228: /*-
! 229: *-----------------------------------------------------------------------
! 230: * Targ_FindNode --
! 231: * Find a node in the list using the given name for matching
! 232: *
! 233: * Results:
! 234: * The node in the list if it was. If it wasn't, return NILGNODE of
! 235: * flags was TARG_NOCREATE or the newly created and initialized node
! 236: * if it was TARG_CREATE
! 237: *
! 238: * Side Effects:
! 239: * Sometimes a node is created and added to the list
! 240: *-----------------------------------------------------------------------
! 241: */
! 242: GNode *
! 243: Targ_FindNode (name, flags)
! 244: char *name; /* the name to find */
! 245: int flags; /* flags governing events when target not
! 246: * found */
! 247: {
! 248: GNode *gn; /* node in that element */
! 249: Hash_Entry *he; /* New or used hash entry for node */
! 250: Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
! 251: /* an entry for the node */
! 252:
! 253:
! 254: if (flags & TARG_CREATE) {
! 255: he = Hash_CreateEntry (&targets, name, &isNew);
! 256: if (isNew) {
! 257: gn = Targ_NewGN (name);
! 258: Hash_SetValue (he, gn);
! 259: (void) Lst_AtEnd (allTargets, (ClientData)gn);
! 260: }
! 261: } else {
! 262: he = Hash_FindEntry (&targets, name);
! 263: }
! 264:
! 265: if (he == (Hash_Entry *) NULL) {
! 266: return (NILGNODE);
! 267: } else {
! 268: return ((GNode *) Hash_GetValue (he));
! 269: }
! 270: }
! 271:
! 272: /*-
! 273: *-----------------------------------------------------------------------
! 274: * Targ_FindList --
! 275: * Make a complete list of GNodes from the given list of names
! 276: *
! 277: * Results:
! 278: * A complete list of graph nodes corresponding to all instances of all
! 279: * the names in names.
! 280: *
! 281: * Side Effects:
! 282: * If flags is TARG_CREATE, nodes will be created for all names in
! 283: * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
! 284: * an error message will be printed for each name which can't be found.
! 285: * -----------------------------------------------------------------------
! 286: */
! 287: Lst
! 288: Targ_FindList (names, flags)
! 289: Lst names; /* list of names to find */
! 290: int flags; /* flags used if no node is found for a given
! 291: * name */
! 292: {
! 293: Lst nodes; /* result list */
! 294: register LstNode ln; /* name list element */
! 295: register GNode *gn; /* node in tLn */
! 296: char *name;
! 297:
! 298: nodes = Lst_Init (FALSE);
! 299:
! 300: if (Lst_Open (names) == FAILURE) {
! 301: return (nodes);
! 302: }
! 303: while ((ln = Lst_Next (names)) != NILLNODE) {
! 304: name = (char *)Lst_Datum(ln);
! 305: gn = Targ_FindNode (name, flags);
! 306: if (gn != NILGNODE) {
! 307: /*
! 308: * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
! 309: * are added to the list in the order in which they were
! 310: * encountered in the makefile.
! 311: */
! 312: (void) Lst_AtEnd (nodes, (ClientData)gn);
! 313: if (gn->type & OP_DOUBLEDEP) {
! 314: (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
! 315: }
! 316: } else if (flags == TARG_NOCREATE) {
! 317: Error ("\"%s\" -- target unknown.", name);
! 318: }
! 319: }
! 320: Lst_Close (names);
! 321: return (nodes);
! 322: }
! 323:
! 324: /*-
! 325: *-----------------------------------------------------------------------
! 326: * Targ_Ignore --
! 327: * Return true if should ignore errors when creating gn
! 328: *
! 329: * Results:
! 330: * TRUE if should ignore errors
! 331: *
! 332: * Side Effects:
! 333: * None
! 334: *-----------------------------------------------------------------------
! 335: */
! 336: Boolean
! 337: Targ_Ignore (gn)
! 338: GNode *gn; /* node to check for */
! 339: {
! 340: if (ignoreErrors || gn->type & OP_IGNORE) {
! 341: return (TRUE);
! 342: } else {
! 343: return (FALSE);
! 344: }
! 345: }
! 346:
! 347: /*-
! 348: *-----------------------------------------------------------------------
! 349: * Targ_Silent --
! 350: * Return true if be silent when creating gn
! 351: *
! 352: * Results:
! 353: * TRUE if should be silent
! 354: *
! 355: * Side Effects:
! 356: * None
! 357: *-----------------------------------------------------------------------
! 358: */
! 359: Boolean
! 360: Targ_Silent (gn)
! 361: GNode *gn; /* node to check for */
! 362: {
! 363: if (beSilent || gn->type & OP_SILENT) {
! 364: return (TRUE);
! 365: } else {
! 366: return (FALSE);
! 367: }
! 368: }
! 369:
! 370: /*-
! 371: *-----------------------------------------------------------------------
! 372: * Targ_Precious --
! 373: * See if the given target is precious
! 374: *
! 375: * Results:
! 376: * TRUE if it is precious. FALSE otherwise
! 377: *
! 378: * Side Effects:
! 379: * None
! 380: *-----------------------------------------------------------------------
! 381: */
! 382: Boolean
! 383: Targ_Precious (gn)
! 384: GNode *gn; /* the node to check */
! 385: {
! 386: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
! 387: return (TRUE);
! 388: } else {
! 389: return (FALSE);
! 390: }
! 391: }
! 392:
! 393: /******************* DEBUG INFO PRINTING ****************/
! 394:
! 395: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
! 396: /*-
! 397: *-----------------------------------------------------------------------
! 398: * Targ_SetMain --
! 399: * Set our idea of the main target we'll be creating. Used for
! 400: * debugging output.
! 401: *
! 402: * Results:
! 403: * None.
! 404: *
! 405: * Side Effects:
! 406: * "mainTarg" is set to the main target's node.
! 407: *-----------------------------------------------------------------------
! 408: */
! 409: void
! 410: Targ_SetMain (gn)
! 411: GNode *gn; /* The main target we'll create */
! 412: {
! 413: mainTarg = gn;
! 414: }
! 415:
! 416: static int
! 417: TargPrintName (gnp, ppath)
! 418: ClientData gnp;
! 419: ClientData ppath;
! 420: {
! 421: GNode *gn = (GNode *) gnp;
! 422: printf ("%s ", gn->name);
! 423: #ifdef notdef
! 424: if (ppath) {
! 425: if (gn->path) {
! 426: printf ("[%s] ", gn->path);
! 427: }
! 428: if (gn == mainTarg) {
! 429: printf ("(MAIN NAME) ");
! 430: }
! 431: }
! 432: #endif /* notdef */
! 433: return (ppath ? 0 : 0);
! 434: }
! 435:
! 436:
! 437: int
! 438: Targ_PrintCmd (cmd, dummy)
! 439: ClientData cmd;
! 440: ClientData dummy;
! 441: {
! 442: printf ("\t%s\n", (char *) cmd);
! 443: return (dummy ? 0 : 0);
! 444: }
! 445:
! 446: /*-
! 447: *-----------------------------------------------------------------------
! 448: * Targ_FmtTime --
! 449: * Format a modification time in some reasonable way and return it.
! 450: *
! 451: * Results:
! 452: * The time reformatted.
! 453: *
! 454: * Side Effects:
! 455: * The time is placed in a static area, so it is overwritten
! 456: * with each call.
! 457: *
! 458: *-----------------------------------------------------------------------
! 459: */
! 460: char *
! 461: Targ_FmtTime (time)
! 462: time_t time;
! 463: {
! 464: struct tm *parts;
! 465: static char buf[40];
! 466: static char *months[] = {
! 467: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
! 468: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
! 469: };
! 470:
! 471: parts = localtime(&time);
! 472:
! 473: sprintf (buf, "%d:%02d:%02d %s %d, 19%d",
! 474: parts->tm_hour, parts->tm_min, parts->tm_sec,
! 475: months[parts->tm_mon], parts->tm_mday, parts->tm_year);
! 476: return(buf);
! 477: }
! 478:
! 479: /*-
! 480: *-----------------------------------------------------------------------
! 481: * Targ_PrintType --
! 482: * Print out a type field giving only those attributes the user can
! 483: * set.
! 484: *
! 485: * Results:
! 486: *
! 487: * Side Effects:
! 488: *
! 489: *-----------------------------------------------------------------------
! 490: */
! 491: void
! 492: Targ_PrintType (type)
! 493: register int type;
! 494: {
! 495: register int tbit;
! 496:
! 497: #ifdef __STDC__
! 498: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
! 499: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
! 500: #else
! 501: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
! 502: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
! 503: #endif /* __STDC__ */
! 504:
! 505: type &= ~OP_OPMASK;
! 506:
! 507: while (type) {
! 508: tbit = 1 << (ffs(type) - 1);
! 509: type &= ~tbit;
! 510:
! 511: switch(tbit) {
! 512: PRINTBIT(OPTIONAL);
! 513: PRINTBIT(USE);
! 514: PRINTBIT(EXEC);
! 515: PRINTBIT(IGNORE);
! 516: PRINTBIT(PRECIOUS);
! 517: PRINTBIT(SILENT);
! 518: PRINTBIT(MAKE);
! 519: PRINTBIT(JOIN);
! 520: PRINTBIT(INVISIBLE);
! 521: PRINTBIT(NOTMAIN);
! 522: PRINTDBIT(LIB);
! 523: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
! 524: case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
! 525: PRINTDBIT(ARCHV);
! 526: }
! 527: }
! 528: }
! 529:
! 530: /*-
! 531: *-----------------------------------------------------------------------
! 532: * TargPrintNode --
! 533: * print the contents of a node
! 534: *-----------------------------------------------------------------------
! 535: */
! 536: static int
! 537: TargPrintNode (gnp, passp)
! 538: ClientData gnp;
! 539: ClientData passp;
! 540: {
! 541: GNode *gn = (GNode *) gnp;
! 542: int pass = *(int *) passp;
! 543: if (!OP_NOP(gn->type)) {
! 544: printf("#\n");
! 545: if (gn == mainTarg) {
! 546: printf("# *** MAIN TARGET ***\n");
! 547: }
! 548: if (pass == 2) {
! 549: if (gn->unmade) {
! 550: printf("# %d unmade children\n", gn->unmade);
! 551: } else {
! 552: printf("# No unmade children\n");
! 553: }
! 554: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
! 555: if (gn->mtime != 0) {
! 556: printf("# last modified %s: %s\n",
! 557: Targ_FmtTime(gn->mtime),
! 558: (gn->made == UNMADE ? "unmade" :
! 559: (gn->made == MADE ? "made" :
! 560: (gn->made == UPTODATE ? "up-to-date" :
! 561: "error when made"))));
! 562: } else if (gn->made != UNMADE) {
! 563: printf("# non-existent (maybe): %s\n",
! 564: (gn->made == MADE ? "made" :
! 565: (gn->made == UPTODATE ? "up-to-date" :
! 566: (gn->made == ERROR ? "error when made" :
! 567: "aborted"))));
! 568: } else {
! 569: printf("# unmade\n");
! 570: }
! 571: }
! 572: if (!Lst_IsEmpty (gn->iParents)) {
! 573: printf("# implicit parents: ");
! 574: Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
! 575: fputc ('\n', stdout);
! 576: }
! 577: }
! 578: if (!Lst_IsEmpty (gn->parents)) {
! 579: printf("# parents: ");
! 580: Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
! 581: fputc ('\n', stdout);
! 582: }
! 583:
! 584: printf("%-16s", gn->name);
! 585: switch (gn->type & OP_OPMASK) {
! 586: case OP_DEPENDS:
! 587: printf(": "); break;
! 588: case OP_FORCE:
! 589: printf("! "); break;
! 590: case OP_DOUBLEDEP:
! 591: printf(":: "); break;
! 592: }
! 593: Targ_PrintType (gn->type);
! 594: Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
! 595: fputc ('\n', stdout);
! 596: Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
! 597: printf("\n\n");
! 598: if (gn->type & OP_DOUBLEDEP) {
! 599: Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
! 600: }
! 601: }
! 602: return (0);
! 603: }
! 604:
! 605: /*-
! 606: *-----------------------------------------------------------------------
! 607: * TargPrintOnlySrc --
! 608: * Print only those targets that are just a source.
! 609: *
! 610: * Results:
! 611: * 0.
! 612: *
! 613: * Side Effects:
! 614: * The name of each file is printed preceeded by #\t
! 615: *
! 616: *-----------------------------------------------------------------------
! 617: */
! 618: static int
! 619: TargPrintOnlySrc(gnp, dummy)
! 620: ClientData gnp;
! 621: ClientData dummy;
! 622: {
! 623: GNode *gn = (GNode *) gnp;
! 624: if (OP_NOP(gn->type))
! 625: printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
! 626:
! 627: return (dummy ? 0 : 0);
! 628: }
! 629:
! 630: /*-
! 631: *-----------------------------------------------------------------------
! 632: * Targ_PrintGraph --
! 633: * print the entire graph. heh heh
! 634: *
! 635: * Results:
! 636: * none
! 637: *
! 638: * Side Effects:
! 639: * lots o' output
! 640: *-----------------------------------------------------------------------
! 641: */
! 642: void
! 643: Targ_PrintGraph (pass)
! 644: int pass; /* Which pass this is. 1 => no processing
! 645: * 2 => processing done */
! 646: {
! 647: printf("#*** Input graph:\n");
! 648: Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
! 649: printf("\n\n");
! 650: printf("#\n# Files that are only sources:\n");
! 651: Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
! 652: printf("#*** Global Variables:\n");
! 653: Var_Dump (VAR_GLOBAL);
! 654: printf("#*** Command-line Variables:\n");
! 655: Var_Dump (VAR_CMD);
! 656: printf("\n");
! 657: Dir_PrintDirectories();
! 658: printf("\n");
! 659: Suff_PrintAll();
! 660: }