[net.sources] make depend

kim@enea.UUCP (Kim Walden) (04/10/85)

In response to all requests for my dependency generating program,
which uses only source files as basis for generation,
(general method described in: K. Walden, "Automatic Generation of
Make Dependencies", Softw. Pract. & Exper., vol. 14(6), 575-585,
June 1984), I am now posting it to net.sources, in the two following
parts.

It was developed for 4.2bsd, and I did not pay any special attention
to portability. System V users must do the usual name changes
CFLAGS="-Dindex=strchar -Drindex=strrchar" etc.

The program deals correctly with included generated files, provided
that the include statements are recognizable in the corresponding
source files, and standard suffix conventions are used.

If conditional includes, like 

#ifdef KERNEL & !defined(LOCORE)
#include "foo"
#else
#include "bar"

appear in the files, it may sometimes be possible to extend the recognition
part so that only the relevant include statements are extracted (the
distributed program uses only grep), but in the general case, only the
C preprocessor may resolve the conditions correctly, and therefore one
may be forced to use the newly added -M option of cpp instead.

But then again, cpp -M cannot handle included generated files correctly.
-- 
	Kim Walden
	ENEA DATA Sweden

	UUCP:	{seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim
	ARPA:	decvax!mcvax!enea!kim@berkeley.arpa
		mcvax!enea!kim@seismo.arpa

kim@enea.UUCP (Kim Walden) (04/10/85)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	tool
# This archive created: Wed Apr 10 14:06:20 1985
mkdir tool
chdir tool
sed 's/^XX//' << \SHAR_EOF > READ_ME
XX*******************************************************************
XX**                                                               **
XX**  This distribution implements the algorithm described in      **
XX**                                                               **
XX**      K. Walden, "Automatic Generation of Make Dependencies",  **
XX**      Softw. Practice & Exper., vol. 14, no. 6, June 1984      **
XX**                                                               **
XX**  Copyright (c) 1983  Kim Walden                               **
XX**      ENEA DATA, Sweden and                                    **
XX**      SYSLAB, Department of Computer Science,                  **
XX**      University of Stockholm, Sweden.                         **
XX**                                                               **
XX**  The software may be used and copied freely,                  **
XX**      provided that proper credit is given to the originator   **
XX**      by including this text label in each copy.               **
XX**                                                               **
XX*******************************************************************
XX
XX
XX
XXSOURCES			FUNCTION
XX
XXMakefile		Make script to build the programs.
XXmakedep.c		Main program for extracting include statements
XX			and pipe them to makenorm and depend.
XXmakenorm.y		Include statement normalizer.
XXnormscan.l		Scanner for the normalizer.
XXdepend.y		Main dependency generator.
XXdepscan.l		Scanner for the dependency generator.
XXmpath.c			File name path reduction routine.
XXerror.c			Error handling routine.
XX
XXman			Manuals subdirectory
XXtest			Subdirectory structure with test files.
XX
XX
XX
XX
XXThe programs should be built invoking the Makefile, and the tool
XXdirectory added to the command search path, so the programs can be
XXfound when running the test below.
XX
XXWhen make is invoked on the test directory test/proc, the test
XXexample in the above SP & E paper is run, and the output should be
XXthe same as the contents of the file Dep.mk.
XX
XXMakedep and makenorm extract and normalize include statements that
XXare directed to the C preprocessor.
XXThese programs must be modified if include statements of other
XXlanguages are to be handled, unless the include syntax and semantics
XXhappen to be the same, while depend can be used unchanged.
XX
XXA general recommendation for Berkeley UNIX users is to get hold of
XXthe augmented version of make available under AT & T System III/V,
XXwhich has an include facility.
XXAll generated dependencies can then be put in a separate file,
XXwhich is made part of the ordinary make dependency graph.
XX
XXPorting the augmented make to run under Berkeley UNIX is not very
XXdifficult, and mostly has to do with different formats of archive
XXfiles.
SHAR_EOF
if test 2713 -ne "`wc -c READ_ME`"
then
echo shar: error transmitting READ_ME '(should have been 2713 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > Makefile
XXCFLAGS= -O -s
XX
XXOBJ1= mpath.o 
XXOBJ2= error.o
XX
XXall: makedep makenorm depend 
XX
XXmakedep: makedep.o $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ2) -o $@
XX
XXmakenorm: makenorm.o $(OBJ1) $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ1) $(OBJ2) -ll -o $@
XX
XXdepend: depend.o $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ2) -ll -o $@
XX
XXmakenorm.o: normscan.c
XXdepend.o: depscan.c
XX
XXclean:
XX	rm *.o
XX	rm makedep
XX	rm makenorm makenorm.c normscan.c
XX	rm depend depend.c depscan.c
XX	rm man/*.man
XX
XX.y.o:
XX	$(YACC) $(YFLAGS) $<
XX	@mv -f y.tab.c $*.c
XX	$(CC) $(CFLAGS) -c $*.c
XX
XX.y.c:
XX	$(YACC) $(YFLAGS) $<
XX	@mv -f y.tab.c $@
XX
XX.l.o:
XX	$(LEX) $(LFLAGS) $<
XX	@mv -f lex.yy.c $*.c
XX	$(CC) $(CFLAGS) -c $*.c
XX
XX.l.c:
XX	$(LEX) $(LFLAGS) $<
XX	@mv -f lex.yy.c $@
SHAR_EOF
if test 688 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 688 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > depend.y
XX%{
XX/* -- Make include dependency generator
XX *
XX * $File: depend.y  1.13  1985-03-29  14:06:29 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This program implements part of the algorithm described in
XX *      	K. Walden, "Automatic Generation of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX * $Log:	depend.y,v $
XX * 
XX * Revision 1.13  1985-03-29  14:06:29  kim
XX * New source format
XX * 
XX * Revision 1.12  1985-03-08  01:16:37  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.11  1985-02-25  19:40:21  kim
XX * Path reduction moved to earlier stage
XX * 
XX * Revision 1.10  1985-02-19  11:19:59  kim
XX * New default include rules
XX * 
XX * Revision 1.9  1985-02-18  14:23:55  kim
XX * New error handling
XX * 
XX * Revision 1.8  1985-02-14  13:59:52  kim
XX * Changed rules options to -r/-R
XX * 
XX * Revision 1.7  1985-02-14  01:53:19  kim
XX * Converted to RCS format
XX * 
XX * Revision 1.4  1983-10-06  19:50:16  kim
XX * Allow empty include line input
XX * 
XX * Revision 1.3  1983-07-20  19:50:00  kim
XX * Closer to algorithm in SYSLAB Report No. 19 (June 1983)
XX * 
XX * Revision 1.2  1983-02-22  19:49:51  kim
XX * First version with include rules
XX * 
XX * Revision 1.1  1982-12-15  19:49:47  kim
XX * Initial revision
XX */
XX%}
XX
XX%token SPACE RULSEP INCSEP PATH SUFF
XX%{
XX# define PREF    struct pref
XX# define SUF     struct suf
XX# define INCFILE struct incfile
XX# define LHSFILE struct lhsfile
XX# define NAME    struct filename
XX# define OUTSIZ  10
XX# define PATHSIZ 100
XX# define DIRSIZ  14
XX# define LINSIZ  256
XX# define PHASHL  503
XX# define LINE	 80
XX# define INCLUDED  1
XX# define CNULL '\0'
XX# define KOL ':'
XX# define EQU '='
XX# define RULES	 ".o: .c .p .f; .c= .y .l .q; .h= .y"
XX
XX# include <stdio.h>
XX# include <strings.h>
XX
XXstatic char usage[]= "Usage: depend [-1] [-rfile] [-Rrules]";
XX
XX/* File name prefixes
XX */
XXPREF
XX{	
XX	PREF	*	nexthash;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name suffixes:
XX *
XX * If the suffix occurs in the rhs of a rule,
XX * the output file suffix and rule type
XX * (KOL or EQU) is recorded.
XX */
XXSUF
XX{
XX	SUF	*	next,
XX		*	out[OUTSIZ];
XX	char		name[DIRSIZ+1];
XX	int		top,
XX			rule;
XX};
XX
XX/* List of files included by a given file.
XX */
XXINCFILE
XX{
XX	INCFILE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX/* A node for each file found in the lhs of some include statement.
XX * The transfer rules are successively applied to the suffix
XX * before the file is inserted.
XX * Reference to list of included files.
XX */
XXLHSFILE
XX{
XX	LHSFILE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX	INCFILE	*	ic;
XX	int		state;
XX};
XX
XXNAME
XX{
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XXstruct
XX{
XX	SUF	*	sf;
XX	LHSFILE *	lf;
XX} first;
XX
XX
XXextern char	*	calloc();
XXvoid			yyerror();
XX
XXstatic NAME		getname(),
XX			lhs,
XX			rhs;
XXstatic LHSFILE	*	nodelf(),
XX		*	thislf;
XXstatic PREF	*	nodepf(),
XX		*	phash[PHASHL];
XXstatic SUF	*	nodesf(),
XX		*	lsuf,
XX		*	rsuf;
XXstatic char	*	alloc(),
XX		*	rulstring,
XX		*	yystring;
XXstatic char		line[LINSIZ];
XXstatic void		printdep(),
XX			copyinc(),
XX			nodeic();
XXstatic int		hash(),
XX			lineno,
XX			rule,
XX			onedep;
XX
XX# include "depscan.c"
XX
XXmain(argc, argv)
XX	int		argc;
XX	char	*	argv[];
XX{
XX	char		rulbuf[LINSIZ];
XX
XX	setprogname(argv[0]);
XX	rulstring = rulbuf;
XX	strcpy(rulbuf, RULES);
XX
XX	while (argc > 1 && argv[1][0] == '-')
XX	{
XX		switch (argv[1][1])
XX		{
XX		 case 'r':
XX			strcat(rulbuf, "; ");
XX			strcat(rulbuf, argv[1]+2);
XX			break;
XX
XX		 case 'R':
XX			rulstring = argv[1]+2;
XX			break;
XX
XX		 case '1':
XX			onedep++;
XX			break;
XX
XX		 default:
XX			fatal("unknown option %s", argv[1]);
XX		}
XX
XX		argv++;
XX		argc--;
XX	}
XX
XX	if (argc != 1)
XX		fatalmesg(usage);
XX
XX	yystring = rulstring;
XX	BEGIN rules;
XX
XX	first.lf = NULL;
XX	yyparse();
XX	if (first.lf)
XX		printdep();
XX	exit(0);
XX}
XX%}
XX
XX%%
XX
XXaccept	:	rules includes
XX	;
XXrules	:	rule
XX	|	RULSEP rules
XX	|	rules RULSEP
XX	|	rules RULSEP rule
XX	;
XXrule	:	':' SPACE
XX			{   /* Lhs of inclusion rule, empty output suffix */
XX				lsuf = nodesf("");
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf ':' SPACE
XX			{   /* Lhs of inclusion rule */
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf '=' SPACE
XX			{   /* Lhs of transfer rule */
XX				rule = EQU;
XX			}
XX		rhssuf
XX	|	rule SPACE rhssuf
XX	;
XXlhssuf	:	SUFF
XX			{   /* Lhs of any rule */
XX				lsuf = nodesf(yytext);
XX			}
XX	;
XXrhssuf	:	SUFF
XX			{   /* Rhs of any rule */
XX				rsuf = nodesf(yytext);
XX				if (rsuf->rule && (rsuf->rule != EQU || rule != EQU))
XX				        fatal("ambiguous rules %s", rulstring);
XX				rsuf->rule = rule;
XX				if (rsuf->top >= OUTSIZ)
XX					fatal("to many parallel transfers %s", rulstring);
XX				rsuf->out[rsuf->top++] = lsuf;
XX			}
XX	;
XXincludes:
XX	|	includes INCSEP
XX	|	includes INCSEP include
XX	;
XXinclude	:	PATH
XX			{   /* Lhs of include statement:
XX			     *      Insert in lhsfile list.
XX			     */
XX				lhs = getname(yytext);
XX				thislf = nodelf(lhs.pf, lhs.sf);
XX			}
XX		SPACE '<' SPACE
XX		PATH
XX			{   /* Rhs of include statement:
XX			     *      Append to include list of lhsfile.
XX			     */
XX				rhs = getname(yytext);
XX				nodeic(thislf, rhs.pf, rhs.sf);
XX			}
XX	;
XX
XX%%
XX
XXvoid
XXyyerror(s)
XX	char	*	s;
XX{
XX	if (yystring)
XX		fatal("%s rules: %s", s, rulstring);
XX	else
XX		fatal("%s near line %d: %s", s, lineno, line);
XX}
XX
XX/* Go through lhsfile list and print implied Make dependencies.
XX */
XXstatic void
XXprintdep()
XX{
XX	LHSFILE	*	lf,
XX		*	lf2;
XX	SUF	*	sf;
XX	INCFILE	*	ic;
XX	int		i;
XX
XX    /* Apply transfer rules to the LHS suffixes.
XX     * If there are more than one output suffix,
XX     * make a new LHS node with a copy of the include list for each of them.
XX     *
XX     * Since the new nodes are inserted at the end of the LHS list,
XX     * they will be dealt with again, later in the for-loop.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX		while (lf->sf->rule == EQU)
XX		{
XX			for (i = 1; i < lf->sf->top; i++)
XX				copyinc(lf, nodelf(lf->pf, lf->sf->out[i]));
XX			
XX			lf->sf = lf->sf->out[0];
XX		}
XX
XX    /* Construct Transitive Closure.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX		for (lf2 = first.lf; lf2; lf2 = lf2->next)
XX			for (ic = lf2->ic; ic; ic = ic->next)
XX				if (ic->pf == lf->pf && ic->sf == lf->sf)
XX				{
XX					lf->state = INCLUDED;
XX					copyinc(lf, lf2);
XX					break;
XX				}
XX
XX    /* For each lhs file, apply inclusion rules
XX     * and generate Make dependencies.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX	{
XX		char	lhsdep[PATHSIZ+1], rhsdep[PATHSIZ+1];
XX		int	brk = 0;
XX
XX	    /* If the file was included in some other file,
XX	     * no separate output file will be generated for it.
XX	     * The corresponding dependencies have thus already
XX	     * been taken care of.
XX	     */
XX		if (lf->state == INCLUDED)
XX			continue;
XX
XX		sf = lf->sf;
XX
XX	    /* If the file was not included in any other file,
XX	     * and there is no inclusion rule for its suffix,
XX	     * the file is discarded.
XX	     */
XX		if (sf->rule != KOL)
XX			continue;
XX
XX		sprintf(lhsdep, "%s%s", lf->pf->path, sf->out[0]->name); 
XX		sprintf(line, "%s:", lhsdep); 
XX
XX		for (ic = lf->ic; ic; ic = ic->next)
XX		{
XX			sprintf(rhsdep, "%s%s", ic->pf->path, ic->sf->name);
XX
XX			if (strlen(line)+strlen(rhsdep)+1 > LINE || brk)
XX			{
XX				printf("%s\n", line);
XX				sprintf(line, "%s:", lhsdep); 
XX			}
XX			strcat(line, " ");
XX			strcat(line, rhsdep);
XX			brk = onedep;
XX		}
XX		printf("%s\n", line);
XX	}
XX}
XX
XX/* Copy entire include file list.
XX *
XX */
XXstatic void
XXcopyinc(from, to)
XX	LHSFILE *	from,
XX		*	to;
XX{
XX	INCFILE	*	ic;
XX
XX		for (ic = from->ic; ic; ic = ic->next)
XX			nodeic(to, ic->pf, ic->sf);
XX}
XX
XX/* Return file name.  
XX *
XX */
XXstatic NAME
XXgetname(path)
XX	char	*	path;
XX{
XX	NAME		nm;
XX	char	*	p;
XX	int		c;
XX
XX	if (strlen(path) > PATHSIZ)
XX		fatal("path too long: %s", path);
XX
XX	if ((p = rindex(path, '/')) == NULL)
XX		p = path;
XX
XX	if ((p = rindex(p, '.')) == NULL)
XX		p = path + strlen(path);
XX
XX	nm.sf = nodesf(p);
XX	c = *p;
XX	*p = CNULL;
XX	nm.pf = nodepf(path);
XX	*p = c;
XX
XX	return nm;
XX}
XX
XX/* Return suffix node.
XX * If the given suffix was not in the suffix list,
XX * allocate a new node.
XX */
XXstatic SUF *
XXnodesf(name)
XX	char	*	name;
XX{
XX	SUF	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.sf; node; prev = node, node = node->next)
XX		if (strcmp(name, node->name) == 0)
XX			return node;
XX
XX	node = (SUF *) alloc(sizeof(SUF), name);
XX	strcpy(node->name, name);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.sf = node;
XX
XX	return node;
XX}
XX
XX/* Return prefix node.
XX * If the given (reduced) path was not in the prefix list,
XX * allocate a new node.
XX */
XXstatic PREF *
XXnodepf(path)
XX	char	*	path;
XX{
XX	PREF	*	node,
XX		*	prevhash;
XX	int		h;
XX
XX	h = hash(path, PHASHL);
XX
XX	for (node = phash[h]; node; node = node->nexthash)
XX		if (strcmp(path, node->path) == 0)
XX			return node;
XX		else
XX			prevhash = node;
XX
XX	node = (PREF *) alloc(sizeof(PREF), path);
XX	strcpy(node->path, path);
XX
XX	if (phash[h])
XX		prevhash->nexthash = node;
XX	else
XX		phash[h] = node;
XX
XX	return node;
XX}
XX
XX/* Return lhsfile node.
XX * If the given lhsfile was not in the lhsfile list,
XX * allocate a new node.
XX */
XXstatic LHSFILE *
XXnodelf(pf, sf)
XX	PREF	*	pf;
XX	SUF	*	sf;
XX{
XX	LHSFILE *	node,
XX		*	prev;
XX
XX	for (prev = node = first.lf; node; prev = node, node = node->next)
XX		if (node->pf == pf && node->sf == sf)
XX			return node;
XX
XX	node = (LHSFILE *) alloc(sizeof(LHSFILE), line);
XX
XX	node->pf = pf;
XX	node->sf = sf;
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.lf = node;
XX
XX	return node;
XX}
XX
XX/* Add the given rhsfile to the include list
XX * of the given lhsfile,
XX * if it was not there already.
XX */
XXstatic void
XXnodeic(lf, pf, sf)
XX	LHSFILE	*	lf;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX{
XX	INCFILE *	node,
XX		*	prev;
XX
XX	if (sf->rule == EQU)
XX	   /* Must follow the Suffix Convention for Included Files.
XX	    */
XX		fatal("bad include file suffix %s%s < %s%s",
XX		   lf->pf->path, lf->sf->name, pf->path, sf->name);
XX		
XX	for (prev = node = lf->ic; node; prev = node, node = node->next)
XX		if (node->pf == pf && node->sf == sf)
XX			return;
XX
XX	if (pf == lf->pf && sf == lf->sf)
XX	{
XX		error("infinite recursion on %s%s - dependency ignored", pf->path, sf->name);
XX		return;
XX	}
XX
XX	node = (INCFILE *) alloc(sizeof(INCFILE), line);
XX	node->pf = pf;
XX	node->sf = sf;
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		lf->ic = node;
XX}
XX
XX/* Allocate a zero initialized node.
XX */
XXstatic char *
XXalloc(size, obj)
XX	char	*	obj;
XX{
XX	char	*	node;
XX
XX	if ((node = calloc(1, size)) == NULL)
XX		fatal("can't alloc: %s", obj);
XX
XX	return node;
XX}
XX
XX/* Hash a character string, and return the hash value
XX * modulo the given hash length.
XX */
XXstatic int
XXhash(p, hashl)
XX	char	*	p;
XX	int		hashl;
XX{
XX	register 	unsigned sum;
XX	register 	c;
XX
XX	sum = 0;
XX	while ((c = *p++) != 0)
XX	{
XX		if (sum & 01)
XX			sum = (sum >> 1) + 0x8000;
XX		else
XX			sum >>= 1;
XX		sum += c;
XX		sum &= 0xFFFF;
XX	}
XX	return sum % hashl;
XX}
SHAR_EOF
if test 10650 -ne "`wc -c depend.y`"
then
echo shar: error transmitting depend.y '(should have been 10650 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > makenorm.y
XX%{
XX/* -- Normalize include references
XX *
XX * $File: makenorm.y  1.8  1985-03-29  14:11:19 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This program implements part of the algorithm described
XX *      	in K. Walden, "Automatic Generation of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX *
XX * $Log:	makenorm.y,v $
XX * 
XX * Revision 1.8  1985-03-29  14:11:19  kim
XX * New source format
XX * 
XX * Revision 1.7  1985-03-21  09:31:11  kim
XX * Use sprintf in a System V compatible way
XX * 
XX * Revision 1.6  1985-03-08  01:18:35  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.5  1985-02-25  19:41:56  kim
XX * Added -a option for absolute directories
XX * 
XX * Revision 1.4  1985-02-20  11:53:09  kim
XX * Bug fix
XX * 
XX * Revision 1.3  1985-02-19  11:21:23  kim
XX * New default include rules
XX * 
XX * Revision 1.2  1985-02-18  14:24:15  kim
XX * New error handling
XX * 
XX * Revision 1.1  1985-02-16  18:57:07  kim
XX * Initial revision
XX */
XX%}
XX
XX%token SPACE RULSEP INCSEP PATH SUFF INCL QUOTE LPAR RPAR
XX%{
XX# define DIRLIST  struct dirlist
XX# define PREF     struct pref
XX# define SUF      struct suf
XX# define SOURCE   struct source
XX# define NAME     struct filename
XX# define PATHSIZ  100
XX# define DIRSIZ   14
XX# define LINSIZ   256
XX# define OUTSIZ   10
XX# define PHASHL   503
XX# define LINE	  80
XX# define EXACT    0
XX# define DERIVED  1
XX# define FORCE	  2
XX# define NOREDUCE 0
XX# define REDUCE   1
XX# define FALSE	  0
XX# define TRUE	  1
XX# define CNULL   '\0'
XX# define KOL     ':'
XX# define EQU     '='
XX# define RULES	 ".o: .c; .c= .y .l .q; .h= .y"
XX
XX# include <stdio.h>
XX# include <strings.h>
XX# include <sys/types.h>
XX# include <sys/stat.h>
XX
XXstatic char usage[]=
XX"Usage: makenorm [-rfile] [-Rrules] [-Ilist] [-alist] [-i] makedir sourcefiles";
XX
XX/* Directory lists
XX */
XXDIRLIST
XX{
XX	DIRLIST	*	next;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name prefixes   (including directory part)
XX */
XXPREF
XX{	
XX	PREF	*	nexthash;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name suffixes:
XX *
XX * If the suffix occurs in the rhs of a rule,
XX * the output file suffix and rule type
XX * (KOL or EQU) is recorded.
XX */
XXSUF
XX{
XX	SUF	*	next,
XX		*	out[OUTSIZ];
XX	char		name[DIRSIZ+1];
XX	int		top,
XX			rule;
XX};
XX
XX/* Declared sources:
XX *
XX * The transfer rules are successively applied
XX * to the suffix before a file is inserted.
XX */
XXSOURCE
XX{
XX	SOURCE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX/* File names
XX */
XXNAME
XX{
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX
XXstruct 
XX{
XX	SOURCE	*	so;		/* source list */
XX	SUF	*	sf;		/* suffix list */
XX	DIRLIST	*	idir, 		/* list of include directories */
XX		*	adir;		/* list of absolute directories */
XX} first;
XX
XXextern char	*	calloc(),
XX		*	mpath();
XXvoid			yyerror();
XXstatic PREF 	*	nodepf(),
XX		*	phash[PHASHL];	/* hash table for prefixes */
XXstatic SUF	*	nodesf(),
XX		*	lsuf,
XX		*	rsuf;
XXstatic NAME		getname(),
XX			lhs,
XX			rhs;
XXstatic char	*	alloc(),
XX		*	makedir,
XX		*	rulstring,
XX		*	yystring;
XXstatic char		line[LINSIZ];
XXstatic int		derived(),
XX			hash(),
XX			findso(),
XX			printcond(),
XX			lineno,
XX			rule,
XX			remote,
XX			sysflag;
XXstatic void		getdirlist(),
XX			nodedl(),
XX			printnorm();
XX
XX# include "normscan.c"
XX
XXmain(argc, argv)
XX	int		argc;
XX	char	*	argv[];
XX{
XX	char		rulbuf[LINSIZ];
XX
XX	setprogname(argv[0]);
XX	rulstring = rulbuf;
XX	strcpy(rulbuf, RULES);
XX	nodedl("/usr/include", &first.adir);
XX	sysflag = 0;
XX
XX	while (argc > 1 && argv[1][0] == '-')
XX	{
XX		switch (argv[1][1])
XX		{
XX		 case 'r':
XX			strcat(rulbuf, "; ");
XX			strcat(rulbuf, argv[1]+2);
XX			break;
XX
XX		 case 'R':
XX			rulstring = argv[1]+2;
XX			break;
XX
XX		 case 'i':
XX			sysflag++;
XX			break;
XX
XX		 case 'a':
XX		 case 'I':
XX			getdirlist(argv[1]);
XX			break;
XX
XX		 default:
XX			error("unknown option %s", argv[1]);
XX			fatalmesg(usage);
XX		}
XX
XX		argv++;
XX		argc--;
XX	}
XX
XX	if (argc < 2)
XX		fatalmesg(usage);
XX	makedir = argv[1];
XX	argv ++;
XX	argc --;
XX
XX	if (argc < 2)
XX		fatal("no source files specified");
XX
XX	while (--argc)
XX		findso(getname(argv++[1], REDUCE), FORCE);
XX
XX	yystring = rulstring;
XX	BEGIN rules;
XX
XX	yyparse();
XX	exit(0);
XX}
XX%}
XX
XX%%
XX
XXaccept	:	rules includes
XX	;
XXrules	:	rule
XX	|	RULSEP rules
XX	|	rules RULSEP
XX	|	rules RULSEP rule
XX	;
XXrule	:	':' SPACE
XX			{   /* Lhs of inclusion rule, empty output suffix */
XX				lsuf = nodesf("");
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf ':' SPACE
XX			{   /* Lhs of inclusion rule */
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf '=' SPACE
XX			{   /* Lhs of transfer rule */
XX				rule = EQU;
XX			}
XX		rhssuf
XX	|	rule SPACE rhssuf
XX	;
XXlhssuf	:	SUFF
XX			{   /* Lhs of any rule */
XX				lsuf = nodesf(yytext);
XX			}
XX	;
XXrhssuf	:	SUFF
XX			{   /* Rhs of any rule */
XX				rsuf = nodesf(yytext);
XX				if (rsuf->rule && (rsuf->rule != EQU || rule != EQU))
XX				        fatal("ambiguous rules %s", rulstring);
XX				rsuf->rule = rule;
XX				if (rsuf->top >= OUTSIZ)
XX					fatal("to many parallel transfers %s", rulstring);
XX				rsuf->out[rsuf->top++] = lsuf;
XX			}
XX	;
XXincludes:
XX	|	includes INCSEP
XX	|	includes INCSEP include
XX	;
XXinclude	:	lhs
XX		QUOTE
XX			{	remote = 0;	}
XX		rhs
XX		QUOTE
XX			{	unput('#');
XX				BEGIN comment;
XX			}
XX	|	lhs
XX		LPAR
XX			{	remote = 1;	}
XX		rhs
XX		RPAR
XX			{	unput('#');
XX				BEGIN comment;
XX			}
XX	;
XXlhs	:	PATH
XX			{   /* Lhs of include statement:
XX			     *      Reduce filename, and check that
XX			     *      file name was in the source list.
XX			     */
XX				lhs = getname(yytext, REDUCE);
XX				if (!findso(lhs, EXACT))
XX					error("%s not in source list",
XX					   yytext);
XX			}
XX		':' INCL 
XX	;
XXrhs	:	PATH
XX			{   /* Rhs of include statement:
XX			     *      Resolve file reference and print
XX			     *      normalized include statement.
XX			     */
XX				rhs = getname(yytext, NOREDUCE);
XX				if (rhs.sf->rule == EQU)
XX					fatal("bad include file suffix: %s",
XX					   line);
XX				printnorm();
XX			}
XX	;
XX
XX%%
XX
XXvoid
XXyyerror(s)
XX	char	*	s;
XX{
XX	if (yystring)
XX		fatal("%s rules: %s", s, rulstring);
XX	else
XX		fatal("%s near line %d: %s", s, lineno, line);
XX}
XX
XX/* Resolve current include file reference and print
XX * the corresponding normalized include statement.
XX */
XXstatic void
XXprintnorm()
XX{
XX	DIRLIST *	dl;
XX	char	*	p;
XX	char		dir[PATHSIZ+1];
XX
XX    /* Try directory of left hand side file when
XX     *    format: #include "file".
XX     */
XX	if (!remote)
XX	{
XX		strcpy(dir, lhs.pf->path);
XX
XX		if ((p = rindex(dir, '/')) == NULL)
XX			p = dir;
XX
XX		*p = CNULL;
XX
XX		if (printcond(dir))
XX			return;
XX	}
XX
XX    /* Try user include libraries */
XX
XX	for (dl = first.idir; dl; dl = dl->next)
XX		if (printcond(dl->path))
XX			return;
XX
XX    /* Try system include library */
XX
XX	if (printcond("/usr/include"))
XX		return;
XX	
XX	error("cannot resolve: %s", line);
XX}
XX
XXstatic int
XXprintcond(dir)
XX	char	*	dir;
XX{
XX	struct stat	stbuf;
XX	NAME		nm;
XX	char		buf[PATHSIZ+1];
XX
XX    /* If include reference is not absolute,
XX     * prepend directory.
XX     */
XX
XX	if (strlen(dir) != 0 && rhs.pf->path[0] != '/')
XX		sprintf(buf, "%s/%s%s", dir, rhs.pf->path, rhs.sf->name);
XX	else
XX		sprintf(buf, "%s%s", rhs.pf->path, rhs.sf->name);
XX
XX	nm = getname(buf, REDUCE);
XX
XX	sprintf(buf, "%s%s", nm.pf->path, nm.sf->name);
XX
XX    /* If the resulting file name path can be derived from a source,
XX     * accept include reference and print dependency.
XX     */
XX	if (findso(nm, DERIVED))
XX	{
XX		printf("%s%s < %s\n", lhs.pf->path, lhs.sf->name, buf); 
XX		return TRUE;
XX	}
XX
XX    /* Ignore system include references not specified as sources,
XX     * unless -i option was specified.
XX     */
XX	if (strncmp(buf, "/usr/include/", strlen("/usr/include/")) == 0
XX	       && !sysflag && (stat(buf, &stbuf) == 0))
XX		return TRUE;
XX
XX	return FALSE;
XX}
XX
XX
XX/* Return file name,
XX *    reduced if flag == REDUCE.
XX */
XXstatic NAME
XXgetname(path, flag)
XX	char	*	path;
XX	int		flag;
XX{
XX	NAME		nm;
XX	DIRLIST *	dl;
XX	char	*	mp,
XX		*	p;
XX	char		buf[PATHSIZ+1];
XX	int		c;
XX
XX	mp = path;
XX
XX	if (flag == REDUCE )
XX	{
XX	    int absdir = 0;
XX
XX	    /* Make reference absolute */
XX		if (*path != '/')
XX		{
XX			sprintf(buf, "%s/%s", makedir, path);
XX			path = buf;
XX		}
XX
XX	    /* If the file name refers to one of the absolute directories,
XX	     * it should be in absolute form.
XX	     */
XX		for (dl = first.adir; dl; dl = dl->next)
XX		{
XX			if ((mp = mpath(path, dl->path)) == NULL)
XX				fatal("can't reduce path");
XX
XX			if (strncmp(mp, "../", 3) != 0)
XX			{
XX				if (strlen(mp)+strlen(dl->path)+1 > PATHSIZ)
XX					fatal("path too long: %s/%s",
XX					   dl->path, mp);
XX
XX				absdir++;
XX				sprintf(buf, "%s/%s", dl->path, mp);
XX				mp = buf;
XX				break;
XX			}
XX		}
XX
XX	    /* If the file name does not refer to any of the
XX	     * absolute directories, it should be in relative form.
XX	     */
XX		if (!absdir)
XX		{
XX			if ((mp = mpath(path, makedir)) == NULL)
XX				fatal("can't reduce path");
XX
XX			if (strlen(mp) > PATHSIZ)
XX				fatal("path too long: %s", mp);
XX		}
XX	}
XX
XX
XX	if ((p = rindex(mp, '/')) == NULL)
XX		p = mp;
XX
XX	if ((p = rindex(p, '.')) == NULL)
XX		p = mp + strlen(mp);
XX
XX	nm.sf = nodesf(p);
XX	c = *p;
XX	*p = CNULL;
XX	nm.pf = nodepf(mp);
XX	*p = c;
XX
XX	return nm;
XX}
XX
XXstatic char *
XXgetword(p, buf)
XX	char	*	p,
XX		*	buf;
XX{
XX	while (*p == ' ' || *p == '\t')
XX		p++;
XX
XX	if (*p == CNULL)
XX		return NULL;
XX
XX	while (*p != ' ' && *p != '\t' && *p != CNULL)
XX		*buf++ = *p++;
XX
XX	*buf = CNULL;
XX	return p;
XX}
XX
XXstatic void
XXgetdirlist(arg)
XX	char	*	arg;
XX{
XX	DIRLIST **	head;
XX	char	*	s;
XX	char		buf[PATHSIZ+1];
XX
XX	if (arg[1] == 'a')
XX		head = &first.adir;
XX	else
XX		head = &first.idir;
XX	
XX	s = arg;
XX	s += 2;
XX	while (s = getword(s, buf))
XX	{
XX		if (arg[1] == 'a' && buf[0] != '/')
XX			fatal("directory list must be absolute: %s", arg);
XX
XX		nodedl(buf, head); 
XX	}
XX}
XX
XX/* Return suffix node.
XX * If the given suffix was not in the suffix list,
XX * allocate a new node.
XX */
XXstatic SUF *
XXnodesf(name)
XX	char	*	name;
XX{
XX	SUF	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.sf; node; prev = node, node = node->next)
XX		if (strcmp(name, node->name) == 0)
XX			return node;
XX
XX	node = (SUF *) alloc(sizeof(SUF), name);
XX	strcpy(node->name, name);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.sf = node;
XX
XX	return node;
XX}
XX
XX/* Return prefix node.
XX * If the given (reduced) path was not in the prefix list,
XX * allocate a new node.
XX */
XXstatic PREF *
XXnodepf(path)
XX	char	*	path;
XX{
XX	PREF	*	node,
XX		*	prevhash;
XX	int		h;
XX
XX	h = hash(path, PHASHL);
XX
XX	for (node = phash[h]; node; node = node->nexthash)
XX		if (strcmp(path, node->path) == 0)
XX			return node;
XX		else
XX			prevhash = node;
XX
XX	node = (PREF *) alloc(sizeof(PREF), path);
XX	strcpy(node->path, path);
XX
XX	if (phash[h])
XX		prevhash->nexthash = node;
XX	else
XX		phash[h] = node;
XX
XX	return node;
XX}
XX
XX/* Search the source list for the given file name:
XX *
XX *   1. flag = EXACT		Look for exact match.
XX *				Return TRUE if found, else FALSE
XX *
XX *   2. flag = FORCE		Look for exact match.
XX *				If not found, allocate a new node.
XX *				Always return TRUE.
XX *
XX *   3. flag = DERIVED		Return TRUE if a match can be found by applying
XX *				transfer rules to the file name suffixes in the
XX *			 	source list, else FALSE.
XX */
XXstatic int
XXfindso(nm, flag)
XX	NAME		nm;
XX	int		flag;
XX{
XX	SOURCE	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.so; node; prev = node, node = node->next)
XX		if (node->pf == nm.pf
XX		  && (node->sf == nm.sf || DERIVED && derived(nm.sf, node->sf)))
XX			return TRUE;
XX
XX	if (flag == FORCE)
XX	{
XX		node = (SOURCE *) alloc(sizeof(SOURCE), line);
XX
XX		node->pf = nm.pf;
XX		node->sf = nm.sf;
XX
XX		if (prev)
XX			prev->next = node;
XX		else
XX			first.so = node;
XX
XX		return TRUE;
XX	}
XX	else
XX		return FALSE;
XX}
XX
XX/* If dsf is same as sf, or can be derived from it by applying
XX * a number of transfer rules, return TRUE, else FALSE
XX */
XXstatic int
XXderived(dsf, sf)
XX	SUF	*	dsf,
XX		*	sf;
XX{
XX	int		i;
XX
XX	if (dsf == sf)
XX		return TRUE;
XX
XX	if (sf->rule != EQU)
XX		return FALSE;
XX
XX	for (i = 0; i < sf->top; i++)
XX		if (derived(dsf, sf->out[i]))
XX			return TRUE;
XX
XX	return FALSE;
XX}
XX
XX/* Append directory to search list.
XX */
XXstatic void
XXnodedl(path, head)
XX	char	*	path;
XX	DIRLIST **	head;
XX{
XX	DIRLIST *	node,
XX		*	prev;
XX
XX	for (prev = node = *head; node; prev = node, node = node->next)
XX		if (strcmp(path, node->path) == 0)
XX			return;
XX
XX	node = (DIRLIST *) alloc(sizeof(DIRLIST), path);
XX	strcpy(node->path, path);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		*head = node;
XX
XX	return;
XX}
XX
XX
XX/* Allocate a zero initialized node.
XX */
XXstatic char *
XXalloc(size, obj)
XX	char	*	obj;
XX{
XX	char	*	node;
XX
XX	if ((node = calloc(1, size)) == NULL)
XX		fatal("can't alloc %s", obj);
XX
XX	return node;
XX}
XX
XX/* Hash a character string, and return the hash value
XX * modulo the given hash length.
XX */
XXstatic int
XXhash(p, hashl)
XX	char	*	p;
XX	int		hashl;
XX{
XX	register	unsigned sum;
XX	register	c;
XX
XX	sum = 0;
XX	while ((c = *p++) != 0)
XX	{
XX		if (sum & 01)
XX			sum = (sum >> 1) + 0x8000;
XX		else
XX			sum >>= 1;
XX		sum += c;
XX		sum &= 0xFFFF;
XX	}
XX	return sum % hashl;
XX}
SHAR_EOF
if test 12659 -ne "`wc -c makenorm.y`"
then
echo shar: error transmitting makenorm.y '(should have been 12659 characters)'
fi
chdir ..
#	End of shell archive
exit 0
-- 
	Kim Walden
	ENEA DATA Sweden

	UUCP:	{seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim
	ARPA:	decvax!mcvax!enea!kim@berkeley.arpa
		mcvax!enea!kim@seismo.arpa

kim@enea.UUCP (Kim Walden) (04/10/85)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	tool
# This archive created: Wed Apr 10 14:07:18 1985
mkdir tool
chdir tool
mkdir test
chdir test
mkdir h
chdir h
sed 's/^XX//' << \SHAR_EOF > cons.h
XX# include "../proc/globs.h"
SHAR_EOF
if test 28 -ne "`wc -c cons.h`"
then
echo shar: error transmitting cons.h '(should have been 28 characters)'
fi
chdir ..
mkdir proc
chdir proc
sed 's/^XX//' << \SHAR_EOF > Makefile
XX# Makefile using automatic dependency generation.
XX
XXSRCS= convert.l error.h globs.h parser.y \
XX      prog.c scanner.l tab.h ../h/cons.h
XX
XXdepend:
XX	@makedep $(SRCS)
SHAR_EOF
if test 162 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 162 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > tab.h
SHAR_EOF
if test 0 -ne "`wc -c tab.h`"
then
echo shar: error transmitting tab.h '(should have been 0 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > scanner.l
XX# include "../h/cons.h"
XX# include "error.h"
SHAR_EOF
if test 44 -ne "`wc -c scanner.l`"
then
echo shar: error transmitting scanner.l '(should have been 44 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > prog.c
XX# include	"error.h"
SHAR_EOF
if test 20 -ne "`wc -c prog.c`"
then
echo shar: error transmitting prog.c '(should have been 20 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > parser.y
XX# include "scanner.c"
XX#include "tab.h"
SHAR_EOF
if test 39 -ne "`wc -c parser.y`"
then
echo shar: error transmitting parser.y '(should have been 39 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > globs.h
XX
SHAR_EOF
if test 1 -ne "`wc -c globs.h`"
then
echo shar: error transmitting globs.h '(should have been 1 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > error.h
SHAR_EOF
if test 0 -ne "`wc -c error.h`"
then
echo shar: error transmitting error.h '(should have been 0 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > convert.l
XX# include "../h/cons.h"
SHAR_EOF
if test 24 -ne "`wc -c convert.l`"
then
echo shar: error transmitting convert.l '(should have been 24 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > Dep.mk
XXconvert.o: ../h/cons.h globs.h
XXparser.o: scanner.c tab.h ../h/cons.h error.h globs.h
XXprog.o: error.h
SHAR_EOF
if test 101 -ne "`wc -c Dep.mk`"
then
echo shar: error transmitting Dep.mk '(should have been 101 characters)'
fi
chdir ..
chdir ..
sed 's/^XX//' << \SHAR_EOF > mpath.c
XX/* -- Minimal file path
XX *
XX * $File: mpath.c  1.3  1985-03-29  14:12:00 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *	ENEA DATA, Sweden and 
XX *	SYSLAB, Department of Computer Science,
XX *	University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above Copyright lines in each copy.
XX *
XX *	Usage:	mpath(filename, currdir)
XX *		
XX *		A pointer to the minmal path of 'filename'
XX *		relative to directory 'currdir' is returned.
XX *
XX *		If 'filename' is not given in absolute form,
XX *		it is taken to be relative to 'currdir'.
XX *
XX *		'currdir'  must be given in absolute form.
XX *		
XX *		E.g.:
XX *
XX *		1. mpath("/usr/src/doc", "/usr/src/cmd")  -->  "../doc"
XX *
XX *		2. mpath("../../src/doc/csh/..", "/usr/src/cmd")  -->  "../doc"
XX *
XX * $Log:	mpath.c,v $
XX * 
XX * Revision 1.3  1985-03-29  14:12:00  kim
XX * New source format
XX * 
XX * Revision 1.2  1985-02-18  14:24:24  kim
XX * New error handling
XX */
XX
XX# define LINSIZ 256
XX# define MAXLEVEL 100
XX# define CNULL '\0'
XX
XX# include <stdio.h>
XX
XXchar	*	mpath();
XXint		split(),
XX		reduce();
XX
XXchar *
XXmpath(filename, currdir)
XX	char	*	filename,
XX		*	currdir;
XX{
XX	static	char	buf[LINSIZ];
XX	char	*	nm[MAXLEVEL],
XX		*	cd[MAXLEVEL];
XX	int		nmlen,
XX			cdlen,
XX			i,
XX			k;
XX
XX	if (strlen(filename)+strlen(currdir) > LINSIZ-2)
XX	{
XX		error("too long path: %s/%s", currdir, filename);
XX		return NULL;
XX	}
XX
XX	if (currdir[0] != '/')
XX	{
XX		error("directory not absolute: %s", currdir);
XX		return NULL;
XX	}
XX
XX    /* Split the path strings of current directory and filename
XX    ** into arrays of characters pointers
XX    */
XX	cdlen = split(currdir, cd, '/');
XX
XX	if (filename[0] != '/')
XX		sprintf(buf, "%s/%s", currdir, filename);
XX	else
XX		strcpy(buf, filename);
XX
XX	nmlen = split(buf, nm, '/');
XX
XX    /* Remove "//", "/.", and "x/.." entries */
XX
XX	cdlen = reduce(cd, cdlen);
XX	nmlen = reduce(nm, nmlen);
XX
XX    /* Both strings are now absolute and normalized,
XX    ** find out how far they match from root down
XX    */
XX	for (i = 0; i < cdlen && i < nmlen; i++)
XX		if (strcmp(cd[i], nm[i]) != 0)
XX			break;
XX
XX    /* Concatenate the required number of ".." references
XX    ** needed to reach the point of divergence.
XX    */
XX	buf[0] = CNULL;
XX
XX	for (k = 0; k < cdlen-i; k++)
XX	{
XX		if (buf[0] != CNULL)
XX			strcat(buf, "/");
XX		strcat(buf, "..");
XX	}
XX
XX    /* Append the rest of the filename path */
XX
XX	for (k = 0; k < nmlen-i; k++)
XX	{
XX		if (buf[0] != CNULL)
XX			strcat(buf, "/");
XX		strcat(buf, nm[i+k]);
XX	}
XX
XX    /* Empty means "." reference */
XX
XX	if (strlen(buf) == 0)
XX		strcpy(buf, ".");
XX
XX	return buf;
XX}
XX
XXstatic int
XXsplit(s, array, sep)
XX	char	*	s,
XX		*	array[];
XX{
XX	char	*	index(),
XX		*	p;
XX	int		n = 0;
XX
XX    /* Split string on given separator into array.
XX    ** Works much like the split function of awk.
XX    */
XX	if ((p = (char *) calloc(1, strlen(s)+1)) == NULL)
XX	{
XX		error("can't allocate: %s", s);
XX		return NULL;
XX	}
XX
XX	strcpy(p, s);
XX
XX	array[n++] = p;
XX	while ((p = index(p, sep)) != NULL)
XX	{
XX		*p++ = CNULL;
XX		array[n++] = p;
XX	}
XX
XX	return n;
XX}
XX
XX
XXstatic int
XXreduce(array, len)
XX	char	*	array[];
XX{
XX	int		af,
XX			bf;
XX
XX    /* Remove ".", "..", and empty references from array,
XX    ** by shifting the cells.
XX    */
XX	for (af = bf = 0; bf < len; bf++)
XX	{
XX		if (strlen(array[bf]) == 0 ||
XX		    strcmp(array[bf], ".") == 0)
XX			continue;
XX
XX		if (strcmp(array[bf], "..") == 0)
XX		{
XX			if (af == 0)
XX				continue;
XX
XX			af -= 1;
XX		}
XX		else
XX			array[af++] = array[bf];
XX	}
XX
XX	return af;
XX}
SHAR_EOF
if test 3421 -ne "`wc -c mpath.c`"
then
echo shar: error transmitting mpath.c '(should have been 3421 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > makedep.c
XX/* -- Make dependency generator
XX *
XX * $File: makedep.c  1.3  1985-03-29  14:46:31 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This program implements part of the algorithm described
XX *      	in K. Walden, "Automatic Generation of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX * $Log:	makedep.c,v $
XX * 
XX * Revision 1.3  1985-03-29  14:46:31  kim
XX * New source format
XX * 
XX * Revision 1.3  1985-03-29  14:11:11  kim
XX * New source format
XX * 
XX * Revision 1.2  1985-03-08  01:18:53  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.1  1985-02-25  19:37:39  kim
XX * Initial revision
XX */
XX
XX# define CMDSIZ  10000
XX# define OPTSIZ  1000
XX# define CNULL  '\0'
XX
XX# include <strings.h>
XX
XXstatic char usage[]=
XX"Usage: makedep [-1] [-rfile] [-Rrules] [-Ilist] [-alist] [-i] sourcefiles";
XX
XXmain(argc, argv)
XX	int		argc;
XX	char	*	argv[];
XX{
XX	char	*	n,
XX		*	d,
XX		*	s;
XX	char		buf[CMDSIZ],
XX			srcs[CMDSIZ],
XX			norm[OPTSIZ],
XX			dep[OPTSIZ];
XX	int 		vflag = 0;
XX
XX	setprogname(argv[0]);
XX
XX	s = srcs;
XX	n = norm;
XX	d = dep;
XX	*s = *n = *d = CNULL;
XX
XX	while (argc > 1 && argv[1][0] == '-')
XX	{
XX		switch (argv[1][1])
XX		{
XX		 case 'v':
XX			vflag++;
XX			break;
XX
XX		 case 'r':
XX		 case 'R':
XX			sprintf(d, "-%c\"%s\" ", argv[1][1], &argv[1][2]);
XX			d += strlen(d);
XX		 case 'I':
XX		 case 'a':
XX			sprintf(n, "-%c\"%s\" ", argv[1][1], &argv[1][2]);
XX			n += strlen(n);
XX			break;
XX
XX		 case '1':
XX			sprintf(d, "-%c ", argv[1][1]);
XX			d += strlen(d);
XX			break;
XX
XX		 case 'i':
XX			sprintf(n, "-%c ", argv[1][1]);
XX			n += strlen(n);
XX			break;
XX
XX		 default:
XX			error("unknown option %s", argv[1]);
XX			fatalmesg(usage);
XX		}
XX
XX		argv++;
XX		argc--;
XX	}
XX
XX	if (argc < 2)
XX		fatal("no source files specified");
XX
XX	while (--argc)
XX	{
XX		sprintf(s, "%s ", argv++[1]);
XX		s += strlen(s);
XX	}
XX
XX	s = buf;
XX	sprintf(s, "grep '^#[ \t]*include' /dev/null %s | ", srcs);
XX	s += strlen(s);
XX
XX	sprintf(s, "makenorm %s `pwd` %s %s | ", norm, srcs);
XX	s += strlen(s);
XX
XX	sprintf(s, "depend %s\n", dep);
XX
XX	if (vflag)
XX		printf("%s", buf);
XX
XX	system(buf);
XX}
SHAR_EOF
if test 2339 -ne "`wc -c makedep.c`"
then
echo shar: error transmitting makedep.c '(should have been 2339 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > depscan.l
XX%{
XX/* -- Scanner for depend
XX *
XX * $File: depscan.l  1.7  1985-03-29  14:10:37 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This scanner is part of an implementation of the
XX *		algorithm described in K. Walden, "Automatic Generation
XX *		of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX *		When yylex is first called, it is supposed to be in
XX *		state <rules>, and 'yystring' is supposed to point
XX *		to a string containing declared include rules.
XX *		The input is taken from this string through a
XX *		modified getc() routine.
XX *
XX *		The scanner recognizes rules of the form:
XX *
XX *		  .o: .c .p .f
XX *		  .c= .y .l .q
XX *
XX *		where '\n' or ';' may be used as record separators.
XX *
XX *		The rules string is scanned until it is exhausted,
XX *		(Lex considers '\0' to be EOF,) and then yywrap()
XX *		will switch to state <includes>.
XX *
XX *		The scanner now recognizes include statements of the form:
XX *
XX *		  file1 < file2
XX *
XX *		and getc() starts reading from the Standard Input.
XX *
XX *
XX * $Log:	depscan.l,v $
XX * 
XX * Revision 1.7  1985-03-29  14:10:37  kim
XX * New source format
XX * 
XX * Revision 1.6  1985-03-08  01:18:45  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.5  1985-02-14  01:44:06  kim
XX * Converted to RCS format
XX *
XX * Revision 1.4  1984-08-21  19:50:58  kim
XX * Change SYSLAB report reference to SP & E
XX * 
XX * Revision 1.3  1983-10-31  19:50:54  kim
XX * Include Copyright lines
XX * 
XX * Revision 1.2  1983-07-20  19:50:50  kim
XX * Closer to algorithm in SYSLAB Report No. 19 (June 1983)
XX * 
XX * Revision 1.1  1983-02-22  19:50:47  kim
XX * Initial revision
XX */
XX
XX# undef getc
XX# undef YYLMAX
XX# define YYLMAX 10000
XX
XX%}
XX
XX%START	rules includes
XX
XXDOT	[.]
XXW	[ \t]
XX
XXSUF	[!%+\-0-9?@A-Z\^_a-z~]
XXPATH	[!%+\-./0-9?@A-Z\^_a-z~]
XX
XX	int nlfound;
XX
XX%%
XX
XX{W}+			{	return(SPACE);
XX			}
XX<rules>{DOT}{SUF}+	{	return(SUFF);
XX			}
XX<rules>{W}*[\n;]{W}*	{	return(RULSEP);
XX			}
XX<includes>^.+$		{	strcpy(line, yytext);
XX				lineno = nlfound;
XX				REJECT;
XX			}
XX<includes>{W}*\n{W}*	{	nlfound++;
XX				return(INCSEP);
XX			}
XX<includes>{PATH}+	{	return(PATH);
XX			}
XX.			{	return(yytext[0]);
XX			}
XX%%
XX
XXint
XXyywrap()
XX{
XX	if (yystring)
XX	{
XX		yystring = NULL;
XX		BEGIN includes;
XX		nlfound = 0;
XX		lineno = 0;
XX		unput('\n');
XX		return(0);
XX	}
XX	else
XX		return(1);
XX}
XX
XXint
XXgetc(fp)
XX	FILE	*	fp;
XX{
XX	if (yystring)
XX		return(*yystring ? *yystring++ : 0);
XX	else
XX		return(fgetc(fp));
XX}
SHAR_EOF
if test 2702 -ne "`wc -c depscan.l`"
then
echo shar: error transmitting depscan.l '(should have been 2702 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > error.c
XX/* -- Error handling
XX *
XX * $File: error.c  1.3  1985-03-29  14:46:48 $
XX *
XX *	Usage:	fatal(format, args)
XX *		fatalmesg(format, args)
XX *
XX *		error(format, args)
XX *		errorc(format, args)
XX *
XX *		mesg(format, args)
XX *		mesgc(format, args)
XX *
XX *		setprogname(s)
XX *
XX *	Descr:	Setprogname copies a string to be used as error message
XX *		prefix into the external array 'progname'. Normally
XX *		this function is called once with argv[0] as argument
XX *		when a command begins execution.
XX *
XX *		Mesg prints a message on stderr, followed by a newline.
XX *		Error is like mesg, but prints a prefix.
XX *		Fatal is like error, but exits.
XX *		Fatalmesg is like mesg, but exits.
XX *
XX *		Mesgc and errorc suppress the newline, and errorc prints
XX *		the prefix only the first time it is called.
XX *
XX *		If a UNIX system call has returned an error number
XX *		in the external variable 'errno', then the
XX *		corresponding system error string is also output,
XX *		enclosed in parentheses.
XX *
XX * $Log:	error.c,v $
XX * 
XX * Revision 1.3  1985-03-29  14:46:48  kim
XX * Removed system error printout
XX * 
XX * Revision 1.3  1985-03-29  14:29:58  kim
XX * removed system error printout
XX * 
XX * Revision 1.2  1985-03-08  01:18:57  kim
XX * Removed fatalc.
XX * 
XX * Revision 1.1  1985-02-18  13:22:12  kim
XX * Initial revision
XX */
XX
XX# include <stdio.h>
XX
XX# define ARGS format,a,b,c,d,e,f
XX# define PROGNAMELEN 100
XX
XXfatal(ARGS)		{ errpri(1, 0, 1, ARGS); }
XXfatalmesg(ARGS)		{ errpri(0, 0, 1, ARGS); }
XX
XXerror(ARGS)		{ errpri(1, 0, 0, ARGS); }
XXerrorc(ARGS)		{ errpri(1, 1, 0, ARGS); }
XX
XXmesg(ARGS)		{ errpri(0, 0, 0, ARGS); }
XXmesgc(ARGS)		{ errpri(0, 1, 0, ARGS); }
XX
XXchar		progname[PROGNAMELEN] = "NULL";
XX
XXsetprogname(s) char *s; { strcpy(progname, s); }
XX
XXstatic errpri(prf, cont, ex, ARGS)
XX	int		prf,
XX			cont,
XX			ex;
XX{
XX	static int	prf_printed;
XX
XX	if (prf && !prf_printed)
XX	{
XX		fprintf(stderr, "%s: ", progname);
XX		prf_printed++;
XX	}
XX
XX	fprintf(stderr, ARGS);
XX
XX	if (!cont)
XX	{
XX		fprintf(stderr, "\n");
XX		prf_printed = 0;
XX	}
XX
XX	if (ex)
XX		exit(1);
XX}
SHAR_EOF
if test 1985 -ne "`wc -c error.c`"
then
echo shar: error transmitting error.c '(should have been 1985 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > normscan.l
XX%{
XX/* -- Scanner for makenorm
XX *
XX * $File: normscan.l  1.3  1985-03-29  14:12:33 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This scanner is part of an implementation of the
XX *		algorithm described in K. Walden, "Automatic Generation
XX *		of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX *		When yylex is first called, it is supposed to be in
XX *		state <rules>, and 'yystring' is supposed to point
XX *		to a string containing declared include rules.
XX *		The input is taken from this string through a
XX *		modified getc() routine.
XX *
XX *		The scanner recognizes rules of the form:
XX *
XX *		  .o: .c .p .f
XX *		  .c= .y .l .q
XX *
XX *		where '\n' or ';' may be used as record separators.
XX *
XX *		The rules string is scanned until it is exhausted,
XX *		(Lex considers '\0' to be EOF,) and then yywrap()
XX *		will switch to state <includes>.
XX *
XX *		The scanner now recognizes include statements of the form:
XX *
XX *		  #include "file"  or  #include <file>
XX *
XX *		with possible whitespace and trailing comments,
XX *		and getc() starts reading from the Standard Input.
XX *
XX *
XX * $Log:	normscan.l,v $
XX * 
XX * Revision 1.3  1985-03-29  14:12:33  kim
XX * New source format
XX * 
XX * Revision 1.2  1985-03-08  01:18:49  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.1  1985-02-16  18:57:56  kim
XX * Initial revision
XX */
XX
XX# undef getc
XX# undef YYLMAX
XX# define YYLMAX 10000
XX
XX%}
XX
XX%START	rules includes comment
XX
XXDOT	[.]
XXW	[ \t]
XX
XXSUF	[!%+\-0-9?@A-Z\^_a-z~]
XXPATH	[!%+\-./0-9?@A-Z\^_a-z~]
XX
XX	int nlfound;
XX
XX%%
XX
XX<comment>.*			{	BEGIN includes;
XX				}
XX{W}+				{	return(SPACE);
XX				}
XX<rules>{DOT}{SUF}+		{	return(SUFF);
XX				}
XX<rules>{W}*[\n;]{W}*		{	return(RULSEP);
XX				}
XX<includes>^.+$			{	strcpy(line, yytext);
XX					lineno = nlfound;
XX					REJECT;
XX				}
XX<includes>{W}*#{W}*include{W}*	{	return(INCL);
XX				}
XX<includes>{W}*\"{W}*		{	return(QUOTE);
XX				}
XX<includes>{W}*"<"{W}*		{	return(LPAR);
XX				}
XX<includes>{W}*">"{W}*		{	return(RPAR);
XX				}
XX<includes>{W}*\n{W}*		{	nlfound++;
XX					return(INCSEP);
XX				}
XX<includes>{PATH}+		{	return(PATH);
XX				}
XX.				{	return(yytext[0]);
XX				}
XX%%
XX
XXyywrap()
XX{
XX	if (yystring)
XX	{
XX		yystring = NULL;
XX		BEGIN includes;
XX		nlfound = 0;
XX		lineno = 0;
XX		unput('\n');
XX		return(0);
XX	}
XX	else
XX		return(1);
XX}
XX
XXgetc(fp)
XX	FILE	*	fp;
XX{
XX	if (yystring)
XX		return(*yystring ? *yystring++ : 0);
XX	else
XX		return(fgetc(fp));
XX}
SHAR_EOF
if test 2680 -ne "`wc -c normscan.l`"
then
echo shar: error transmitting normscan.l '(should have been 2680 characters)'
fi
mkdir man
chdir man
sed 's/^XX//' << \SHAR_EOF > Makefile
XXall: makedep.man makenorm.man depend.man
XX
XXROFF= nroff
XX
XX.1.man:
XX	$(ROFF) -man $< > $@
XX
XX.SUFFIXES: .man .1
SHAR_EOF
if test 105 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 105 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > makedep.1
XX.so tmac.anx
XX.TH MAKEDEP 1 "ENEA DATA  March 1985"
XX.SH NAME
XXmakedep - make dependency generator
XX.SH SYNOPSIS
XX.B makedep
XX.SP r rules ]
XX.SP R rules ]
XX.SP I list ]
XX.SP a list ]
XX.SF i
XXsourcefiles
XX.SH DESCRIPTION
XX.I Makedep
XXexamines the given source files,
XXand extracts all C preprocessor include statements 
XXof the standard form
XX.IP
XX	#include "file"
XX.br
XX	#include <file>
XX.P
XXwith possible extra white space and trailing comments.
XXThe include statements are piped to
XX.I makenorm,
XXwhich transforms them into the normal form
XX.IP
XX	file1 < file2
XX.P
XXWhen the top directory of a system is moved to a new position
XXin a global file system, all
XX.I make
XXdependencies should still be valid.
XXThe file names must therefore be expressed in a form
XXthat is insensitive to relocation.
XXIn most cases,
XXfile references relative to the current
XX.I make
XXdirectory have this property.
XXSome references, however, are global in nature.
XXThe dependency
XX.IP
XX	prog.o: ../../../../../../usr/include/time.h
XX.P
XXbecomes invalid when the system is moved downwards in
XXa file system.
XX.P
XXTherefore, whenever a file name refers to an absolute directory,
XXit is expressed in absolute form,
XXotherwise it is made relative to the given
XX.I make
XXdirectory.
XXThe directory
XX.I /usr/include
XXis always considered absolute,
XXbut additional absolute directories may be specified.
XX.P
XXThe normalized include statements are, in turn,
XXpiped to
XX.I depend,
XXwhich generates all
XX.I make
XXdependencies implied by the include statements.
XX.P
XXThe resulting dependencies are written to the standard output.
XX.P
XXInclude file references are normally interpreted by
XXthe C preprocessor as relative to
XXthe directory of the file in which the statement occurred.
XXHowever, if the referenced file cannot be found,
XXa user directory list is first searched, if specified,
XXand then the system directory
XX.I /usr/include.
XXThe '#include <file>' form searches only the user list
XXand the system directory.
XX.P
XXGenerated files may be missing or obsolete
XXat the time of the
XX.I make
XXdependency generation,
XXso include statements must extracted from source files.
XXHowever, include statements may reference generated files,
XXlike e.g. a 
XX.I lex
XXgenerated 'scanner.c' which is included in a
XX.I yacc
XXfile.
XXTherefore, a set of standard include suffix rules
XXare used to deduce which files will be present at
XXC compile time,
XXand all implied 
XX.I make
XXdependencies may thus be generated by examining
XXthe source files
XX(see the SP & E article below).
XX.P
XXSince include statements are sometimes propagated
XXto more than one output file,
XXparallell transfer rules are permitted.
XXFor example, the
XX.B -d
XXoption to 
XX.I yacc
XXproduces a definitions file,
XXwhich may be referenced by other files.
XX.P
XXTo make automatic dependency generation possible,
XX.I yacc
XXoutput files must have the same base name as the
XXinput file.
XXThus, if the
XX.I make
XXdependencies and corresponding commands are written:
XX.IP
XX	grammar.h grammar.c: grammar.y
XX.br
XX		yacc -d grammar.y
XX.br
XX		mv y.tab.c grammar.c
XX.br
XX		mv y.tab.h grammar.h
XX.P
XXthe default parallell rules
XX.IP
XX	.c= .y 
XX.br
XX	.h= .y
XX.P
XXwill be applicable.
XX.P
XXArguments:
XX.A1 r rules The
XXstandard include suffix rules
XX.IP
XX	.o: .c .p .f
XX.br
XX	.c= .y .l .q
XX.br
XX	.h= .y
XX.IP
XXare augmented by the specified rules.
XXThe argument is a string of rules, separated by semicolon.
XX.A1 R rules The
XXstandard include suffix rules are replaced by
XXthe specified rules.
XX.A1 I list Add
XXthe specified directory to the 
XXuser include directory search list.
XX.A1 a list Add
XXthe specified directory to the 
XXabsolute directory list.
XX.AR i Since
XXit is often convenient to exclude
XXdependencies to standard system include files,
XXreferences that cannot be resolved by examining the explicit
XX.I sourcefiles
XXlist,
XXare silently ignored if they are found in the 
XX.I /usr/include
XXdirectory.
XXThe
XX.B -i
XXoption forces system include references to be treated like
XXany other references.
XX.C1 sourcefiles The
XXcomplete list of source files.
XX.RE
XX.P
XXA standard Makefile using
XX.I makedep
XXmay contain
XX.P
XX.nf
XX\&...
XX
XXSRCS= 'list of source files'
XX
XXdepend: 
XX	makedep $(SRCS) > Dep.mk
XX	@echo "\tInclude dependencies generated."
XX
XXinclude Dep.mk
XX
XX\&...
XX.fi
XX.SH IDENTIFICATION
XX.de VL
XX\\$2
XX..
XXAuthor: Kim Walden,
XXENEA DATA and University of Stockholm, Sweden.
XX.sp 0
XXRevision Number:
XX.VL $Revision: 2.2 $
XX; Release Date:
XX.VL $Date: 1985-03-13  18:39:26 $
XX\h'-1'.
XX.sp 0
XXCopyright \(co 1983.
XX.SH "SEE ALSO"
XXdepend(1), makenorm(1), make(1)
XX.sp 0
XXK. Walden, "Automatic Generation of Make Dependencies",
XX.IR "Softw. Practice & Exper." ,
XXvol. 14, no. 6, June 1984.
XX.sp 0
XX.IR "Make - A Program for Maintaining Computer Programs" ,
XXby S. I. Feldman.
XX.sp 0
XX.IR "An Augmented Version of Make" ,
XXby E. G. Bradford.
SHAR_EOF
if test 4650 -ne "`wc -c makedep.1`"
then
echo shar: error transmitting makedep.1 '(should have been 4650 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > tmac.anx
XX.tr ~
XX.nr f 0
XX.bd S B 3
XX.de SP
XX.if n .ul
XX\%[\fB\-\\$1\fR\\c
XX.if n .ul 0
XX\\$2\\$3
XX..
XX.de SF
XX.if n .ul
XX\%[\fB\-\\$1\fR]
XX.if n .ul 0
XX..
XX.de ZZ
XX\fB.\|.\|.\fR
XX..
XX.de AR
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 5
XX.TP 15
XX\fB\-\\$1\\fR
XX\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
XX.nr f 1
XX..
XX.de C1
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 5
XX.TP 15
XX\\$1
XX\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
XX.nr f 1
XX..
XX.de A1
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 5
XX.TP 15
XX\fB\-\\$1\fR[\fI\\$2\fR]
XX\\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
XX.nr f 1
XX..
XX.de A2
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 5
XX.TP 15
XX\fB\-\\$1\fI\\$2\fR
XX\\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
XX.nr f 1
XX..
XX.ds M)  \fI\s-1MR\s+1\fR
XX.ds R)  \fI\s-1RELEASE NUMBER\s+1\fR
XX.ds S)  \s-1SCCS\s+1
XX.ds I)  \s-1SID\s+1
XX.de F1
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 13
XX.TP 7
XX\fB\\$1\fI\\$2\fR
XX\\$3
XX.nr f 1
XX..
XX.de F2
XX.if \\nf \{ \
XX.    RE
XX.    nr f 0 \}
XX.PP
XX.RS 13
XX.TP 7
XX\fB\\$1[\fI\\$2\fR]
XX\\$3
XX.nr f 1
XX..
XX.de GE
XX.br
XX.if \\w'\\n(.z' .ab "GE: diversion in effect"
XX.nr m \\n(.v*2
XX.nr h 0\\$1
XX.if \\nm-\\nh .ab "GE: unscaled arg"
XX.if \\nh-\\n(.t .bp
XX..
SHAR_EOF
if test 1098 -ne "`wc -c tmac.anx`"
then
echo shar: error transmitting tmac.anx '(should have been 1098 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > makenorm.1
XX.so tmac.anx
XX.TH MAKENORM 1 "ENEA DATA  March 1985"
XX.SH NAME
XXmakenorm - include statement normalizer
XX.SH SYNOPSIS
XX.B makenorm
XX.SP r rules ]
XX.SP R rules ]
XX.SP I list ]
XX.SP a list ]
XX.SF i
XXmakedir
XXsourcefiles
XX.SH DESCRIPTION
XX.I Makenorm
XXaccepts C preprocessor include statements
XXof the form
XX.IP
XX	file1: #include "file"
XX.br
XX	file2: #include <file>
XX.P
XXfrom the standard input
XXwith possible extra white space and trailing comments,
XXand writes them to the standard output in the normal form
XX.IP
XX	file1 < file2
XX.P
XXThis form is suitable for later processing by the
XX.I depend
XXcommand to generate 
XX.I make
XXdependencies.
XX.P
XXWhen the top directory of a system is moved to a new position
XXin a global file system, all
XX.I make
XXdependencies should still be valid.
XXThe file names must therefore be expressed in a form
XXthat is insensitive to relocation.
XXIn most cases,
XXfile references relative to the current
XX.I make
XXdirectory have this property.
XXSome references, however, are global in nature.
XXThe dependency
XX.IP
XX	prog.o: ../../../../../../usr/include/time.h
XX.P
XXbecomes invalid when the system is moved downwards in
XXa file system.
XX.P
XXTherefore, whenever a file name refers to an absolute directory,
XXit is expressed in absolute form,
XXotherwise it is made relative to the given
XX.I make
XXdirectory.
XXThe directory
XX.I /usr/include
XXis always considered absolute,
XXbut additional absolute directories may be specified.
XX.P
XXWhether a reference is absolute or not,
XXit is always reduced to the shortest possible path
XX(loops eliminated),
XXso that file names can later be unambiguously identified by the
XX.I depend
XXcommand.
XX.P
XXInclude file references are normally interpreted by
XXthe C preprocessor as relative to
XXthe directory of the file in which the statement occurred.
XXHowever, if the referenced file cannot be found,
XXa user directory list is first searched, if specified,
XXand then the system directory
XX.I /usr/include.
XXThe '#include <file>' form searches only the user list
XXand the system directory.
XX.P
XXGenerated files may be missing or obsolete
XXat the time of the
XX.I make
XXdependency generation,
XXso include statements must extracted from source files.
XXHowever, include statements may reference generated files,
XXlike e.g. a 
XX.I lex
XXgenerated 'scanner.c' which is included in a
XX.I yacc
XXfile.
XXTherefore, a set of standard include suffix rules
XXare used to deduce,
XXfrom the given list of source files,
XXwhich files will be present at C compile time
XX(see the SP & E article below).
XXInclude file references are thus resolved without requiring
XXany of the files to be present when
XX.I makenorm
XXis run.
XX.P
XXArguments:
XX.A1 r rules The
XXstandard include suffix rules
XX.IP
XX	.o: .c .p .f
XX.br
XX	.c= .y .l .q
XX.br
XX	.h= .y
XX.IP
XXare augmented by the specified rules.
XXThe argument is a string of rules, separated by semicolon.
XX.A1 R rules The
XXstandard include suffix rules are replaced by
XXthe specified rules.
XX.A1 I list Add
XXthe specified directories to the 
XXuser include directory search list.
XX.A1 a list Add
XXthe specified directories to the 
XXabsolute directory list.
XX.AR i Since
XXit is often convenient to exclude
XXdependencies to standard system include files,
XXreferences that cannot be resolved by examining the explicit
XX.I sourcefiles
XXlist,
XXare silently ignored if they are found in the
XX.I /usr/include
XXdirectory.
XXThe
XX.B -i
XXoption forces system include references to be treated like
XXany other references.
XX.C1 makedir The
XXfull path name of the
XX.I make
XXdirectory.
XXIt must be given in absolute form.
XX.C1 sourcefiles The
XXcomplete list of source files,
XXfrom which the include statements were extracted.
XXThis is needed to identify source files which do not
XXcontain include statements.
XX.SH IDENTIFICATION
XX.de VL
XX\\$2
XX..
XXAuthor: Kim Walden,
XXENEA DATA and University of Stockholm, Sweden.
XX.sp 0
XXRevision Number:
XX.VL $Revision: 2.2 $
XX; Release Date:
XX.VL $Date: 1985-03-13  18:39:30 $
XX\h'-1'.
XX.sp 0
XXCopyright \(co 1983.
XX.SH "SEE ALSO"
XXdepend(1), makedep(1), make(1)
XX.sp 0
XXK. Walden, "Automatic Generation of Make Dependencies",
XX.IR "Softw. Practice & Exper." ,
XXvol. 14, no. 6, June 1984.
XX.sp 0
XX.IR "Make - A Program for Maintaining Computer Programs" ,
XXby S. I. Feldman.
XX.sp 0
XX.IR "An Augmented Version of Make" ,
XXby E. G. Bradford.
SHAR_EOF
if test 4167 -ne "`wc -c makenorm.1`"
then
echo shar: error transmitting makenorm.1 '(should have been 4167 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > depend.1
XX.so tmac.anx
XX.TH DEPEND 1 "ENEA DATA  March 1985"
XX.SH NAME
XXdepend - make dependency generator
XX.SH SYNOPSIS
XX.B depend
XX.SP r file ]
XX.SP R rules ]
XX.SF 1
XX.SH DESCRIPTION
XX.I Depend
XXaccepts lines of the form
XX.IP
XX	file1 < file2
XX.P
XXfrom the standard input.
XXThe lines represent include statements
XXextracted from source files.
XXEach file name is assumed to be in normal form,
XXi.e., shortest absolute path for files 
XXin absolute directories,
XXand shortest path relative to the make directory
XXfor all other files.
XX.P
XXThe
XX.I make
XXdependencies implied by these 
XXinclude statements
XXare output in the form
XX.nf
XX.IP
XX	fileX1: fileX2 fileX3 fileX4 ...
XX	fileY1: fileY2 fileY3 fileY4 ...
XX	...
XX.fi
XX.P
XXto the standard output.
XXIf a dependency line is longer than 80 characters,
XXit is split into two lines,
XXso the generated dependencies can be conveniently
XXinspected from a crt terminal.
XX.P
XXArguments:
XX.A1 r rules The
XXstandard include suffix rules
XX.IP
XX	.o: .c .p .f
XX.br
XX	.c= .y .l .q
XX.br
XX	.h= .y
XX.IP
XXare augmented by the specified rules.
XXThe argument is a string of rules, separated by semicolon.
XX.A1 R rules The
XXstandard include suffix rules are replaced by
XXthe specified rules.
XX.AR 1 Only one dependency per output line.
XXThis is useful for postprocessing,
XXfor example, when object file dependencies are to be
XXtransformed into object library member dependencies.
XX.SH IDENTIFICATION
XX.de VL
XX\\$2
XX..
XXAuthor: Kim Walden,
XXENEA DATA and University of Stockholm, Sweden.
XX.sp 0
XXRevision Number:
XX.VL $Revision: 2.1 $
XX; Release Date:
XX.VL $Date: 1985-03-13  18:29:12 $
XX\h'-1'.
XX.sp 0
XXCopyright \(co 1983.
XX.SH "SEE ALSO"
XXmakedep(1), makenorm(1), make(1)
XX.sp 0
XXK. Walden, "Automatic Generation of Make Dependencies",
XX.IR "Softw. Practice & Exper." ,
XXvol. 14, no. 6, June 1984.
XX.sp 0
XX.IR "Make - A Program for Maintaining Computer Programs" ,
XXby S. I. Feldman.
XX.sp 0
XX.IR "An Augmented Version of Make" ,
XXby E. G. Bradford.
SHAR_EOF
if test 1881 -ne "`wc -c depend.1`"
then
echo shar: error transmitting depend.1 '(should have been 1881 characters)'
fi
chdir ..
chdir ..
#	End of shell archive
exit 0
-- 
	Kim Walden
	ENEA DATA Sweden

	UUCP:	{seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim
	ARPA:	decvax!mcvax!enea!kim@berkeley.arpa
		mcvax!enea!kim@seismo.arpa