[net.sources] makedep: construct dependency lines for makefiles

mann@Navajo.ARPA (10/06/84)

#! /bin/sh
: This is a shar archive.  Extract with sh, not csh.
echo x - makedep.1
cat > makedep.1 << '965!Funky!Stuff!'
.TH MAKEDEP 1  "2 April 1984"
.SU
.SH NAME
makedep \- construct dependency lines for makefiles
.SH SYNOPSIS
.B makedep [
options
.B ] [
source files
.B ]
.SH DESCRIPTION
.I Makedep
constructs a makefile-style dependency list
showing which header files the object files constructed
from the given source files depend
upon.  The dependency of the object file upon the source 
file is not indicated in the output; this dependency can
normally be inferred by the
.I make
program.
.PP
.I Makedep
handles nested includes properly, propagating
dependencies of one header file upon another back to
each object file whose source file includes the dependent
header file.
.PP
The following options are accepted.  In options that take an
argument, the space between the option letter and the argument is optional.
.IP "-o file" 1i
Output file name.  The default is "dependencies".  The name "-" 
indicates standard output.
.IP "-I dir" 1i
Add
.I dir
to the include file search list.  Multiple
-I options accumulate, building the search list from
left to right, with the system include directories
added at the end.  Directory names
are interpreted relative to the directory from which
.I makedep
is invoked.  
.IP "-U" 1i
Use the standard Unix header directories as the system
search list.  Equivalent to specifying -I/usr/include after
all other -I options.
.IP "-V" 1i
Use the standard V-System header directories as the
system search list.  Equivalent to specifying the options
-I/usr/sun/include -I/usr/local/include -I/usr/include after
all other -I options.
.IP "-xV" 1i
Use the experimental V-System header directories as the
system search list.  Equivalent to specifying the options
-I/usr/sun/xinclude -I/usr/sun/include -I/usr/local/include
-I/usr/include after all other -I options.
.IP "-N" 1i
Use no system search list.  Suppresses the warning message 
ordinarily printed when a header file cannot be found.  This
option is useful when you are not interested in dependencies
on system include files.
.IP "-e ext" 1i
Object files have extension ".ext".  Defaults to .b if -V or -xV
is specified, .o otherwise.
.IP "-d" 1i
Turn on debug output.  Useful only to the maintainers.
.PP
If the source files depend on any header files in standard system 
include directories, one of the options -U, -V, -xV, or -N should 
normally be specified.  These four options are mutually exclusive.
If none of these options is given, only the directories specified 
in -I options are included in the search list (as with the -N flag), 
but warning messages are still printed for any header files that
cannot be found.
.SH "SEE ALSO"
make(1)
.SH DIAGNOSTICS
A warning is printed for each included file that cannot be found.
Other errors are fatal; the messages should be self-explanatory.
.SH BUGS
Pathnames that are excessively long may be silently truncated or
cause crashes.
.PP
.I Makedep
does not know that the same file can have two different names,
for example "bar.h" and "foo/../bar.h".  This means it
will fail to detect loops in the dependency graph if the pathnames grow
in this way while it is following the loop.  The loop will eventually
terminate due to the previous bug, and garbage output will result.
.SH AUTHORS
Marvin Theimer and Tim Mann, Stanford.

965!Funky!Stuff!
echo x - buildfile
cat > buildfile << '965!Funky!Stuff!'
# Buildfile for makedep

OBJS = makedep.o gen.o getincl.o print.o list.o

CFLAGS = -O

.c.o:
	cc $(CFLAGS) -c $<

makedep: $(OBJS)
	cc -o makedep $(OBJS)

#include dependencies

install:
	install -q -s makedep ${DESTDIR}/bin/makedep
	install -q -c makedep.1 /usr/man/man1/makedep.1

clean:
	rm -f *BAK *CKP *.o makedep
cleanbak:
	rm -f *BAK *CKP

build:
	makedep -U *.c
	buildmake

xbuild:
	makedep -U *.c
	buildmake -DX=1
965!Funky!Stuff!
echo x - gen.c
cat > gen.c << '965!Funky!Stuff!'
/*
 * Module which generates the list of source files and which generates
 * the include file dependencies.
 */


#include "makedep.h"

/* External and forward fcn declarations */
extern StringList *GetIncludeFileList();
StringList *FindIListLocation();



/*
 * GenIncludeFileDependencies:
 * Generate all include file dependencies.
 * Starting with an empty list of include files, each source file 
 * on SrcFiles is examined
 * to extract all include file references it contains.  These file names
 * are placed on an include file list, IList.  Also, each source file gets
 * a linked list of (immediate) dependencies associated with it.
 * Each include file on IList
 * is examined to extract its include file dependencies; which are added to
 * the list.  Also, each include file gets a linked list of (immediate)
 * dependencies associated with it.
 * The IList is kept in sorted order in order to remove duplicates
 * and processed list entries are marked as such to prevent reprocessing.
 */

GenIncludeFileDependencies()
  {
    StringList *p;
    int done;

    if (Debug)
      {
	printf("\nGenIncludeFileDependencies:\n");
      }

    IList = MakeList();		/* Create an empty IList. */
    /* Run through the source files, generating each one's immediate
       dependency list. */
    for (p = SrcFiles->next; p != NULL; p = p->next)
      {
	GenDependencies(p);
      }
    /* Repeatedly iterate over IList until all elements have been processed. */
    done = FALSE;
    while (!done)
      {
        done = TRUE;		/* Assume we're done until proven otherwise. */
	for (p = IList->next; p != NULL; p = p->next)
	  {
	    if (p->state == UNPROCESSED)
	      {
	        done = FALSE;
		GenDependencies(p);
	      }
	  }
      }
  }


/*
 * GenDependencies:
 * Generate the immediate dependency list for p and mark it as processed.
 * Adds newly encountered include files to IList.  IList is kept in sorted
 * order so that duplicates can be removed.
 */

GenDependencies(p)
    StringList *p;
  {
    StringList *il, *pil, *pIList;
    DepList *dil;

    p->state = PROCESSED;
    /* Generate a list of include files referenced directly in p. */
    il = GetIncludeFileList(p);
    /* Create a list of corresponding dependency records for p. */
    for (pil = il->next; pil != NULL; pil = pil->next)
      {
	AddDepList(pil, p);
      }

    if (Debug)
      {
        printf("%s ", p->str);
	PrintDepList(p, "dependency list");
      }

    /* Merge the list of include files into IList, discarding duplicates.
       Make the pointers in p's dependency list point at the
       records in IList rather than the il list.  This is simpler to program
       than attempting to extract the non-duplicated records from il and
       selectively updating things. */
    for (dil = p->dep; dil != NULL; dil = dil->next)
      {
	pIList = FindIListLocation(dil->inclFile);
				/* pIList now points either to a record in
				   IList for this include file or to the
				   record in IList after which the include
				   file should be inserted. */
	if ((pIList == IList) || (!Equal(pIList->str, dil->inclFile->str)))
	  {
	    /* No duplicate - insert a new record into IList. */
	    InsertList(dil->inclFile->str, pIList);
	    pIList = pIList->next;
				/* Make pIList point at the new record. */
	  }
	dil->inclFile = pIList;	/* pIList at this point points at the correct
				   record in IList. */
      }
    /* Get rid of the il list of include files.  All references are now to
       the records in IList. */
    DestroyList(il);
  }


/*
 * FindIListLocation:
 * Search the (sorted) IList for a record corresponding to p.  If one is
 * found then return a pointer to it.  Otherwise return a pointer to the
 * record in IList after which such a record would appear.
 */

StringList *FindIListLocation(p)
    StringList *p;
  {
    StringList *ptr;
    int order;

    for (ptr = IList; ptr->next != NULL; ptr = ptr->next)
      {
        order = strcmp(p->str, ptr->next->str);
	if (order == 0)
	  {
	    /* Found a corresponding record.  Return a ptr to it. */
	    return(ptr->next);
	  }
	else if (order < 0)
	  {
	    /* ptr->next->str is lexically greater than p->str.  p should
	       go before it but after ptr. */
	    return(ptr);
	  }
      }
    /* p goes at the end of the list. */
    return(ptr);
  }
965!Funky!Stuff!
echo x - getincl.c
cat > getincl.c << '965!Funky!Stuff!'
/*
 * Module which finds all include file references in a specified file.
 */


#include "makedep.h"

#define MaxLine 200		/* Maximum line size allowed for a file. */

extern FILE *fopen();
extern char *rindex();

/*
 * GetIncludeFileList:
 * Scan the file corresponding to p and extract all include file references
 * from it.  
 */

StringList *GetIncludeFileList(p)
    StringList *p;
  {
   FILE *pf;
   char *linePtr;
   char line[MaxLine];
   char dirName[MaxLine];
   StringList *iList;
   char *p1;
 
    /* Open the file corresponding to p for reading. */
    pf = fopen(p->str, "r");
    if (pf == NULL)
      {
	perror(p->str);
	exit(errno);
      }

    /* Determine the correct path prefix for the 
     *   local directory. */
    strcpy(dirName, p->str);
    p1 = rindex(dirName, '/');
    if (p1 != NULL)
	*p1 = '\0';		/* chop off the last component */
    else
	*dirName = '\0';	/* no path prefix */

    /* Scan each line of the file in search of include file references. */
    iList = MakeList();
    linePtr = fgets(line, MaxLine, pf);
    while (linePtr != NULL)
      {
	ProcessLine(linePtr, iList, dirName);
	linePtr = fgets(line, MaxLine, pf);
      }
    /* Close p's file. */
    fclose(pf);

    return(iList);
  }


/*
 * ProcessLine:
 * Process a line from a file, looking for include file references.
 * Create a list of records, one per include file reference.
 * Each include file record contains the correctly expanded include file,
 * i.e. the include file name is prepended with the appropriate directory
 * prefix, as determined from InclDirs directory search list.
 */

ProcessLine(linePtr, iList, dirName)
    char *linePtr;
    StringList *iList;
    char *dirName;		/* Local directory name. */
  {
    char *p = linePtr;
    int relLocal;
    char name[MaxLine], dname[MaxLine];
    char *p1;
    StringList *dp;

    if (*p != '#')
      {				/* Couldn't find the # in col. 1. */
	return;
      }
    p++;
    /* Skip over any blanks or tabs between the # and the include. */
    while ((*p == ' ') || (*p == '\t'))
      {
	p++;
      }
    /* Parse the include string. */
    if (strcmpn(p, "include", 7) != 0)
      {				/* Didn't find the include string. */
	return;
      }
    p += 7;
    /* Skip over any blanks or tabs between the include and the " or < . */
    while ((*p == ' ') || (*p == '\t'))
      {
	p++;
      }
    /* Determine whether the include is relative to the local dir or not. */
    if (*p == '"')
      {
	relLocal = TRUE;
      }
    else if (*p == '<')
      {
	relLocal = FALSE;
      }
    else
      {
	return;			/* It's neither - so this isn't an include file
				   refernence. */
      }
    p++;			/* p now points at the include file's name. */
    /* Extract the include file's name. */
    p1 = name;
    while ((*p != '"') && (*p != '>') && (*p != '\0'))
      {
	*p1++ = *p++;
      }
    if (*p == '\0')
      {
	return;			/* Abrupt end-of-line encountered.  This isn't
				   an include file ref. after all. */
      }
    *p1 = '\0';

    /* Now determine which directory the include file is actually in and
       prepend the file's name with the appropriate directory name. */
    if (*name == '/')
      {				/* Dealing with an absolute path name. */
	if (TryToAddIncl(name, iList))
	  {
	    return;
	  }
	else
	  {
	    if (!NFlag)
	      {
	        fprintf(stderr,"%s: Warning - include file '%s' not found.\n",
		    MyName, name);
	      }
	    return;
	  }
      }
    if (relLocal)
      {
	/* Look in the local directory first. */
	if (*dirName != '\0')
	  {
	    strcpy(dname, dirName);
	    strcat(dname, "/");
	    strcat(dname, name);
	  }
	else
	  {
	    strcpy(dname, name);
	  }
	if (TryToAddIncl(dname, iList))
	  {
	    return;
	  }
      }
    for (dp = InclDirs->next; dp != NULL; dp = dp->next)
      {
        strcpy(dname, dp->str);
	strcat(dname, "/");
	strcat(dname, name);
	if (TryToAddIncl(dname, iList))
	  {
	    return;
	  }
      }
    /* We couldn't find the include file */
    if (!NFlag)
      {
        fprintf(stderr, "%s: Warning - include file '%s' not found.\n",
		 MyName, name);
      }
  }


/*
 * TryToAddIncl:
 * Tries to open the file  name  and if successful adds  name  to iList.
 * Returns whether name was added to iList or not.
 */

int TryToAddIncl(name, iList)
    char *name;
    StringList *iList;
  {
    FILE *inclF;

    inclF = fopen(name, "r");
    if (inclF != NULL)
      {
	/* Add the include file to the iList */
	AddList(name, iList);
	fclose(inclF);
	return(TRUE);
      }
    return(FALSE);
  }
965!Funky!Stuff!
echo x - list.c
cat > list.c << '965!Funky!Stuff!'
/*
 * String List Package
 */

#include "makedep.h"

extern char *malloc();


/*
 * GetMem:
 * malloc with error exit.
 */

char *GetMem(n)
    int n;
  {
    char *p;

    p = malloc(n);
    if (p == NULL)
      {
	fprintf(stderr, "%s: Ran out of memory!\n", MyName);
	exit(1);
      }
    return(p);
  }


/*
 * MakeList:
 * Create an empty list.
 */

StringList *MakeList()
  {
    StringList *ptr;

    ptr = (StringList *) GetMem(sizeof(StringList));
    ptr->str = NULL;
    ptr->state = HEADER;
    ptr->dep = NULL;
    ptr->next = NULL;
    return(ptr);
  }


/*
 * AddList:
 * Add a string to a list.
 */

AddList(s, l)
    char *s;
    StringList *l;
  {
    StringList *ptr;

    ptr = (StringList *) GetMem(sizeof(StringList));
    ptr->str = GetMem(strlen(s)+1);
    strcpy(ptr->str, s);
    ptr->state = UNPROCESSED;
    ptr->dep = NULL;
    ptr->next = l->next;
    l->next = ptr;
  }


/*
 * InsertList:
 * Insert a string to a list after the designated record.
 * The same implementation as for AddList can be used.
 */

InsertList(s, l)
    char *s;
    StringList *l;
  {
    AddList(s, l);
  }


/*
 * DeleteList:
 * Delete a string from a list.
 */

DeleteList(s, l)
    char *s;
    StringList *l;
  {
    StringList *ptr, *ptr1;

    if (l->next == NULL)
      {
	return;
      }
    for (ptr = l; ptr->next != NULL; ptr = ptr->next)
      {
	if (Equal(s, ptr->next->str))
	  {
	    ptr1 = ptr->next;
	    ptr->next = ptr->next->next;
	    free(ptr1->str);
	    free(ptr1);
	    return;
	  }
      }
  }


/*
 * MemberOfList:
 * Determines whether s is a member of l.
 */

int MemberOfList(s, l)
    char *s;
    StringList *l;
  {
    StringList *ptr;

    for (ptr = l->next; ptr != NULL; ptr = ptr->next)
      {
	if (Equal(s, ptr->str))
	  {
	    return(TRUE);
	  }
      }
    return(FALSE);
  }


/*
 * DestroyList:
 * Deallocates a list and all its members.
 */

DestroyList(l)
    StringList *l;
  {
    StringList *ptr;

    while (l->next != NULL)
      {
	ptr = l->next;
	l->next = ptr->next;
	free(ptr->str);
	free(ptr);
      }
    free(l);
  }


/*
 * MergeLists:
 * Merges list l1 onto the front of list l2.
 * l1 is NOT destroyed in the process.
 */

MergeLists(l1, l2)
    StringList *l1;
    StringList *l2;
  {
    StringList *p;

    p = l1->next;
    while (p != NULL)
      {
	AddList(p->str, l2);
	p = p->next;
      }
  }

/*
 * PrintList:
 * Prints a list preceded by a banner.
 * Intended for diagnostic purposes.
 */

PrintList(l, banner)
    StringList *l;
    char *banner;
  {
    printf("%s:\n", banner);
    for (l = l->next; l != NULL; l = l->next)
      {
	printf("  %s,  state: %d\n", l->str, l->state);
      }
  }


/*
 * AddDepList:
 * Add a dependency record for pi to the dependency list for p.
 */

AddDepList(pi, p)
    StringList *pi, *p;
  {
    DepList *ptr;

    ptr = (DepList *) GetMem(sizeof(DepList));
    ptr->inclFile = pi;
    ptr->next = p->dep;
    p->dep = ptr;
  }


/*
 * PrintDepList:
 * Print a dependency list preceded by a banner.
 * Intended for diagnostic purposes.
 */

PrintDepList(l, banner)
    StringList *l;
    char *banner;
  {
    DepList *p;

    printf("%s:\n", banner);
    for (p = l->dep; p != NULL; p = p->next)
      {
	printf("  %s\n", p->inclFile->str);
      }
  }


/*
 * CheckDepList:
 * Checks to ensure that all dependency records actually point at a record
 * which is on the IList.
 */

CheckDepList(p)
    StringList *p;
  {
    DepList *ptr;
    StringList *p1;
    int ok;

    for (ptr = p->dep; ptr != NULL; ptr = ptr->next)
      {
        ok = FALSE;
	for (p1 = IList->next; p1 != NULL; p1 = p1->next)
	  {
	    if (p1 == ptr->inclFile)
	      {
		ok = TRUE;
		break;
	      }
	  }
	if (!ok)
	  {
	    fprintf(stderr, "\n%s: dependency %s doesn't point into IList.\n",
	    		MyName, ptr->inclFile->str);
	  }
      }
  }
965!Funky!Stuff!
echo x - makedep.c
cat > makedep.c << '965!Funky!Stuff!'
/*
 * Program to construct dependency lines for makefiles.
 *
 * Marvin Theimer and Tim Mann, 3/18/84.
 *
 * Synopsis
 *	makedep [options] [source files]
 *
 * Discussion
 *   Makedep constructs a makefile-style dependency list
 *   showing which header files the object files constructed
 *   from the given source files depend
 *   upon.  The dependency of the object file upon the source 
 *   file is not indicated in the output; this dependency can 
 *   usually be inferred by the make program.
 *
 *   Makedep handles nested includes properly, propagating
 *   dependencies of one header file upon another back to
 *   each object file whose source file includes the dependent
 *   header file.
 *
 * Options
 *   -o outfile
 *	Output file name.  The default is "dependencies".  The name "-" 
 *	indicates standard output.
 *
 *   -I dir
 *	Add "dir" to the include file search list.  Multiple
 *	-I options accumulate, building the search list from
 *	left to right, with the system include directories
 *	added at the end.  The space separating the directory
 *	name from the -I may be omitted.  Directory names
 *	may be given relative to the directory from which
 *	makedep is invoked.  
 *
 *   -U
 *	Use the standard Unix header directories as the system
 *	search list.  Equivalent to specifying -I/usr/include after
 *	all other -I options.
 *
 *   -V
 *	Use the standard V-System header directories as the
 *	system search list.  Equivalent to specifying the options
 *	-I/usr/sun/include -I/usr/local/include -I/usr/include after
 *	all other -I options.
 *
 *   -xV
 *	Use the experimental V-System header directories as the
 *	system search list.  Equivalent to specifying the options
 *	-I/usr/sun/xinclude -I/usr/sun/include -I/usr/local/include
 *	-I/usr/include after all other -I options.
 *
 *   -N
 *	Use no system search list.  Suppresses the warning message 
 *	ordinarily printed when a header file cannot be found.  This
 *	option is useful when you are not interested in dependencies
 *	on system include files.
 *
 *   -e ext
 *	Object files have extension ".ext".  Defaults to .b if -V or -xV
 *	is specified, .o otherwise.
 *
 *   -d
 *	Turn on debug output.  Useful only to the maintainers.
 *
 *   If the source files depend on any header files in standard system 
 *   include directories, one of the options -U, -V, -xV, or -N should 
 *   normally be specified.  These four options are mutually exclusive.
 *   If none of these options is given, only the directories specified 
 *   in -I options are included in the search list (as with the -N flag), 
 *   but warning messages are still printed for any header files that
 *   cannot be found.
 */

#include "makedep.h"

extern FILE *freopen();


main(argc, argv)
    int argc;
    char **argv;
  {

    Debug = 0;

    Initialize();
    ProcessCommandLine(argc, argv);
    /* Redirect stdout to the output file. */
    if (strcmp(OutputFileName, "-") != 0)
       {
        if (freopen(OutputFileName, "w", stdout) == NULL)
          {
	    fprintf(stderr, "%s: can't open %s for writing.\n", 
		MyName, OutputFileName);
	    perror(OutputFileName);
	    exit(errno);
	  }
      }
    GenIncludeFileDependencies();
    PrintDependencies();

    exit(0);
  }


/*
 * Initialize various program data structures and variables.
 */

Initialize()
  {

    /* Set up default option flag settings. */
    NFlag = FALSE;
    UFlag = FALSE;
    VFlag = FALSE;
    xVFlag = FALSE;
    eFlag = FALSE;

    /* Set up default source and object extensions. */
    strcpy(ObjExt, DefaultObjExt);

    /* Set up default output filename. */
    strcpy(OutputFileName, DefaultOutputFileName);

    /* Set up default search list for include files. */
    InclDirs = MakeList();
    UserInclDirs = MakeList();	/* Empty to begin with. */

    /* Set up default source directory list. */
    SrcFiles = MakeList();
  }


/*
 * ProcessCommandLine:
 * Process user's command line.
 */

ProcessCommandLine(argc, argv)
    int argc;
    char **argv;
  {
    int nArg = 1;
    char *p;

    MyName = argv[0];

    /* Parse command line options. */
    while (nArg < argc)
      {
        if ( argv[nArg][0] == '-' )
	  {
	    switch (argv[nArg][1] )
	      {
                case 'o':
		    if (argv[nArg][2] == '\0')
		      {
			p = argv[nArg+1];
				/* Name is a separate input arg. */
			nArg++;	/* Incr. over the input arg. */
		      }
		    else
		      {
			p = &(argv[nArg][2]);
				/* Name is tacked onto the -o directly. */
		      }
		    strcpy(OutputFileName, p);
		    break;

	        case 'I':
		    if (argv[nArg][2] == '\0')
		      {
			AddList(argv[nArg+1], UserInclDirs);
				/* Name is a separate input arg. */
			nArg++;	/* Incr. over the input arg. */
		      }
		    else
		      {
			AddList(&(argv[nArg][2]), UserInclDirs);
				/* Name is tacked onto the -I directly. */
		      }
	      	    break;

	        case 'N':
		    NFlag = TRUE;
	      	    break;

	        case 'U':
		    UFlag = TRUE;
		    AddDefaultDirectoryLists(DefaultUnixInclDirs, InclDirs);
	      	    break;

		case 'V':
		    VFlag = TRUE;
		    AddDefaultDirectoryLists(DefaultVInclDirs, InclDirs);
		    if (!eFlag) strcpy(ObjExt, DefaultVObjExt);
		    break;

	        case 'x':  /* xV */
		    if (argv[nArg][2] != 'V') 
			goto badswitch;  /* sorry, Edsger */
		    xVFlag = TRUE;
		    AddDefaultDirectoryLists(DefaultXVInclDirs, InclDirs);
		    if (!eFlag) strcpy(ObjExt, DefaultVObjExt);
	      	    break;

	        case 'e':
		    eFlag = TRUE;
		    if (argv[nArg][2] == '\0')
		      {
			p = argv[nArg+1];
				/* Name is a separate input arg. */
			nArg++;	/* Incr. over the input arg. */
		      }
		    else
		      {
			p = &(argv[nArg][2]);
				/* Name is tacked onto the -e directly. */
		      }
		    strcpy(ObjExt, p);
	      	    break;

		case 'd':
		    Debug = TRUE;
		    break;

	 	default:
		badswitch:
		    fprintf(stderr, "%s: Unknown switch: %s\n", 
			MyName, argv[nArg]);
		    exit(1);
	      }
	  }
	else			/* No more options */
	  {
	    break;
	  }
	nArg++;
      }

    if (NFlag + UFlag + VFlag + xVFlag > 1)
      {
	fprintf(stderr, "%s: -N, -U, -V, and -xV are mutually exclusive.\n",
		MyName);
	exit(1);
      }

    /* Add source files for which dependencies are to be found. */
    while (nArg < argc)
      {
	AddList(argv[nArg], SrcFiles);
	nArg++;
      }

    /* Merge the list of user include directories with the list of "regular"
       include directories to get the final search path. */
    MergeLists(UserInclDirs, InclDirs);

    if (Debug)
      {
	printf("NFlag: %d, UFlag: %d, VFlag: %d, xVFlag",
		NFlag, UFlag, VFlag, xVFlag);
	printf("    ObjExt: %s\n", ObjExt);
	printf("output filename: %s\n", OutputFileName);
	PrintList(SrcFiles, "SrcFiles");
	PrintList(InclDirs, "InclDirs");
	PrintList(UserInclDirs, "UserInclDirs");
      }
  }


/*
 * AddDefaultDirectoryLists:
 * Adds the directory names in dirs to the list l.
 * The names in dirs are separated by blanks.
 */

AddDefaultDirectoryLists(dirs, l)
    char *dirs;
    StringList l;
  {
    char *p, *p1;

    p = dirs;
    while (*p != '\0')
      {
	for (p1 = p; ((*p1 != ' ') && (*p1 != '\0')); p1++)
	    ;
	while (*p1 == ' ')
	  {
	    *p1++ = '\0';
	  }
	AddList(p, l);
	p = p1;
      }
  }
965!Funky!Stuff!
echo x - print.c
cat > print.c << '965!Funky!Stuff!'
/*
 * Module which prints out the dependencies of each source file to the
 * file OutputFileName.
 */


#include "makedep.h"

extern char *rindex();

int CurrentMarkValue;		/* This variable is used to keep track of
				   which marking cycle is currently going
				   on.  Each source file's dependency graph
				   is traversed using a new value of
				   this variable.  Dependency records are
				   marked to avoid infinite recursions
				   through a possibly cyclic dependency
				   graph. */


/*
 * PrintDependencies:
 * Prints out the dependencies of each file on the source file list SrcFiles.
 * This is done by recursively printing the dependency list of each file.
 * I.e. each source file's dependency list is traversed and the print
 * routine is called to print the dependency list of each file on the list.
 * Since there may be cycles in the graph of dependencies, a marking scheme
 * is employed.
 */

PrintDependencies()
  {
    StringList *p;

    if (Debug)
      {
	printf("\nPrintDependencies:\n");
	PrintList(IList, "IList");
	for (p = SrcFiles->next; p != NULL; p = p->next)
	  {
	    CheckDepList(p);
	  }
      }

    /* Mark all include file records' state with the same starting value. */
    for (p = IList->next; p != NULL; p = p->next)
      {
	p->state = START_MARK_VALUE;
      }
    CurrentMarkValue = START_MARK_VALUE;
    /* Traverse the list source files and print the dependencies of each. */
    for (p = SrcFiles->next; p != NULL; p = p->next)
      {
        if (p->dep != NULL)	/* Don't print anything if there are no
				   dependencies! */
	  {
	    CurrentMarkValue++;
	    PrintSrcObjFile(p);
	    PrintDeps(p);
	    printf("\n");
	  }
      }
  }


/*
 * PrintSrcObjFile:
 * Print the source file name with its source extension replaced by its
 * object extension.  Only the base name is printed.
 */

PrintSrcObjFile(p)
    StringList *p;
  {
    char name[80];
    char *ptr;

    /* Replace the source file's extension with its object extension. */
    strcpy(name, p->str);
    ptr = name + strlen(name);
    while ((ptr != name) && (*ptr != '.'))
      {
	ptr--;
      }
    if (ptr == name)
      {
	fprintf(stderr, "%s: malformed source file name: %s\n", 
	    MyName, p->str);
	exit(1);
      }
    ptr++;			/* Get over the '.' */
    strcpy(ptr, ObjExt);

    /* Find the start of the base name. */
    ptr = rindex(name, '/');
    if (ptr != NULL)
      {
        ptr++;
      }
    else
      {
        ptr = name;
      }

    /* Print out the first part of the appropriate makefile-style 
       dependency line. */
    printf("%s:", ptr);
  }


/*
 * PrintDeps:
 * Recursive routine which prints out the dependencies for p and invokes
 * itself for all dependencies of dependencies of p.  Uses a marking scheme
 * to avoid cycles in the dependency graph.
 */

PrintDeps(p)
    StringList *p;
  {
    DepList *ptr;
    StringList *p1;

    /* Traverse the list of immediate dependencies. */
    for (ptr = p->dep; ptr != NULL; ptr = ptr->next)
      {
        p1 = ptr->inclFile;
        if (p1->state < CurrentMarkValue)
	  {			/* We've haven't yet seen this dependency. */
	    printf(" \\\n\t%s", p1->str);
				/* Print out the immediate dependency. */
	    p1->state = CurrentMarkValue;
				/* Mark the include file as already seen. */
	    PrintDeps(p1);
				/* Print out the dependency's dependencies. */
	  }
      }
  }
965!Funky!Stuff!

djhawley@wateng.UUCP (David J. Hawley) (10/16/84)

I think there is something wrong with the distribution. Where is "makedep.h"
and why does the buildfile (/* you need buildmake */) include a non-existent
file called "dependencies".

	David Hawley
	University of Waterloo

mann@CSL-Vax.ARPA (Tim Mann) (10/26/84)

> I think there is something wrong with the distribution. Where is "makedep.h"
> and why does the buildfile (/* you need buildmake */) include a non-existent
> file called "dependencies".
> 
> 	David Hawley
> 	University of Waterloo


The missing "dependencies" is due to a circularity:  makedep's buildfile
uses makedep to build its own dependencies.  You can start out with an empty
"dependencies" file to make the initial makefile.

I'm sorry if makedep.h got left out.  I don't have the original shar archive
anymore so I have no way of guessing what went wrong.  At any rate, here it
is:

/*
 * Primary include file for makedep
 */


#include <stdio.h>
#include <errno.h>

#define FALSE 0
#define TRUE 1

extern int errno;
int Debug;
char *MyName;	/* name by which makedep was invoked */


/*
 * List definitions
 */

/* StringList record states. */
#define HEADER 1
#define UNPROCESSED 2
#define PROCESSED 3
#define START_MARK_VALUE 4

typedef struct StringListType
  {
    char *str;
    int state;
    struct DepListType *dep;
    struct StringListType *next;
  }
    StringList;

typedef struct DepListType
  {
    struct StringListType *inclFile;
    struct DepListType *next;
  }
    DepList;

extern StringList *MakeList();


/*
 * Various string objects and their default defns.
 */

/* Extensions for object. */
#define DefaultObjExt "o"
#define DefaultVObjExt "b"
char ObjExt[16];

/* Source file list. */
StringList *SrcFiles;

/* Search lists for include files. */
#define DefaultVInclDirs "/usr/sun/include /usr/local/include /usr/include"
#define DefaultXVInclDirs "/usr/sun/xinclude /usr/sun/include /usr/local/include /usr/include"
#define DefaultUnixInclDirs "/usr/include"
StringList *InclDirs;
StringList *UserInclDirs;

/* Output file name. */
#define DefaultOutputFileName "dependencies"
char OutputFileName[128];

/* Command line option flags */
int NFlag, UFlag, VFlag, xVFlag, eFlag;

/* List of include files that have been encountered. */
StringList *IList;


#define Equal(a,b) (strcmp(a,b) == 0)