4.4BSD/usr/src/contrib/mkmf/src/depend.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1983, 1985, 1991, 1993 Peter J. Nicklin.
 * Copyright (c) 1991, 1993 Version Technology.
 * All Rights Reserved.
 *
 * $License: VT.1.1 $
 * Redistribution and use in source and binary forms,  with or without
 * modification,  are permitted provided that the following conditions
 * are met:  (1) Redistributions of source code must retain the  above
 * copyright  notice,  this  list  of  conditions  and  the  following
 * disclaimer.  (2) Redistributions in binary form must reproduce  the
 * above  copyright notice,  this list of conditions and the following
 * disclaimer in the  documentation  and/or other  materials  provided
 * with  the  distribution.  (3) All advertising materials  mentioning
 * features or  use  of  this  software  must  display  the  following
 * acknowledgement:  ``This  product  includes  software  developed by
 * Version Technology.''  Neither the name of Version  Technology  nor
 * the  name  of  Peter J. Nicklin  may  be used to endorse or promote
 * products derived from this software without specific prior  written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY VERSION TECHNOLOGY ``AS IS''  AND  ANY
 * EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
 * IMPLIED  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL  VERSION  TECHNOLOGY  BE
 * LIABLE  FOR ANY DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR  CONSEQUENTIAL DAMAGES   (INCLUDING,   BUT   NOT   LIMITED   TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT LIABILITY,  OR  TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING  IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE,  EVEN  IF  ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * Report problems and direct questions to nicklin@netcom.com
 *
 * $Header: depend.c,v 4.10 93/05/25 21:17:49 nicklin Exp $
 *
 * Author: Peter J. Nicklin
 */
#include <ctype.h>
#include <stdio.h>
#include "Mkmf.h"
#include "config.h"
#include "dlist.h"
#include "hash.h"
#include "macro.h"
#include "null.h"
#include "path.h"
#include "slist.h"
#include "stringx.h"
#include "yesno.h"

#define CURINCLUDE		"./"
#define TOLOWER(c)		(isupper(c) ? tolower(c) : (c))
#define ISWHITESPACE(c)		(c == ' ' || c == '\t')
#define SKIPWHITESPACE(c, f)	while ((c = getc(f))==' ' || c=='\t'); ungetc(c,f);
#define USRINCLUDE		"/usr/include/"
#define USRINCLUDECC		"/usr/include/CC/"

/*
 * Include file state
 */
#define NOTFOUND		0	/* not found anywhere */
#define EXTERNAL		1	/* not found in current directory */
#define INTERNAL		2	/* found in current directory */
#define FROMRULE		3	/* derived from tranformation rule */
#define SYSTEM			4	/* a system header file */

static char SYSINCLUDE[PATHSIZE];	/* /usr/include pathname buffer */
static char SYSINCLUDECC[PATHSIZE];	/* /usr/include/CC pathname buffer */
static int  SYSINCLUDELEN;		/* length of SYSINCLUDE */
/*
 * Include files are stored in hash tables by direct chaining (See
 * p. 134 in `The C Programming Language' by Kernighan and Ritchie).
 * Included include files are also added to a singly-linked list
 * attached to the hash table entry for the include file.
 */
static HASH *C_INCLUDETABLE   = NULL;	/* C include file hash table */
static HASH *CXX_INCLUDETABLE = NULL;	/* C++ include file hash table */
static HASH *F_INCLUDETABLE   = NULL;	/* Fortran include file hash table */
static HASH *P_INCLUDETABLE   = NULL;	/* Pascal include file hash table */
/*
 * Additional include directories are specified via the -I compiler
 * command line option. These directories are stored in singly-linked lists.
 * We also assume that the last look-up directory is "/usr/include".
 */
static SLIST *C_INCDIR;			/* C include directories */
static SLIST *CXX_INCDIR;		/* C++ include directories */
static SLIST *F_INCDIR;			/* Fortran include directories */
static SLIST *P_INCDIR;			/* Pascal include directories */

SLIST *EXTLIST;				/* external header file name list */
SLIST *SYSLIST;				/* system header file name list */

extern char *PGN;			/* program name */
extern int  SYSHDRS;			/* search system header files? */
extern HASH *MDEFTABLE;			/* macro definition table */

/*
 * addincdir() adds directories containing include files to the
 * appropriate singly-linked list. The pathnames to the directories
 * are derived from makefile macro definitions.
 */
void
addincdir()
{
	char *slappend();		/* append to singly-linked list */
	HASHBLK *htb;			/* hash table entry block */
	HASHBLK *htlookup();		/* find hash table entry */
	int cleanup();			/* remove temporary makefile and exit */
	void getI();			/* get include directory pathnames */

	/* initialize system include pathnames */
	initsysinclude();

	/* C CFLAGS macro */
	if ((htb = htlookup(MCFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, C_INCDIR);
	if (slappend(SYSINCLUDE, C_INCDIR) == NULL)
		cleanup();
	
	/* C++ CXXFLAGS macro */
	if ((htb = htlookup(MCXXFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, CXX_INCDIR);

	/* C++ C++FLAGS macro */
	if ((htb = htlookup(MCPXFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, CXX_INCDIR);

	/* C++ CCFLAGS macro */
	if ((htb = htlookup(MCCFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, CXX_INCDIR);

	if (slappend(SYSINCLUDECC, CXX_INCDIR) == NULL ||
	    slappend(SYSINCLUDE,   CXX_INCDIR) == NULL)
		cleanup();

	/* Fortran FFLAGS macro */
	if ((htb = htlookup(MFFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, F_INCDIR);
	if (slappend(SYSINCLUDE, F_INCDIR) == NULL)
		cleanup();

	/* Pascal PFLAGS macro */
	if ((htb = htlookup(MPFLAGS, MDEFTABLE)) != NULL)
		getI(htb->h_key, htb->h_def, P_INCDIR);
	if (slappend(SYSINCLUDE, P_INCDIR) == NULL)
		cleanup();
}



/*
 * findinclude() tries to find the pathname of an include file. Returns
 * integer INTERNAL if found in the current directory, EXTERNAL if found
 * somewhere else, FROMRULE if derived from a transformation rule,
 * SYSTEM if a system header file, otherwise NOTFOUND.  The pathname
 * is copied into incpath.
 */
#define LOCALDIR(f)    (strchr(f, _PSC) == NULL)
#define ISYSINCLUDE(f) (strncmp(f, SYSINCLUDE, SYSINCLUDELEN) == 0)
#define INCLUDETYPE(f) (LOCALDIR(f) ? INTERNAL : (ISYSINCLUDE(f) ? SYSTEM : EXTERNAL))

findinclude(incpath, incname, lastname, type)
	char *incpath;			/* pathname receiving buffer */
	register char *incname;		/* include file name */
	char *lastname;			/* file that includes incname */
	int type;			/* file type */
{
	register char *pp;		/* include file path pointer */
	char *optpath();		/* optimize pathname */
	char *pathcat();		/* pathname concatenation */
	char *pathhead();		/* remove pathname tail */
	char *strpcpy();		/* string copy and update pointer */
	int applyrule();		/* apply transformation rules */
	SLBLK *slb;			/* singly-linked list block */
	SLIST *slist;			/* include directory list pointer */

	/*
	 * look for an absolute include file name
	 */
	if (*incname == '/')
		{
		strcpy(incpath, incname);
		return(FILEXIST(incpath) ? INCLUDETYPE(incpath) : NOTFOUND);
		}

	/*
	 * search the current include directory for an #include file
	 * whose name is enclosed in " ", or see if it can be generated
	 * by a transformation rule in the current working directory.
	 */
	if (*incname != '<')
		{
		if (LOCALDIR(lastname))
			{
			if (LOCALDIR(incname))
				{
				if (applyrule(incname, incpath) == YES)
					return(FROMRULE);
				}
			strcpy(incpath, incname);
			if (FILEXIST(incpath))
				return(INCLUDETYPE(incpath));
			}
		else	{
			strcpy(incpath, lastname);
			pathcat(incpath, pathhead(incpath), incname);
			optpath(incpath);
			if (FILEXIST(incpath))
				return(INCLUDETYPE(incpath));
			}
		}

	/*
	 * search directory list
	 */
	switch (type)
		{
		case INCLUDE_C:
			slist = C_INCDIR;
			break;
		case INCLUDE_CXX:
			slist = CXX_INCDIR;
			break;
		case INCLUDE_FORTRAN:
			slist = F_INCDIR;
			break;
		case INCLUDE_PASCAL:
			slist = P_INCDIR;
			break;
		}
	for (slb = slist->head; slb != NULL; slb = slb->next)
		{
		pp = strpcpy(incpath, slb->key);
		if (*incname == '<')
			{
			pp = strpcpy(pp, incname+1);
			pp[-1] = '\0';
			}
		else	{
			strcpy(pp, incname);
			}
		optpath(incpath);
		if (FILEXIST(incpath))
			return(INCLUDETYPE(incpath));
		}

	return(NOTFOUND);
}



/*
 * getI() appends include directories found via the -I compiler option to
 * a singly linked list.
 */
void
getI(mnam, mdef, slist)
	char *mnam;			/* compiler options macro name */
	char *mdef;			/* compiler options macro definition */
	SLIST *slist;			/* singly-linked list */
{
	char *getoption();		/* get next token */
	char incpath[PATHSIZE];		/* include directory pathname buffer */
	char *slappend();		/* append to singly-linked list */
	int cleanup();			/* remove temporary makefile and exit */

	while ((mdef = getoption(incpath, mdef, "-I")) != NULL)
		{
		if (*incpath == '\0')
			{
			warns("missing include directory in %s macro definition", mnam);
			break;
			}
		else	{
			strcat(incpath, PATHSEP);
			if (slappend(incpath, slist) == NULL)
				cleanup();
			}
		}
}



/*
 * getinclude() fetchs an include file name from a line of source code.
 * /usr/include '<' and '>' delimiters remain with the filename to
 * distinguish it from an include file in a local directory. Returns
 * NO if syntax error, otherwise YES.
 */
getinclude(incname, curname, lineno, ifp)
	char *curname;			/* current file name */
	char *incname;			/* include file name receiving buffer */
	int lineno;			/* current line number */
	register FILE *ifp;		/* input stream */
{
	register char *ip;		/* include file name buffer pointer */
	register int c;			/* current character */

	SKIPWHITESPACE(c, ifp);
	for (ip = incname; (c = getc(ifp)) != EOF; ip++)
		{
		*ip = c;
		if (c == '\n' || c == '\t' || c == ' ' ||
		    c == ';'  || c == ','  || c == '$' )
			{
			ungetc(c, ifp);
			break;
			}
		}
	*ip = '\0';
	if ((*incname == '<'  && ip[-1] != '>')  ||
	    (*incname == '\"' && ip[-1] != '\"') ||
	    (*incname == '\'' && ip[-1] != '\'') ||
	    (*incname == '('  && ip[-1] != ')'))
		{
		fprintf(stderr,
			"%s: \"%s\", line %d: bad include syntax for %s\n",
			PGN, curname, lineno, incname);
		return(NO);
		}
	if (*incname == '\"' || *incname == '\'' || *incname == '(')
		{
		ip[-1] = '\0';
		ip = incname + 1;
		while (*incname++ = *ip++)
			continue;
		}
	return(YES);
}



/*
 * inclink() stores a pointer to a hash table block (which contains
 * include file information) somewhere. Returns a pointer to the somewhere,
 * or calls cleanup() if out of memory.
 */
INCBLK *
inclink(htb)
	HASHBLK *htb;			/* hash table block pointer to save */
{
	char *malloc();			/* memory allocator */
	INCBLK *iblk;			/* pointer to new include chain block */
	int cleanup();			/* remove temporary makefile and exit */

	if ((iblk = (INCBLK *) malloc(sizeof(INCBLK))) == NULL)
		{
		nocore();
		cleanup();
		}
	iblk->i_loop = NO;
	iblk->i_hblk = htb;
	iblk->i_next = NULL;
	return(iblk);
}



/*
 * instalinclude() adds an include file name to the appropriate include
 * file hash table. Returns a pointer to the hash table block, or calls
 * cleanup() if out of memory.
 */
HASHBLK *
instalinclude(incname, incpath, type)
	char *incname;			/* name of include file */
	char *incpath;			/* path to include file */
	int type;			/* type of source file */
{
	HASH *htinit();			/* initialize hash table */
	HASHBLK *htb;			/* hash table block */
	HASHBLK *htinstall();		/* install hash table entry */
	int cleanup();			/* remove temporary makefile and exit */
	int ilen;			/* include path length */

	ilen = strlen(incpath);
	switch (type)
		{
		case INCLUDE_C:
			if (C_INCLUDETABLE == NULL)
				{
				C_INCLUDETABLE = htinit(INCLUDETABLESIZE);
				}
			htb = htinstall(incname, incpath, ilen, C_INCLUDETABLE);
			break;
		case INCLUDE_CXX:
			if (CXX_INCLUDETABLE == NULL)
				{
				CXX_INCLUDETABLE = htinit(INCLUDETABLESIZE);
				}
			htb = htinstall(incname, incpath, ilen, CXX_INCLUDETABLE);
			break;
		case INCLUDE_FORTRAN:
			if (F_INCLUDETABLE == NULL)
				{
				F_INCLUDETABLE = htinit(INCLUDETABLESIZE);
				}
			htb = htinstall(incname, incpath, ilen, F_INCLUDETABLE);
			break;
		case INCLUDE_PASCAL:
			if (P_INCLUDETABLE == NULL)
				{
				P_INCLUDETABLE = htinit(INCLUDETABLESIZE);
				}
			htb = htinstall(incname, incpath, ilen, P_INCLUDETABLE);
			break;
		default:
			htb = NULL;
			break;
		}
	if (htb == NULL)
		cleanup();
	return(htb);
}



/*
 * lookupinclude() returns a pointer to an include hash table block
 * corresponding to incname and type. Returns null if not found.
 */
HASHBLK *
lookupinclude(incname, type)
	char *incname;			/* name of include file */
	int type;			/* type of source file */
{
	HASH *includetable;		/* include file hash table */
	HASHBLK *htlookup();		/* find hash table entry */

	switch (type)
		{
		case INCLUDE_C:
			includetable = C_INCLUDETABLE;
			break;
		case INCLUDE_CXX:
			includetable = CXX_INCLUDETABLE;
			break;
		case INCLUDE_FORTRAN:
			includetable = F_INCLUDETABLE;
			break;
		case INCLUDE_PASCAL:
			includetable = P_INCLUDETABLE;
			break;
		default:
			includetable = NULL;
			break;
		}
	return((includetable == NULL) ? NULL : htlookup(incname, includetable));
}



/*
 * mkdepend() creates include file dependencies for object files and installs
 * them to dependency list dlp. Returns a pointer to the dependency list.
 */
DLIST *
mkdepend()
{
	extern SLIST *SRCLIST;		/* source file name list */
	char *suffix;			/* suffix pointer */
	DLBLK *dlappend();		/* append dependency list */
	DLIST *dlinit();		/* initialize dependency list */
	DLIST *dlist;			/* dependency list */
	INCBLK *ibp;			/* pointer to chain of include files */
	INCBLK *readC();		/* read C include-style files */
	INCBLK *readF();		/* read Fortran include-style files */
	INCBLK *readP();		/* read Pascal include-style files */
	int cleanup();			/* remove temporary makefile and exit */
	int lookuptypeofinclude();	/* look up the brand of include */
	int slsort();			/* sort singly-linked list */
	int type;			/* source file type */
	SLBLK *lbp;			/* list block pointer */
	SLIST *slinit();		/* initialize singly-linked list */
	void addincdir();		/* add to list of include directories */
	void rmprinttag();		/* remove "already printed" tags */

	/* initialize include file look-up lists */
	C_INCDIR   = slinit();
	CXX_INCDIR = slinit();
	F_INCDIR   = slinit();
	P_INCDIR   = slinit();

	/* add additional include directories */
	addincdir();

	/* initialize external and system header file name lists */
	EXTLIST = slinit();
	SYSLIST = slinit();

	/* initialize dependency list */
	dlist = dlinit();

	for (lbp = SRCLIST->head; lbp != NULL; lbp = lbp->next)
		{
		suffix = strrchr(lbp->key, '.');
		type = lookuptypeofinclude(++suffix);
		switch (type)
			{
			case INCLUDE_C:
			case INCLUDE_CXX:
				ibp = readC(lbp->key, 0, lbp->key, type);
				break;
			case INCLUDE_FORTRAN:
				ibp = readF(lbp->key, 0, lbp->key, type);
				break;
			case INCLUDE_PASCAL:
				ibp = readP(lbp->key, 0, lbp->key, type);
				break;
			case INCLUDE_NONE:
				ibp = NULL;
				break;
			}
		if (ibp != NULL)
			{
			if (dlappend(type, lbp, ibp, dlist) == NULL)
				cleanup();
			}
		}
	if (slsort(strcmp, EXTLIST) == NO || slsort(strcmp, SYSLIST) == NO)
		cleanup();
	return(dlist);
}



/*
 * notfound() prints a "can't find" filename error message.
 */
void
notfound(curname, lineno, incname)
	char *curname;			/* current file name */
	char *incname;			/* name of include file */
	int lineno;			/* current line number */
{
	if (PGN != NULL && *PGN != '\0')
		{
		fprintf(stderr, "%s: ", PGN);
		}
	if (*incname == '<')
		{
		fprintf(stderr, "\"%s\", line %d: can't find %s\n",
			curname, lineno, incname);
		}
	else	{
		fprintf(stderr, "\"%s\", line %d: can't find \"%s\"\n",
			curname, lineno, incname);
		}
}



/*
 * readC() searches C files for included files. Returns a pointer to
 * the chain of include files installed or found in the include file
 * hash table, or null if no include files found.
 */
INCBLK *
readC(lastfile, lastline, curname, type)
	char *lastfile;			/* parent file name */
	int lastline;			/* current line in parent file */
	char *curname;			/* current file name */
	int type;			/* file type */
{
	register char *p;		/* include string pointer */
	register FILE *ifp;		/* input file stream */
	register int c;			/* current character */
	char incname[PATHSIZE];		/* name of include file */
	char incpath[PATHSIZE];		/* path to include file */
	char *slappend();		/* append pathname to list */
	FILE *fopen();			/* open file */
	HASHBLK *ftb;			/* fromrule hash table entry block */
	HASHBLK *htb;			/* hash table entry block */
	HASHBLK *instalinclude();	/* install include name in hash table */
	HASHBLK *lookupinclude();	/* look up include in hash table */
	INCBLK *i_head = NULL;		/* head of include chain */
	INCBLK *i_tail = NULL;		/* tail of include chain */
	INCBLK *inclink();		/* link include file hash blocks */
	int cleanup();			/* remove temporary makefile and exit */
	int findinclude();		/* locate include file */
	int getinclude();		/* get include name from input line */
	int inctype;			/* origin of include file */
	int lineno = 1;			/* current line number */
	void notfound();		/* print "can't find" filename msg */

	if ((ifp = fopen(curname, "r")) == NULL)
		{
		if (lastline > 0)
			fprintf(stderr, "%s: \"%s\", line %d: ", PGN,
				lastfile, lastline);
		else
			fprintf(stderr, "%s: ", PGN);
		perror(curname);
		return(NULL);
		}
	while ((c = getc(ifp)) != EOF)
		{
		if (ISWHITESPACE(c))
			continue;
		if (c != '#')
			goto nextline;
		SKIPWHITESPACE(c, ifp);
		for (p = "include"; (c = getc(ifp)) == *p && *p != '\0' ; p++)
			continue;
		if (*p != '\0')
			goto nextline;
		ungetc(c, ifp);
		if (getinclude(incname, curname, lineno, ifp) == NO)
			goto nextline;
		if ((htb = lookupinclude(incname, type)) == NULL)
			{
			inctype = findinclude(incpath, incname, curname, type);
			if (inctype == INTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				}
			else if (inctype == SYSTEM && SYSHDRS == YES)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, SYSLIST) == NULL)
					cleanup();
				}
			else if (inctype == SYSTEM && SYSHDRS == NO)
				{
				goto nextline;
				}
			else if (inctype == EXTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, EXTLIST) == NULL)
					cleanup();
				}
			else if (inctype == FROMRULE)
				{
				htb = instalinclude(incname, incname, type);
				ftb = instalinclude(incpath, incpath, type);
				}
			else	{
				notfound(curname, lineno, incname);
				goto nextline;
				}

			/* look for nested include files */
			htb->h_sub = readC(curname, lineno, incpath, type);

			if (inctype == FROMRULE)
				ftb->h_sub = htb->h_sub;
			}
		if (i_tail == NULL)
			{
			i_head = i_tail = inclink(htb);
			}
		else	{
			i_tail = i_tail->i_next = inclink(htb);
			}
nextline:	while (c != '\n' && c != EOF)
			c = getc(ifp);
		lineno++;
		}
	fclose(ifp);
	return(i_head);
}



/*
 * readF() searches Fortran files for included files. Returns a pointer
 * to the chain of include files installed or found in the include file
 * hash table, or null if no include files found.
 */
INCBLK *
readF(lastfile, lastline, curname, type)
	char *lastfile;			/* parent file name */
	int lastline;			/* current line in parent file */
	char *curname;			/* current file name */
	int type;			/* file type */
{
	register char *p;		/* include string pointer */
	register FILE *ifp;		/* input file stream */
	register int c;			/* current character */
	char incname[PATHSIZE];		/* name of include file */
	char incpath[PATHSIZE];		/* path to include file */
	char *slappend();		/* append pathname to list */
	FILE *fopen();			/* open file */
	HASHBLK *ftb;			/* fromrule hash table entry block */
	HASHBLK *htb;			/* hash table entry block */
	HASHBLK *instalinclude();	/* install include name in hash table */
	HASHBLK *lookupinclude();	/* look up include in hash table */
	INCBLK *i_head = NULL;		/* head of include chain */
	INCBLK *i_tail = NULL;		/* tail of include chain */
	INCBLK *inclink();		/* link include file hash blocks */
	int cleanup();			/* remove temporary makefile and exit */
	int findinclude();		/* locate include file */
	int getinclude();		/* get include name from input line */
	int inctype;			/* origin of include file */
	int lineno = 1;			/* current line number */
	void notfound();		/* print "can't find" filename msg */

	if ((ifp = fopen(curname, "r")) == NULL)
		{
		if (lastline > 0)
			fprintf(stderr, "%s: \"%s\", line %d: ", PGN,
				lastfile, lastline);
		else
			fprintf(stderr, "%s: ", PGN);
		perror(curname);
		return(NULL);
		}
	while ((c = getc(ifp)) != EOF)
		{
		if (c == 'c' || c == 'C' || c == '*' || c == '\n')
			goto nextline;
		while ((c = getc(ifp)) == ' ' || c == '\t' || c == '#' || c == '$')
			continue;
		for (p = "include"; *p == TOLOWER(c) && *p != '\0'; p++)
			c = getc(ifp);
		if (*p != '\0')
			goto nextline;
		ungetc(c, ifp);
		if (getinclude(incname, curname, lineno, ifp) == NO)
			goto nextline;
		if ((htb = lookupinclude(incname, type)) == NULL)
			{
			inctype = findinclude(incpath, incname, curname, type);
			if (inctype == INTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				}
			else if (inctype == SYSTEM && SYSHDRS == YES)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, SYSLIST) == NULL)
					cleanup();
				}
			else if (inctype == SYSTEM && SYSHDRS == NO)
				{
				goto nextline;
				}
			else if (inctype == EXTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, EXTLIST) == NULL)
					cleanup();
				}
			else if (inctype == FROMRULE)
				{
				htb = instalinclude(incname, incname, type);
				ftb = instalinclude(incpath, incpath, type);
				}
			else	{
				notfound(curname, lineno, incname);
				goto nextline;
				}

			/* look for nested include files */
			htb->h_sub = readF(curname, lineno, incpath, type);

			if (inctype == FROMRULE)
				ftb->h_sub = htb->h_sub;
			}
		if (i_tail == NULL)
			{
			i_head = i_tail = inclink(htb);
			}
		else	{
			i_tail = i_tail->i_next = inclink(htb);
			}
nextline:	while (c != '\n' && c != EOF)
			c = getc(ifp);
		lineno++;
		}
	fclose(ifp);
	return(i_head);
}



/*
 * readP() searches Pascal files for included files. Returns a pointer
 * to the chain of include files installed or found in the include file
 * hash table, or null if no include files found.
 */
INCBLK *
readP(lastfile, lastline, curname, type)
	char *lastfile;			/* parent file name */
	int lastline;			/* current line in parent file */
	char *curname;			/* current file name */
	int type;			/* file type */
{
	register char *p;		/* include string pointer */
	register FILE *ifp;		/* input file stream */
	register int c;			/* current character */
	char incname[PATHSIZE];		/* name of include file */
	char incpath[PATHSIZE];		/* path to include file */
	char *slappend();		/* append pathname to list */
	FILE *fopen();			/* open file */
	HASHBLK *ftb;			/* fromrule hash table entry block */
	HASHBLK *htb;			/* hash table entry block */
	HASHBLK *instalinclude();	/* install include name in hash table */
	HASHBLK *lookupinclude();	/* look up include in hash table */
	INCBLK *i_head = NULL;		/* head of include chain */
	INCBLK *i_tail = NULL;		/* tail of include chain */
	INCBLK *inclink();		/* link include file hash blocks */
	int cleanup();			/* remove temporary makefile and exit */
	int findinclude();		/* locate include file */
	int getinclude();		/* get include name from input line */
	int inctype;			/* origin of include file */
	int lineno = 1;			/* current line number */
	void notfound();		/* print "can't find" filename msg */

	if ((ifp = fopen(curname, "r")) == NULL)
		{
		if (lastline > 0)
			fprintf(stderr, "%s: \"%s\", line %d: ", PGN,
				lastfile, lastline);
		else
			fprintf(stderr, "%s: ", PGN);
		perror(curname);
		return(NULL);
		}
	while ((c = getc(ifp)) != EOF)
		{
		if (ISWHITESPACE(c))
			continue;
		if (c != '#' && c != '$')
			goto nextline;
		while ((c = getc(ifp)) == ' ' || c == '\t')
			continue;
		for (p = "include"; *p == TOLOWER(c) && *p != '\0'; p++)
			c = getc(ifp);
		if (*p != '\0')
			goto nextline;
		ungetc(c, ifp);
		if (getinclude(incname, curname, lineno, ifp) == NO)
			goto nextline;
		if ((htb = lookupinclude(incname, type)) == NULL)
			{
			inctype = findinclude(incpath, incname, curname, type);
			if (inctype == INTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				}
			else if (inctype == SYSTEM && SYSHDRS == YES)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, SYSLIST) == NULL)
					cleanup();
				}
			else if (inctype == SYSTEM && SYSHDRS == NO)
				{
				goto nextline;
				}
			else if (inctype == EXTERNAL)
				{
				htb = instalinclude(incname, incpath, type);
				if (slappend(incpath, EXTLIST) == NULL)
					cleanup();
				}
			else if (inctype == FROMRULE)
				{
				htb = instalinclude(incname, incname, type);
				ftb = instalinclude(incpath, incpath, type);
				}
			else	{
				notfound(curname, lineno, incname);
				goto nextline;
				}

			/* look for nested include files */
			htb->h_sub = readP(curname, lineno, incpath, type);

			if (inctype == FROMRULE)
				ftb->h_sub = htb->h_sub;
			}
		if (i_tail == NULL)
			{
			i_head = i_tail = inclink(htb);
			}
		else	{
			i_tail = i_tail->i_next = inclink(htb);
			}
nextline:	while (c != '\n' && c != EOF)
			c = getc(ifp);
		lineno++;
		}
	fclose(ifp);
	return(i_head);
}

initsysinclude()
{
	HASHBLK *htb;			/* hash table entry block */
	HASHBLK *htlookup();		/* find hash table entry */

#ifdef _HasCompileSysType
	if ((htb = htlookup(MCOMPILESYSTYPE, MDEFTABLE)) != NULL)
		{
	        sprintf(SYSINCLUDE, "/%s", htb->h_def);
	        sprintf(SYSINCLUDECC, "/%s", htb->h_def);
		}
#endif

        strcat(SYSINCLUDE, USRINCLUDE);
        strcat(SYSINCLUDECC, USRINCLUDECC);
	SYSINCLUDELEN = strlen(SYSINCLUDE)-1; /* length - last '/' */
}