[comp.bugs.4bsd] Make

gww@beatnix.UUCP (Gary Winiger) (03/13/88)

Subject: Make(1) does not support file inclusion +Fix
Index:	bin/make/{Makefile,defs,gram.y,main.c,misc.c} man1/make.1 4.3BSD

Description:
	4.3BSD make does not support file inclusion.  Other makes do.
Repeat-By:
	Use a System V.3 or SunOS makefile with a include directive.
Fix:
	Elxsi received a large third party package that used the SunOS
	make include directive.  Rather than redo all the makefiles,
	Luong Nguyen-Duy made the following additions to 4.3 make.

	The attached code solves this problem at Elxsi.

Gary..
{ucbvax!sun,uunet,lll-lcc!lll-tis,amdahl!altos86,bridge2}!elxsi!gww
--------- cut --------- snip --------- :.,$w diff -------------
Index: /usr/src/etc/make/Makefile
*** /tmp/,RCSt1000738	Fri Aug  7 14:07:03 1987
--- Makefile	Fri Aug  7 14:05:57 1987
***************
*** 1,6 ****
! #	$Header: Makefile,v 1.1 86/12/11 12:53:09 gww Exp $ ENIX BSD
  #
  # $Log:	Makefile,v $
  # Revision 1.1  86/12/11  12:53:09  gww
  # Initial revision
  # 
--- 1,9 ----
! #	$Header: Makefile,v 1.2 87/08/07 14:05:43 gww Exp $ ENIX BSD
  #
  # $Log:	Makefile,v $
+ # Revision 1.2  87/08/07  14:05:43  gww
+ # Add include Files feature.
+ # 
  # Revision 1.1  86/12/11  12:53:09  gww
  # Initial revision
  # 
***************
*** 12,18 ****
  OBJECTS=ident.o main.o doname.o misc.o files.o dosys.o gram.o 
  LIBES= 
  LINT=	lint -ps
! CFLAGS=	-O -DASCARCH -I. -I/usr/src/bin/make 
  
  all:	make
  
--- 15,22 ----
  OBJECTS=ident.o main.o doname.o misc.o files.o dosys.o gram.o 
  LIBES= 
  LINT=	lint -ps
! DFLAGS=	-DINCLUDES
! CFLAGS=	-O -DASCARCH ${DFLAGS} -I. -I/usr/src/bin/make 
  
  all:	make
  
***************
*** 20,25 ****
--- 24,35 ----
  	${CC} -o make ${CFLAGS} ${OBJECTS} ${LIBES}
  
  ${OBJECTS}:  defs
+ 
+ .y.c:
+ 	/lib/cpp -P -E ${DFLAGS} $*.y >y.tab.y
+ 	${YACC} y.tab.y
+ 	rm -f y.tab.y
+ 	mv y.tab.c $*.c
  
  clean:
  	-rm -f *.o gram.c make a.out errs
Index: /usr/src/etc/make/defs
*** /tmp/,RCSt1000738	Fri Aug  7 14:07:07 1987
--- defs	Fri Aug  7 14:06:02 1987
***************
*** 1,6 ****
! /*	$Header: defs,v 1.1 86/12/11 12:53:11 gww Exp $ ENIX BSD
   *
   * $Log:	defs,v $
   * Revision 1.1  86/12/11  12:53:11  gww
   * Initial revision
   * 
--- 1,9 ----
! /*	$Header: defs,v 1.2 87/08/07 14:05:58 gww Exp $ ENIX BSD
   *
   * $Log:	defs,v $
+  * Revision 1.2  87/08/07  14:05:58  gww
+  * Add include Files feature.
+  * 
   * Revision 1.1  86/12/11  12:53:11  gww
   * Initial revision
   * 
***************
*** 139,141 ****
--- 142,157 ----
  int *ckalloc();
  struct nameblock *srchname(), *makename();
  TIMETYPE exists();
+ 
+ #ifdef	INCLUDES
+ struct include_stack
+ 	{
+ 	FILE *file;
+ 	int lineno;
+ 	char *nextc;
+ 	};
+ #define	MAX_INCLUDES 20
+ extern push();
+ extern empty_stack();
+ extern FILE *pop();
+ #endif	INCLUDES
Index: /usr/src/etc/make/gram.y
*** /tmp/,RCSt1000738	Fri Aug  7 14:07:10 1987
--- gram.y	Fri Aug  7 14:06:05 1987
***************
*** 1,15 ****
  %{#include "defs"
  /*
   * $Log:	gram.y,v $
   * Revision 1.1  86/12/11  12:53:18  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: gram.y,v 1.1 86/12/11 12:53:18 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)gram.y	4.1 (Berkeley) 81/02/28";
  %}
  
  %term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER
  %union
  	{
  	struct shblock *yshblock;
--- 1,22 ----
  %{#include "defs"
  /*
   * $Log:	gram.y,v $
+  * Revision 1.2  87/08/07  14:06:03  gww
+  * Add include Files feature.
+  * 
   * Revision 1.1  86/12/11  12:53:18  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: gram.y,v 1.2 87/08/07 14:06:03 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)gram.y	4.1 (Berkeley) 81/02/28";
  %}
  
+ #ifdef	INCLUDES
+ %term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER INCLUDE
+ #else
  %term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER
+ #endif	INCLUDES
  %union
  	{
  	struct shblock *yshblock;
***************
*** 43,48 ****
--- 50,58 ----
  	;
  
  comline:  START
+ #ifdef	INCLUDES
+ 	| INCLUDE
+ #endif	INCLUDES
  	| MACRODEF
  	| START namelist deplist shellist = {
  	    while( --nlefts >= 0)
***************
*** 272,278 ****
  
  	if((c = text[0]) == '\t')
  		return( retsh(text) );
! 	
  	if(isalpha(c) || isdigit(c) || c==' ' || c=='.')
  		for(p=text+1; *p!='\0'; )
  			if(*p == ':')
--- 282,293 ----
  
  	if((c = text[0]) == '\t')
  		return( retsh(text) );
! #ifdef	INCLUDES
! 	else if((strncmp(text, "include ", 8) == 0) ||
! 		(strncmp(text, "include\t", 8) == 0))
! 		return(do_include(text+8));
! #endif	INCLUDES
! 
  	if(isalpha(c) || isdigit(c) || c==' ' || c=='.')
  		for(p=text+1; *p!='\0'; )
  			if(*p == ':')
***************
*** 312,314 ****
--- 327,366 ----
  		return(START);
  goto again;
  }
+ 
+ 
+ 
+ #ifdef	INCLUDES
+ do_include (text)
+ char *text;
+ {
+ 	register char *p;
+ 	register char *pend;
+ 	char filename[MAXPATHLEN];
+ 
+ 	/* skip leading white space */
+ 
+ 	for (; *text == ' ' || *text == '\t'; text++)
+ 		continue;
+ 
+ 	/* get file name */
+ 
+ 	subst(text, filename);		/* Substitute for macros */
+ 
+ 	if(dbgflag) printf("Include file: %s\n", filename);
+ 
+ 	if (rddescf(filename))
+ 		fatal1("could not do include %s\n", filename);
+ 
+ 	return(INCLUDE);
+ }
+ #endif	INCLUDES
Index: /usr/src/etc/make/main.c
*** /tmp/,RCSt1000738	Fri Aug  7 14:07:14 1987
--- main.c	Fri Aug  7 14:06:09 1987
***************
*** 1,10 ****
  /*
   * $Log:	main.c,v $
   * Revision 1.1  86/12/11  12:53:21  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: main.c,v 1.1 86/12/11 12:53:21 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)main.c	4.8 (Berkeley) 86/01/09";
  # include "defs"
  /*
--- 1,13 ----
  /*
   * $Log:	main.c,v $
+  * Revision 1.2  87/08/07  14:06:06  gww
+  * Add include Files feature.
+  * 
   * Revision 1.1  86/12/11  12:53:21  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: main.c,v 1.2 87/08/07 14:06:06 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)main.c	4.8 (Berkeley) 86/01/09";
  # include "defs"
  /*
***************
*** 280,285 ****
--- 283,292 ----
  char *descfile;
  {
  FILE * k;
+ #ifdef	INCLUDES
+ extern int	yylineno;
+ extern char	*zznextc;
+ #endif	INCLUDES
  
  /* read and parse description */
  
***************
*** 309,315 ****
--- 316,338 ----
  	return( rdd1(stdin) );
  
  if( (k = fopen(descfile,"r")) != NULL)
+ #ifdef	INCLUDES
+ {
+ 	if(fin != NULL) {
+ 		push(fin, yylineno, zznextc);
+ 	}
+ 	if(rdd1(k)) {
+ 		fatal("rddescf(), could not make %s ", descfile);
+ 	}
+ 	else {
+ 		if(!empty_stack())
+ 			fin = pop();
+ 		return(0);
+ 	}
+ }
+ #else
  	return( rdd1(k) );
+ #endif	INCLUDES
  
  return(1);
  }
Index: /usr/src/etc/make/misc.c
*** /tmp/,RCSt1000738	Fri Aug  7 14:07:20 1987
--- misc.c	Fri Aug  7 14:06:13 1987
***************
*** 1,10 ****
  /*
   * $Log:	misc.c,v $
   * Revision 1.1  86/12/11  12:53:23  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: misc.c,v 1.1 86/12/11 12:53:23 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)misc.c	4.3 (Berkeley) 85/08/30";
  #include "defs"
  
--- 1,13 ----
  /*
   * $Log:	misc.c,v $
+  * Revision 1.2  87/08/07  14:06:10  gww
+  * Add include Files feature.
+  * 
   * Revision 1.1  86/12/11  12:53:23  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: misc.c,v 1.2 87/08/07 14:06:10 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)misc.c	4.3 (Berkeley) 85/08/30";
  #include "defs"
  
***************
*** 345,347 ****
--- 348,391 ----
  *--qbufp = '\0';
  return(qbuf);
  }
+ 
+ #ifdef	INCLUDES
+ struct	include_stack stack[MAX_INCLUDES];
+ static	int top = -1;
+ 
+ push (file, lineno, nextc)
+ FILE *file;
+ int lineno;
+ char *nextc;
+ {
+ 	if ( top < MAX_INCLUDES-1 ) {
+ 	    top++;
+ 	    stack[top].file = file;
+ 	    stack[top].lineno = lineno;
+ 	    stack[top].nextc = nextc;
+ 	}
+ 	else fatal1("include depth > %d\n", MAX_INCLUDES);
+ }
+ 
+ FILE *
+ pop()
+ {
+ extern int	yylineno;
+ extern char	*zznextc;
+ 
+ 	if (top == -1) {
+ 		fatal("pop() trying to pop null include stack\n");
+ 	}
+ 	else {
+ 		yylineno = stack[top].lineno;
+ 		zznextc = stack[top].nextc;
+ 		return(stack[top--].file);
+ 	}
+ }
+ 
+ 
+ int empty_stack()
+ {
+ 	return( (top == -1) ? 1 : 0 );
+ }
+ #endif	INCLUDES
Index: /usr/man/man1/make.1
*** /tmp/,RCSt1000941	Fri Aug  7 15:01:47 1987
--- make.1	Fri Aug  7 15:01:20 1987
***************
*** 1,6 ****
! .\"	$Header: make.1,v 1.1 86/12/12 16:17:38 gww Exp $ ENIX BSD
  .\"
  .\" $Log:	make.1,v $
  .\" Revision 1.1  86/12/12  16:17:38  gww
  .\" Initial revision
  .\" 
--- 1,9 ----
! .\"	$Header: make.1,v 1.2 87/08/07 15:01:04 gww Exp $ ENIX BSD
  .\"
  .\" $Log:	make.1,v $
+ .\" Revision 1.2  87/08/07  15:01:04  gww
+ .\" Add include support.
+ .\" 
  .\" Revision 1.1  86/12/12  16:17:38  gww
  .\" Initial revision
  .\" 
***************
*** 233,238 ****
--- 236,254 ----
  unless the target is a directory or
  depends on the special name `.PRECIOUS'.
  .PP
+ Files may be included within a
+ .I makefile
+ similarly to the
+ .I #include
+ directive of the C preprocessor.
+ If the first seven characters of a line in a
+ .I makefile
+ are `include' and the eighth is either a blank or tab, the remainder of
+ the line is interpreted as the path name of the file to be included.
+ Marco substitutions are done on the `include' line before the path name
+ is interpreted.
+ Includes may be nested up to 20 deep.
+ .PP
  Other options:
  .TP
  .B \-i
***************
*** 281,283 ****
--- 297,303 ----
  .PP
  `VPATH' is intended to act like the System V `VPATH' support,
  but there is no guarantee that it functions identically.
+ .PP
+ `Include' is intended to act like the System V `include' support,
+ but there is no guarantee that it functions identically.
+ `include' does not follow `VPATH's.

gww@beatnix.UUCP (Gary Winiger) (03/13/88)

Subject: Make(1) does not function in conjunction with RCS +Fix
Index:	bin/make/{Makefile,defs,doname.c,files.c,main.c,misc.c}, man1/make.1 4.3BSD

Description:
	Make doesn't work in conjunction with RCS as System V works in
	conjunction with SCCS.
Repeat-By:
	Try to make a target when not all the files are checked out.
Fix:
	In 1984 a rework of the 4.1 make by Charles LaBrec (crl@purdue) was
	distributed on the Usenix 84.1 distribution tape.  Over the years
	I have pointed numerous people to this distribution when they
	asked about a make that worked with RCS.  There were two problems
	with this:  It is 4.1 make; It couldn't be distributed generally
	because all of make was reformatted and that meant that diffs wouldn't
	be of any use.  When I faced the problem at Elxsi of not being able
	to use make in conjunction with RCS files not checked out, I went to
	the 84.1 tape and got Charles' work.  Since I wanted to use 4.3 make
	(with the Elxsi extension for include), I couldn't just take the
	make from that tape.  I decided that rather than put the 4.3 make
	into Charles' make, I'd put Charles' work into 4.3 make.  I preserved
	the obnoxious formatting of 4.3 make and now offer those context
	diffs for others to use.
	The attached code solves this problem at Elxsi.

Gary..
{ucbvax!sun,uunet,lll-lcc!lll-tis,amdahl!altos86,bridge2}!elxsi!gww
--------- cut --------- snip --------- :.,$w diff -------------
Index: Makefile
*** /tmp/,RCSt1005798	Fri Aug 14 13:41:13 1987
--- Makefile	Fri Aug 14 13:39:05 1987
***************
*** 1,6 ****
! #	$Header: Makefile,v 1.2 87/08/07 14:05:43 gww Exp $ ENIX BSD
  #
  # $Log:	Makefile,v $
  # Revision 1.2  87/08/07  14:05:43  gww
  # Add include Files feature.
  # 
--- 1,9 ----
! #	$Header: Makefile,v 1.3 87/08/14 13:38:54 gww Exp $ ENIX BSD
  #
  # $Log:	Makefile,v $
+ # Revision 1.3  87/08/14  13:38:54  gww
+ # Add RCS and RCSROOT support.
+ # 
  # Revision 1.2  87/08/07  14:05:43  gww
  # Add include Files feature.
  # 
***************
*** 15,21 ****
  OBJECTS=ident.o main.o doname.o misc.o files.o dosys.o gram.o 
  LIBES= 
  LINT=	lint -ps
! DFLAGS=	-DINCLUDES
  CFLAGS=	-O -DASCARCH ${DFLAGS} -I. -I/usr/src/bin/make 
  
  all:	make
--- 18,24 ----
  OBJECTS=ident.o main.o doname.o misc.o files.o dosys.o gram.o 
  LIBES= 
  LINT=	lint -ps
! DFLAGS=	-DINCLUDES -DRCS -DRCSROOT
  CFLAGS=	-O -DASCARCH ${DFLAGS} -I. -I/usr/src/bin/make 
  
  all:	make
Index: defs
*** /tmp/,RCSt1005809	Fri Aug 14 13:41:31 1987
--- defs	Fri Aug 14 13:39:09 1987
***************
*** 1,6 ****
! /*	$Header: defs,v 1.2 87/08/07 14:05:58 gww Exp $ ENIX BSD
   *
   * $Log:	defs,v $
   * Revision 1.2  87/08/07  14:05:58  gww
   * Add include Files feature.
   * 
--- 1,9 ----
! /*	$Header: defs,v 1.3 87/08/14 13:39:07 gww Exp $ ENIX BSD
   *
   * $Log:	defs,v $
+  * Revision 1.3  87/08/14  13:39:07  gww
+  * Add RCS and RCSROOT support.
+  * 
   * Revision 1.2  87/08/07  14:05:58  gww
   * Add include Files feature.
   * 
***************
*** 69,74 ****
--- 72,91 ----
  extern char *prompt;
  extern int nopdir;
  extern char junkname[ ];
+ #ifdef	RCS
+ #define	RCS_SUF	",v"			/* suffix of RCS files */
+ extern int	coflag;			/* auto-checkout flag */
+ extern int	rmflag;			/* auto-remove flag */
+ extern struct shblock *co_cmd;		/* auto-checkout shell command */
+ extern char	RCSdir[BUFSIZ];		/* name of RCS dir */
+ extern char	*RCSsuf; 		/* suffix of RCS files */
+ extern int	dotRCS;			/* true if ./RCS exists */
+ #ifdef	RCSROOT
+ extern int	rootRCS;		/* true if RCSROOT exists */
+ #endif	RCSROOT
+ extern int	sighvalue;		/* true if SIGHUP ignored */
+ extern int	sigtvalue;		/* true if SIGTERM ignored */
+ #endif	RCS
  
  
  
***************
*** 80,85 ****
--- 97,105 ----
  	struct lineblock *linep;
  	int done:3;
  	int septype:3;
+ #ifdef	RCS
+ 	char *RCSnamep;			/* name of RCS file, if needed */
+ #endif	RCS
  	TIMETYPE modtime;
  	};
  
***************
*** 138,143 ****
--- 158,167 ----
  	char *datap;
  	};
  
+ #ifdef	RCS
+ extern struct chain *rmchain;
+ #endif	RCS
+ 
  char *copys(), *concat(), *subst();
  int *ckalloc();
  struct nameblock *srchname(), *makename();
***************
*** 155,157 ****
--- 179,185 ----
  extern empty_stack();
  extern FILE *pop();
  #endif	INCLUDES
+ #ifdef	RCS
+ TIMETYPE getrcs();
+ char	*ncat();
+ #endif	RCS
Index: doname.c
*** /tmp/,RCSt1005815	Fri Aug 14 13:42:02 1987
--- doname.c	Fri Aug 14 13:39:13 1987
***************
*** 1,10 ****
  /*
   * $Log:	doname.c,v $
   * Revision 1.1  86/12/11  12:53:12  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: doname.c,v 1.1 86/12/11 12:53:12 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)doname.c	4.8 (Berkeley) 85/09/18";
  #include "defs"
  #include <strings.h>
--- 1,13 ----
  /*
   * $Log:	doname.c,v $
+  * Revision 1.2  87/08/14  13:39:10  gww
+  * Add RCS and RCSROOT support.
+  * 
   * Revision 1.1  86/12/11  12:53:12  gww
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: doname.c,v 1.2 87/08/14 13:39:10 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)doname.c	4.8 (Berkeley) 85/09/18";
  #include "defs"
  #include <strings.h>
***************
*** 20,30 ****
--- 23,43 ----
  */
  
  extern char *sys_siglist[];
+ #ifdef	RCS
+ extern char *ctime();
+ #endif	RCS
  
+ #ifndef	RCS
  doname(p, reclevel, tval)
+ #else
+ doname(p, reclevel, tval, ochain)
+ #endif	!RCS
  register struct nameblock *p;
  int reclevel;
  TIMETYPE *tval;
+ #ifdef	RCS
+ struct chain **ochain;
+ #endif	RCS
  {
  int errstat;
  int okdel1;
***************
*** 40,45 ****
--- 53,62 ----
  char *pnamep, *p1namep, *cp;
  char *mkqlist();
  struct chain *qchain, *appendq();
+ #ifdef	RCS
+ struct chain *cochain;
+ int	setimpl;		/* set implicit vars */
+ #endif	RCS
  
  if(p == 0)
  	{
***************
*** 55,60 ****
--- 72,86 ----
  
  if(p->done > 0)
  	{
+ #ifdef	RCS
+ 	/*
+ 	 * if we want to check-out RCS files, and we have previously
+ 	 * determined that we can, then append it to the previous 
+ 	 * level's cochain.
+ 	 */
+ 	if (p->RCSnamep)
+ 		*ochain = appendq(*ochain, p->namep);
+ #endif	RCS
  	*tval = p->modtime;
  	return(p->done == 3);
  	}
***************
*** 63,69 ****
--- 89,100 ----
  tdep = 0;
  implcom = 0;
  explcom = 0;
+ #ifndef	RCS
  ptime = exists(p); 
+ #else
+ cochain = NULL;
+ ptime = exists(p, ochain); 
+ #endif	RCS
  ptime1 = 0;
  didwork = NO;
  p->done = 1;	/* avoid infinite loops */
***************
*** 86,94 ****
--- 117,131 ----
  	td = 0;
  	for(q = lp->depp ; q ; q = q->nxtdepblock)
  		{
+ #ifndef	RCS
  		errstat += doname(q->depname, reclevel+1, &td1);
  		if(dbgflag)
  		    printf("TIME(%s)=%ld\n", q->depname->namep, td1);
+ #else
+ 		errstat += doname(q->depname, reclevel+1, &td1, &cochain);
+ 		if(dbgflag)
+ 		    printf("TIME(%s)=%s", q->depname->namep, ctime(&td1)+4);
+ #endif	!RCS
  		if(td1 > td) td = td1;
  		if(ptime < td1)
  			qchain = appendq(qchain, q->depname->namep);
***************
*** 104,111 ****
--- 141,155 ----
  			setvar("?", mkqlist(qchain) );
  			qchain = NULL;
  			if( !questflag )
+ #ifdef	RCS
+ 				if (cochain)
+ 					co(cochain);
+ #endif	RCS
  				errstat += docom(lp->shp);
  			setvar("@", (char *) NULL);
+ #ifdef	RCS
+ 			cochain = NULL;
+ #endif	RCS
  			okdel = okdel1;
  			ptime1 = prestime();
  			didwork = YES;
***************
*** 127,132 ****
--- 171,179 ----
  
  /* Look for implicit dependents, using suffix rules */
  
+ #ifdef	RCS
+ setimpl = 0;
+ #endif	RCS
  for(lp = sufflist ; lp ; lp = lp->nxtlineblock)
      for(suffp = lp->depp ; suffp ; suffp = suffp->nxtdepblock)
  	{
***************
*** 134,140 ****
--- 181,193 ----
  	if(suffix(p->namep , pnamep , prefix))
  		{
  
+ #ifndef	RCS
  		srchdir( concat(prefix,"*",temp) , NO, (struct depblock *) NULL);
+ #else
+ 		srchdir( concat(prefix,"*",temp) , NO, (struct depblock *) NULL,
+ 		YES);
+ 		srchRCS(temp);
+ #endif	!RCS
  		for(lp1 = sufflist ; lp1 ; lp1 = lp1->nxtlineblock)
  		    for(suffp1=lp1->depp ; suffp1 ; suffp1 = suffp1->nxtdepblock)
  			{
***************
*** 142,155 ****
--- 195,222 ----
  			if( (p1=srchname(concat(p1namep, pnamep ,concsuff))) &&
  			    (p2=srchname(concat(prefix, p1namep ,sourcename))) )
  				{
+ #ifndef	RCS
  				errstat += doname(p2, reclevel+1, &td);
+ #else
+ 				if (dbgflag)
+ 					printf("Found implicit match\n");
+ 				setimpl++;
+ 				errstat += doname(p2, reclevel+1, &td, 
+ 						  &cochain);
+ #endif	!RCS
  				if(ptime < td)
  					qchain = appendq(qchain, p2->namep);
+ #ifndef	RCS
  if(dbgflag) printf("TIME(%s)=%ld\n", p2->namep, td);
+ #else
+ if(dbgflag) printf("TIME(%s)=%s", p2->namep, ctime(&td)+4);
+ #endif	!RCS
  				if(td > tdep) tdep = td;
+ #ifndef	RCS
  				setvar("*", prefix);
  				if (p2->alias) setvar("<", copys(p2->alias));
  				else setvar("<", copys(p2->namep));
+ #endif	!RCS
  				for(lp2=p1->linep ; lp2 ; lp2 = lp2->nxtlineblock)
  					if(implcom = lp2->shp) break;
  				goto endloop;
***************
*** 164,173 ****
--- 231,264 ----
  
  endloop:
  
+ #ifdef	RCS
+ 	if (dbgflag) {
+ 		printf("CO(%s): %s\n", p->namep, mkqlist(cochain));
+ 		fflush(stdout);
+ 	}
+ 	if (p->RCSnamep && (explcom || implcom)) {
+ 		if (keepgoing) {
+ 			errstat++;
+ 			printf("%s has both an RCS file and rules\n", p->namep);
+ 		} else
+ 			fatal1("%s has both an RCS file and rules", p->namep);
+ 	}
+ #endif	RCS
  
  if(errstat==0 && (ptime<tdep || (ptime==0 && tdep==0) ) )
  	{
  	ptime = (tdep>0 ? tdep : prestime() );
+ #ifdef	RCS
+ 	if (cochain)
+ 		co(cochain);
+ 	if (setimpl) {
+ 		setvar("*", prefix);
+ 		if (p2->alias)
+ 			setvar("<", copys(p2->alias));
+ 		else
+ 			setvar("<", copys(p2->namep));
+ 	}
+ #endif	RCS
  	setvar("@", p->namep);
  	setvar("?", mkqlist(qchain) );
  	if(explcom)
***************
*** 195,201 ****
--- 286,296 ----
  			fatal1(" Don't know how to make %s", p->namep);
  
  	setvar("@", (char *) NULL);
+ #ifndef	RCS
  	if(noexflag || (ptime = exists(p)) == 0)
+ #else
+ 	if(noexflag || (ptime = exists(p, (struct chain **)NULL)) == 0)
+ #endif	!RCS
  		ptime = prestime();
  	}
  
***************
*** 206,217 ****
--- 301,322 ----
  	printf("`%s' is up to date.\n", p->namep);
  
  if(questflag && reclevel==0)
+ #ifndef	RCS
  	exit(ndocoms>0 ? -1 : 0);
+ #else
+ 	quit(ndocoms>0 ? -1 : 0);
+ #endif	!RCS
  
  p->done = (errstat ? 3 : 2);
  if(ptime1 > ptime) ptime = ptime1;
  p->modtime = ptime;
  *tval = ptime;
+ #ifdef	RCS
+ if (dbgflag) {
+ 	printf("%s: errstat = %d\n", p->namep, errstat);
+ 	fflush(stdout);
+ }
+ #endif	RCS
  return(errstat);
  }
  
***************
*** 320,326 ****
--- 425,435 ----
  	case '*':
  	case '?':
  	case '[':
+ #ifndef	RCS
  		if( p = srchdir(s1 , YES, q->nxtdepblock) )
+ #else
+ 		if( p = srchdir(s1 , YES, q->nxtdepblock, YES) )
+ #endif	!RCS
  			{
  			q->nxtdepblock = p;
  			q->depname = 0;
Index: files.c
*** /tmp/,RCSt1005820	Fri Aug 14 13:42:21 1987
--- files.c	Fri Aug 14 13:39:20 1987
***************
*** 1,5 ****
--- 1,8 ----
  /*
   * $Log:	files.c,v $
+  * Revision 1.4  87/08/14  13:39:14  gww
+  * Add RCS and RCSROOT support.
+  * 
   * Revision 1.3  86/12/12  17:27:34  gww
   * Don't dereference null pointer when VPATH is not defined.
   * 
***************
*** 11,17 ****
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: files.c,v 1.3 86/12/12 17:27:34 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)files.c	4.12 (Berkeley) 86/01/09";
  #include <fcntl.h>
  
--- 14,20 ----
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: files.c,v 1.4 87/08/14 13:39:14 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)files.c	4.12 (Berkeley) 86/01/09";
  #include <fcntl.h>
  
***************
*** 27,32 ****
--- 30,41 ----
  #else
  	".SUFFIXES : .out .o .c .F .f .e .r .y .yr .ye .l .s .cl .p",
  #endif
+ #ifdef	RCS
+ 	"CO=co",
+ 	"COFLAGS=-q",
+ 	"RM=rm",
+ 	"RMFLAGS=-f",
+ #endif	RCS
  	"YACC=yacc",
  	"YACCR=yacc -r",
  	"YACCE=yacc -e",
***************
*** 34,40 ****
  	"LEX=lex",
  	"LFLAGS=",
  	"CC=cc",
! #if defined(vax) || defined(sun)
  	"AS=as",
  #else
  	"AS=as -",
--- 43,49 ----
  	"LEX=lex",
  	"LFLAGS=",
  	"CC=cc",
! #if defined(vax) || defined(sun) || defined(elxsi)
  	"AS=as",
  #else
  	"AS=as -",
***************
*** 55,60 ****
--- 64,77 ----
  	"CMFLAGS=",
  #endif
  
+ #ifdef	RCS
+ 	".CO :",
+ 	"\t$(CO) $(COFLAGS) $@",
+ 	
+ 	".CLEANUP :",
+ 	"\t$(RM) $(RMFLAGS) $?",
+ #endif	RCS
+ 
  	".c.o :",
  	"\t$(CC) $(CFLAGS) -c $<",
  
***************
*** 152,159 ****
--- 169,183 ----
  
  
  TIMETYPE 
+ #ifndef	RCS
  exists(pname)
+ #else
+ exists(pname, ch)
+ #endif	!RCS
  struct nameblock *pname;
+ #ifdef	RCS
+ struct chain **ch;
+ #endif	RCS
  {
  struct stat buf;
  register char *s, *filename;
***************
*** 176,182 ****
--- 200,216 ----
  		pname->alias = copys(s);
  		if(stat(pname->alias, &buf) == 0)
  			return(buf.st_mtime);
+ #ifdef	RCS
+ 		if (coflag && ch)
+ 			return(getrcs(pname, pname->alias, ch));
+ 		else
+ 			return(0);
+ #endif	RCS
  	}
+ #ifdef	RCS
+ 	if (coflag && ch)
+ 		return(getrcs(pname, filename, ch));
+ #endif	RCS
  	return(0);
  }
  else	return(buf.st_mtime);
***************
*** 197,206 ****
--- 231,247 ----
  
  
  
+ #ifndef	RCS
  struct depblock *srchdir(pat, mkchain, nextdbl)
+ #else
+ struct depblock *srchdir(pat, mkchain, nextdbl, die)
+ #endif	!RCS
  register char *pat; /* pattern to be matched in directory */
  int mkchain;  /* nonzero if results to be remembered */
  struct depblock *nextdbl;  /* final value for chain */
+ #ifdef	RCS
+ int die;		/* fatal error if we can't open dir */
+ #endif	RCS
  {
  DIR *dirf;
  register int i;
***************
*** 214,219 ****
--- 255,263 ----
  struct varblock *cp, *varptr();
  char *path, pth[BUFSIZ], *strcpy();
  struct direct *dptr;
+ #ifdef	RCS
+ char	temp2[BUFSIZ], *RCSpref;
+ #endif	RCS
  
  
  thisdbl = 0;
***************
*** 259,264 ****
--- 303,317 ----
        *path++ = '\0';
        break;
        }
+ #ifdef	RCS
+ 	RCSpref = NULL;
+ 	if (coflag && !mkchain) {
+ 		if (suffix(dirname, RCSdir, temp2))
+ 			RCSpref = temp2;
+ 		else
+ 			RCSpref = dirpref;
+ 	}
+ #endif	RCS
  
  dirf = NULL;
  cldir = NO;
***************
*** 277,283 ****
  	dirf = opendir(dirname);
  	if(nopdir >= MAXDIR)
  		cldir = YES;
! 	else	{
  		++nopdir;
  		od = ALLOC(dirhdr);
  		od->nxtopendir = firstod;
--- 330,336 ----
  	dirf = opendir(dirname);
  	if(nopdir >= MAXDIR)
  		cldir = YES;
! 	else if(dirf != NULL) {
  		++nopdir;
  		od = ALLOC(dirhdr);
  		od->nxtopendir = firstod;
***************
*** 290,298 ****
--- 343,360 ----
  
  if(dirf == NULL)
  	{
+ #ifdef	RCS
+ 	if (die) {
+ #endif	RCS
  	fprintf(stderr, "Directory %s: ", dirname);
  	fatal("Cannot open");
  	}
+ #ifdef	RCS
+ 	if (endir)
+ 		*endir = '/';
+ 	return(NULL);
+ 	}
+ #endif	RCS
  
  else for (dptr = readdir(dirf); dptr != NULL; dptr = readdir(dirf))
  	{
***************
*** 312,317 ****
--- 374,396 ----
  			thisdbl->depname = q;
  			nextdbl = thisdbl;
  			}
+ #ifdef	RCS
+ 			/*
+ 			 * if RCSpref is non-null, it is the dirpref
+ 			 * without the "RCS/".  This, along with RCS_SUF
+ 			 * is stripped so implicit rules can find the
+ 			 * corresponding files
+ 			 */
+ 			if (!suffix(nbuf, RCSsuf, nbuf))
+ 				continue;
+ 			if (RCSpref)
+ 				p1=ncat(fullname, RCSpref, -1);
+ 			else
+ 				p1 = fullname;
+ 			ncat(p1, nbuf, -1);
+ 			if (srchname(fullname) == NULL)
+ 				makename(copys(fullname));
+ #endif	RCS
  		}
  	}
  
***************
*** 666,668 ****
--- 745,905 ----
  		}
  	*d = '\0';
  }
+ #ifdef	RCS
+ 
+ extern char *rindex();
+ extern struct chain *appendq();
+ 
+ /*
+  * Try to find an RCS file corresponding to 'filename', and return
+  *	the modified time of the RCS file.
+  * If ch is non-null, then append it on the chain for later check-out
+  */
+ TIMETYPE 
+ getrcs(p, filename, ch)
+ struct nameblock *p;
+ register char *filename;
+ struct chain **ch;
+ {
+ 	struct stat sbuf;
+ 	char temp[BUFSIZ];
+ 	register char *tail;
+ 	register char *s;
+ 	int headlen;
+ 
+ 	if ((tail = rindex(filename, '/')) == NULL) {
+ 		headlen = 0;
+ 		tail = filename;
+ 	} else
+ 		headlen = ++tail - filename;
+ 	s = ncat(temp, filename, headlen);
+ 	s = ncat(s, RCSdir, -1);
+ 	*s++ = '/';
+ 	s = ncat(s, tail, -1);
+ 	ncat(s, RCSsuf, -1);
+ 	if (stat(temp, &sbuf) < 0) {
+ 		concat(filename, RCSsuf, temp);
+ 		if (stat(temp, &sbuf) < 0)
+ 			return(0);
+ 	}
+ 	p->RCSnamep = copys(temp);
+ 	if (ch)
+ 		*ch = appendq(*ch, filename);
+ 	return(sbuf.st_mtime);
+ }
+ 
+ /*
+  * Try to check-out the files specified in ch, if they do not
+  *	already exist.  If rmflag is true, mark successful attempts
+  *	for automatic deletion.
+  * Try to make the modified time of the file the same as that of the
+  *	RCS file.
+  */
+ co(ch)
+ register struct chain *ch;
+ {
+ 	register struct nameblock *p;
+ 	register char *file;
+ 	char *RCSfile;
+ 	struct stat sbuf;
+ 	int i;
+ 	time_t tm[2];
+ 	
+ 	for ( ; ch; ch = ch->nextp) {
+ 		if ((file=ch->datap) == NULL || (p=srchname(file)) == NULL)
+ 			continue;
+ 		if (stat(file, &sbuf) == 0)
+ 			continue;	/* don't do it again */
+ 		RCSfile = p->RCSnamep;
+ 		p->RCSnamep = NULL;
+ 		setvar("@", file);
+ 		setvar("<", RCSfile);
+ 		i = docom(co_cmd);
+ 		setvar("@", (char *) NULL);  /* so it doesn't get deleted */
+ 		if (i)
+ 			continue;	/* docom() failed */
+ 		/*
+ 		 * since we succeeded, mark it for later deletion
+ 		 */
+ 		if (rmflag && !isprecious(file))
+ 			rmchain = appendq(rmchain, file);
+ 		/*
+ 		 * try to set modified time on file
+ 		 */
+ 		if (stat(RCSfile, &sbuf) == 0) {
+ 			tm[0] = time((time_t *) NULL);
+ 			tm[1] = sbuf.st_mtime;
+ 			utime(file, tm);
+ 		}
+ 	}
+ }
+ 
+ /*
+  * delete the files listed in rmchain
+  */
+ 
+ rm ()
+ {
+ 	register struct chain *q;
+ 	struct nameblock *p;
+ 	register struct lineblock *lp;
+ 	register struct shblock *sp;
+ 	static int once = 0;
+ 
+ 	if (once || (q = rmchain) == NULL)  /* only if we should */
+ 		return;
+ 	once = 1;
+ 	if ((p = srchname(".CLEANUP")) == NULL)
+ 		return;
+ 	sp = NULL;
+ 	for (lp = p->linep; lp; lp = lp->nxtlineblock)
+ 		if (sp = lp->shp)
+ 			break;
+ 	if (sp == NULL)			/* no or NULL .CLEANUP ? */
+ 		return;
+ 	setvar("?", mkqlist(q));
+ 	docom(sp);	
+ }
+ 
+ /*
+  * Do the srchdir for RCS files.  For a pattern a/b, it searches 
+  * a/RCS/b, without generating an error if it doesn't exist
+  */
+ srchRCS(pat)
+ register char *pat;
+ {
+ 	char temp[BUFSIZ];
+ 	int headlen;
+ 	register char *tail, *s;
+ 
+ 	if ((tail = rindex(pat, '/')) == NULL) {
+ 					/* quick search for '.' */
+ 		if (dotRCS) {
+ 			s = ncat(temp, RCSdir, -1);
+ 			*s++ = '/';
+ 			ncat(s, pat, -1);
+ 			srchdir(temp, NO, (struct depblock *) NULL, NO);
+ #ifdef	RCSROOT
+ 		} else if (rootRCS) {
+ 			s = ncat(temp, RCSdir, -1);
+ 			ncat(s, pat, -1);
+ 			srchdir(temp, NO, (struct depblock *) NULL, NO);
+ #endif	RCSROOT
+ 		}
+ 		return;
+ #ifdef	RCSROOT
+ 	} else if (rootRCS) {
+ 		s = ncat(temp, RCSdir, -1);
+ 		ncat(s, pat, -1);
+ #endif	RCSROOT
+ 	} else {
+ 		tail++;
+ 		headlen = tail - pat;
+ 		s = ncat(temp, pat, headlen);
+ 		s = ncat(s, RCSdir, -1);
+ 		*s++ = '/';
+ 		ncat(s, tail, -1);
+ 	}
+ 	srchdir(temp, NO, (struct depblock *) NULL, NO);
+ }
+ #endif	RCS
Index: main.c
*** /tmp/,RCSt1005825	Fri Aug 14 13:42:36 1987
--- main.c	Fri Aug 14 13:39:25 1987
***************
*** 1,5 ****
--- 1,8 ----
  /*
   * $Log:	main.c,v $
+  * Revision 1.3  87/08/14  13:39:21  gww
+  * Add RCS and RCSROOT support.
+  * 
   * Revision 1.2  87/08/07  14:06:06  gww
   * Add include Files feature.
   * 
***************
*** 7,30 ****
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: main.c,v 1.2 87/08/07 14:06:06 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)main.c	4.8 (Berkeley) 86/01/09";
  # include "defs"
  /*
  command make to update programs.
! Flags:	'd'  print out debugging comments
  	'p'  print out a version of the input graph
  	's'  silent mode--don't print out commands
  	'f'  the next argument is the name of the description file;
  	     "makefile" is the default
  	'i'  ignore error codes from the shell
  	'S'  stop after any command fails (normally do parallel work)
  	'n'   don't issue, just print, commands
  	't'   touch (update time of) files but don't issue command
  	'q'   don't do anything, but check if object is up to date;
  	      returns exit code 0 if up to date, -1 if not
  */
  
  struct nameblock *mainname	= NULL;
  struct nameblock *firstname	= NULL;
  struct lineblock *sufflist	= NULL;
--- 10,45 ----
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: main.c,v 1.3 87/08/14 13:39:21 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)main.c	4.8 (Berkeley) 86/01/09";
  # include "defs"
  /*
  command make to update programs.
! Flags:	
! 	'c'  don't check out RCS files
! 	'C'  check out RCS files (default)
! 	'd'  print out debugging comments
  	'p'  print out a version of the input graph
  	's'  silent mode--don't print out commands
  	'f'  the next argument is the name of the description file;
  	     "makefile" is the default
  	'i'  ignore error codes from the shell
+ 	'k'  don't stop after any command fails (default)
  	'S'  stop after any command fails (normally do parallel work)
  	'n'   don't issue, just print, commands
+ 	'r'   don't use default rules
  	't'   touch (update time of) files but don't issue command
+ 	'u'   don't unlink RCS working files
+ 	'U'   unlink RCS working files
  	'q'   don't do anything, but check if object is up to date;
  	      returns exit code 0 if up to date, -1 if not
  */
  
+ /*
+  *	This version is based on the modifications made to the 4.1 make
+  *	made by Charles LaBrec, Purdue University Physics Dept.
+  */
+ 
  struct nameblock *mainname	= NULL;
  struct nameblock *firstname	= NULL;
  struct lineblock *sufflist	= NULL;
***************
*** 32,37 ****
--- 47,71 ----
  struct pattern *firstpat	= NULL;
  struct dirhdr *firstod		= NULL;
  
+ #ifdef	RCS
+ struct shblock *co_cmd		= NULL;
+ struct chain *rmchain		= NULL;
+ 
+ #include <sys/stat.h>
+ 
+ int rmflag = YES;
+ int coflag = YES;
+ char RCSdir[BUFSIZ] = "RCS";
+ char *RCSsuf = RCS_SUF;
+ int dotRCS = NO;
+ #ifdef	RCSROOT
+ int rootRCS = NO;
+ #endif	RCSROOT
+ int sighvalue = 0;
+ int sigtvalue = 0;
+ extern	char *getenv(), *getwd();
+ #endif	RCS
+ 
  #include <signal.h>
  int sigivalue	= 0;
  int sigqvalue	= 0;
***************
*** 73,78 ****
--- 107,117 ----
  int intrupt();
  #endif
  char *op = options + 1;
+ #ifdef	RCS
+ struct lineblock *lp;
+ struct stat sbuf;
+ struct chain *ch;
+ #endif	RCS
  
  
  #ifdef METERFILE
***************
*** 102,107 ****
--- 141,156 ----
  			*op++ = c;
  			switch (c) {
  
+ #ifdef	RCS
+ 			case 'c':
+ 				coflag = NO;
+ 				break;
+ 
+ 			case 'C':
+ 				coflag = YES;
+ 				break;
+ #endif	RCS
+ 
  			case 'd':
  				dbgflag = YES;
  				break;
***************
*** 142,147 ****
--- 191,206 ----
  				questflag = YES;
  				break;
  
+ #ifdef	RCS
+ 			case 'u':
+ 				rmflag = NO;
+ 				break;
+ 
+ 			case 'U':
+ 				rmflag = YES;
+ 				break;
+ #endif	RCS
+ 
  			case 'f':
  				op--;		/* don't pass this one */
  				if(i >= argc-1)
***************
*** 175,180 ****
--- 234,250 ----
  
  if(prtrflag) printdesc(NO);
  
+ #ifdef	RCS
+ if (p = srchname(".CO")) {
+ 	for (lp = p->linep; lp; lp = lp->nxtlineblock)
+ 		if ((co_cmd = lp->shp) != NULL)
+ 			break;
+ 	if (co_cmd == NULL)
+ 		coflag = NO;
+ } else
+ 	coflag = NO;
+ #endif	RCS
+ 
  if( srchname(".IGNORE") ) ++ignerr;
  if( srchname(".SILENT") ) silflag = 1;
  if(p=srchname(".SUFFIXES")) sufflist = p->linep;
***************
*** 183,191 ****
--- 253,298 ----
  #ifdef unix
  sigivalue = (int) signal(SIGINT, SIG_IGN) & 01;
  sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01;
+ #ifdef	RCS
+ sighvalue = (int) signal(SIGHUP, SIG_IGN) & 01;
+ sigtvalue = (int) signal(SIGTERM, SIG_IGN) & 01;
+ #endif	RCS
  enbint(intrupt);
  #endif
  
+ #ifdef	RCS
+ 	if (stat(RCSdir, &sbuf) == 0 && (sbuf.st_mode & S_IFMT) == S_IFDIR)
+ 		dotRCS = YES;		/* fast check for ./RCS */
+ #ifdef	RCSROOT
+ 	/* NOTE: dotRCS == YES implies rootRCS == NO */
+ 	else {
+ 		char pathname[BUFSIZ];
+ 		char *rcsroot;
+ 
+ 		if (rcsroot = getenv("RCSROOT")) {
+ 			strcpy(RCSdir, rcsroot);
+ 			strncat(RCSdir, getwd(pathname), BUFSIZ);
+ 			if ((stat(RCSdir, &sbuf) == 0) && 
+ 			    ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+ 				strncat(RCSdir, "/", BUFSIZ);
+ 				rootRCS = YES;
+ 			}
+ 		}
+ 		if (!rootRCS) {
+ 			strcpy(RCSdir, "/RCS");
+ 			strncat(RCSdir, getwd(pathname), BUFSIZ);
+ 			if ((stat(RCSdir, &sbuf) == 0) && 
+ 			    ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+ 				strncat(RCSdir, "/", BUFSIZ);
+ 				rootRCS = YES;
+ 			}
+ 			else
+ 				RCSdir[0] = '\0';
+ 		}
+ 	}
+ #endif	RCSROOT
+ #endif	RCS
+ 
  nfargs = 0;
  
  for(i=1; i<argc; ++i)
***************
*** 196,202 ****
--- 303,314 ----
  			p = makename(s);
  			}
  		++nfargs;
+ #ifndef	RCS
  		doname(p, 0, &tjunk);
+ #else
+ 		ch = NULL;
+ 		doname(p, 0, &tjunk, &ch);
+ #endif	!RCS
  		if(dbgflag) printdesc(YES);
  		}
  
***************
*** 209,222 ****
--- 321,345 ----
  	if(mainname == 0)
  		fatal("No arguments or description file");
  	else	{
+ #ifndef	RCS
  		doname(mainname, 0, &tjunk);
+ #else
+ 		ch = NULL;
+ 		doname(mainname, 0, &tjunk, &ch);
+ #endif	!RCS
  		if(dbgflag) printdesc(YES);
  		}
  
+ #ifndef	RCS
  exit(0);
+ #else
+ quit(0);
+ #endif	!RCS
  }
  
+ #ifndef	RCS
  #include <sys/stat.h>
+ #endif	!RCS
  
  #ifdef unix
  intrupt()
***************
*** 238,244 ****
--- 361,371 ----
  if(junkname[0])
  	unlink(junkname);
  fprintf(stderr, "\n");
+ #ifndef	RCS
  exit(2);
+ #else
+ quit(2);
+ #endif	!RCS
  }
  
  
***************
*** 268,273 ****
--- 395,406 ----
  	signal(SIGINT,k);
  if(sigqvalue == 0)
  	signal(SIGQUIT,k);
+ #ifdef	RCS
+ if(sighvalue == 0)
+ 	signal(SIGHUP,k);
+ if(sigtvalue == 0)
+ 	signal(SIGTERM,k);
+ #endif	RCS
  }
  #endif
  
Index: misc.c
*** /tmp/,RCSt1005830	Fri Aug 14 13:42:51 1987
--- misc.c	Fri Aug 14 13:39:54 1987
***************
*** 1,5 ****
--- 1,8 ----
  /*
   * $Log:	misc.c,v $
+  * Revision 1.3  87/08/14  13:39:26  gww
+  * Add RCS and RCSROOT support.
+  * 
   * Revision 1.2  87/08/07  14:06:10  gww
   * Add include Files feature.
   * 
***************
*** 7,13 ****
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: misc.c,v 1.2 87/08/07 14:06:10 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)misc.c	4.3 (Berkeley) 85/08/30";
  #include "defs"
  
--- 10,16 ----
   * Initial revision
   * 
   */
! static char *ERcsId = "$Header: misc.c,v 1.3 87/08/14 13:39:26 gww Exp $ ENIX BSD";
  static	char *sccsid = "@(#)misc.c	4.3 (Berkeley) 85/08/30";
  #include "defs"
  
***************
*** 274,283 ****
--- 277,294 ----
  if(s) fprintf(stderr, "Make: %s.  Stop.\n", s);
  else fprintf(stderr, "\nStop.\n");
  #ifdef unix
+ #ifndef	RCS
  exit(1);
+ #else
+ quit(1);
+ #endif	!RCS
  #endif
  #ifdef gcos
+ #ifndef	RCS
  exit(0);
+ #else
+ quit(0);
+ #endif	!RCS
  #endif
  }
  
***************
*** 389,391 ****
--- 400,439 ----
  	return( (top == -1) ? 1 : 0 );
  }
  #endif	INCLUDES
+ 
+ #ifdef	RCS
+ quit(val)
+ int val;
+ {
+ 	if (rmflag) {			/* clean up co'ed files */
+ 		touchflag = 0;		/* don't try to touch anything */
+ 		rm();
+ 	}
+ 	exit(val);
+ }
+ 
+ /*
+  * ncat copies n chars of string b at a, returning a pointer to the
+  * null terminating a.  This way, it can be used to daisy-chain.
+  * If n < 0, all chars of b will be copied
+  */
+ char *
+ ncat(a, b, n)
+ register char *a, *b;
+ register int n;
+ {
+ 	if (n < 0) {
+ 		while(*a++ = *b++)
+ 			;
+ 		return(--a);
+ 	} else {
+ 		if (n != 0) 
+ 			do {
+ 				if ((*a++ = *b++) == '\0')
+ 					return(--a);
+ 			} while (--n);
+ 		*a = '\0';
+ 		return(a);
+ 	}
+ }
+ #endif	RCS
Index: /usr/man/man1/make.1
*** /tmp/,RCSt1005207	Thu Mar 10 15:48:37 1988
--- make.1e	Thu Mar 10 15:47:58 1988
***************
*** 1,6 ****
! .\"	$Header: make.1e,v 1.2 87/08/07 15:01:04 gww Exp $ ENIX BSD
  .\"
  .\" $Log:	make.1e,v $
  .\" Revision 1.2  87/08/07  15:01:04  gww
  .\" Add include support.
  .\" 
--- 1,9 ----
! .\"	$Header: make.1e,v 1.3 88/03/10 15:47:50 gww Exp $ ENIX BSD
  .\"
  .\" $Log:	make.1e,v $
+ .\" Revision 1.3  88/03/10  15:47:50  gww
+ .\" Add RCS support.
+ .\" 
  .\" Revision 1.2  87/08/07  15:01:04  gww
  .\" Add include support.
  .\" 
***************
*** 149,155 ****
  is inferred.
  The default list is
  .IP
! \&.SUFFIXES: .out .o .c .e .r .f .y .l .s .p
  .PP
  The rule to create a file with suffix
  .I s2
--- 152,158 ----
  is inferred.
  The default list is
  .IP
! \&.SUFFIXES: .out .o .c .F .f .e .r .y .yr .ye .l .s .cl .p
  .PP
  The rule to create a file with suffix
  .I s2
***************
*** 216,221 ****
--- 219,226 ----
  .PP
  Command lines are executed one at a time, each by its
  own shell.
+ The default shell is
+ .IR sh (1).
  A line is printed when it is executed unless
  the special target `.SILENT'
  is in 
***************
*** 249,256 ****
--- 254,384 ----
  is interpreted.
  Includes may be nested up to 20 deep.
  .PP
+ .I Make
+ functions in conjunction with RCS (Revision Control System).
+ Unless the \-c option is specified,
+ if the search for a file (called the working file) fails,
+ .I make
+ looks for a corresponding RCS file.
+ For example, if a file xxx does not exist, ./RCS/xxx,v,
+ then enviroment variable RCSROOT/\fIcurrent-directory\fP/xxx,v,
+ then /RCS/\fIcurrent-directory\fP/xxx,v,
+ and finally ./xxx,v are searched for in that order.
+ (When subdirectories are specified, e.g., xxx/yyy, xxx/RCS/yyy,v,
+ RCSROOT/\fIcurrent-directory\fP/xxx/yyy,v,
+ /RCS/\fIcurrent-directory\fP/xxx/yyy,v,
+ and xxx/yyy,v are tried.)
+ If the search is successful, the `last modified' time of the RCS file
+ is considered to be the modified time of the working file, and 
+ .I make
+ remembers that the working file must be checked out.
+ When the time comes to actually make a target, each of these dependents
+ is retrieved from RCS using the target `.CO'.
+ The default rule is:
+ .RS
+ .HP
+ .PD 0
+ .nf
+ \&.CO:
+ $(CO) $(COFLAGS) $@
+ .fi
+ .RE
+ .PD
+ .PP
+ where by default
+ .PP
+ .RS
+ .nf
+ CO = co
+ COFLAGS = -q
+ .fi
+ .RE
+ .PP
+ Also, the special macro `$@' is set to the name of the working
+ file and `$<' to the name of the RCS file (in the spirit that
+ this is an implicit command).
+ Note, however, that `$?' and `$*' have no meaning here.
+ Furthermore, after the check-out is complete,
+ .I make
+ will try to set the modified time of `$@' to that of the RCS file
+ in accordance with its earlier assumption.
+ Since this is the time that has been used throughout execution,
+ there is no way to avoid this action.
+ Also, unless \-u was specified or the working file is mentioned as
+ a dependent of `.PRECIOUS',  it will be removed on exit.
+ If the `.CO' target is missing or has no commands associated with it,
+ then the effect is the same as if \-c had been specified.
+ .PP
+ When 
+ .I make
+ terminates, if any files that were automatically checked out are marked
+ for deletion,
+ it will run the special target `.CLEANUP'.
+ The default rule is:
+ .nf
+ .RS
+ .HP
+ .PD 0
+ \&.CLEANUP:
+ $(RM) $(RMFLAGS) $?
+ .PD
+ .RE
+ .fi
+ .PP
+ where:
+ .PP
+ .RS
+ .nf
+ RM = rm
+ RMFLAGS = -f
+ .RE
+ .fi
+ .PP
+ and the macro `$?' is set to the names of the files that
+ were checked out previously and are not dependents of the
+ target `.PRECIOUS'.
+ If `.CLEANUP' is missing, has no commands associated with it, or `$?'
+ is blank, the effect is the same as if \-u had been specified.
+ .PP
+ The exact form of the `.CO' target is probably open to debate.
+ Since 
+ .IR co (1)
+ strips subdirectories from working file names, but not RCS file names,
+ the `correct' form of the `.CO' should probably be:
+ .PP
+ .RS
+ $(CO) $(COFLAGS) -p $< > $@
+ .RE
+ .PP
+ However, in executing a command,
+ .I make
+ looks at it for the special shell characters:
+ .PP
+ .RS
+ =|^();&<>*?[]:$`'"\\\\n
+ .RE
+ .PP
+ If none are detected, the command is executed directly, without
+ a shell.
+ Thus, the latter form of the `.CO' target is less efficient, since
+ a shell must be used to do the redirection (`>').
+ Furthermore, the former description fails only when RCS files in
+ subdirectories other than `.' or `./RCS' must be checked out.
+ For this reason, the `less correct' rule has been chosen.
+ .PP
  Other options:
  .TP
+ .B \-c
+ If a file does not exist, do not try to find a corresponding
+ RCS file and check it out.
+ .TP
+ .B \-C
+ Try to get the file from RCS (this is the default). 
+ .TP
+ .B \-d
+ Print debugging information (relatively useless except for
+ trying to find out what went wrong).
+ .TP
  .B \-i
  Equivalent to the special entry `.IGNORE:'.
  .TP
***************
*** 263,284 ****
  Trace and print, but do not execute the commands
  needed to update the targets.
  .TP
! .B \-t
! Touch, i.e. update the modified date of targets, without
! executing any commands.
  .TP
  .B \-r
! Equivalent to an initial special entry `.SUFFIXES:'
! with no list.
  .TP 
  .B \-s
  Equivalent to the special entry
  `.SILENT:'.
  .SH FILES
  makefile, Makefile
  .br
  .SH "SEE ALSO"
! sh(1), touch(1), f77(1), pc(1)
  .br
  S. I. Feldman
  .I
--- 391,429 ----
  Trace and print, but do not execute the commands
  needed to update the targets.
  .TP
! .B \-p
! Print a version of the input graph.
  .TP
+ .B \-q
+ Don't do anything, but check if object is up to date.
+ Return exit status 0 if it is, -1 if it is not.
+ .TP
  .B \-r
! Do not use the default set of rules.
! .TP
! .B \-S
! The inverse of
! .BR \-k .
  .TP 
  .B \-s
  Equivalent to the special entry
  `.SILENT:'.
+ .TP
+ .B \-t
+ Touch, i.e. update the modified date of targets, without
+ executing any commands.
+ .TP 
+ .B \-u
+ Don't cleanup files that were automatically checked-out from RCS.
+ .TP
+ .B \-U
+ Cleanup files that were automatically checked-out from RCS,
+ unless they are listed in the `.PRECIOUS' target (default).
  .SH FILES
  makefile, Makefile
  .br
  .SH "SEE ALSO"
! co(1E), rcs(1E), sh(1), touch(1), utime(1)
  .br
  S. I. Feldman
  .I

mohamed@hscfvax.harvard.edu (Mohamed_el_Lozy) (03/16/88)

The two postings about make seem to have something missing.  Applying
the first patch will produce a program that fails to link, with
do_include() missing.  If -DINCLUDE is removed from the DFLAGS it will
make properly.  I very much suspect that do_include() should live in
files.c, and there are no patches for that file.

The second posting (which adds RCS compatibility) confirms that
impression.  There is a patch which takes files.c from 1.3 to 1.4.  It
takes, apart from the headers.  Like after the first patch, compilation
fails with do_include() missing, but works if you remove -DINCLUDE from
DFLAGS.

Since I do not care about the include capability, I am perfectly
satisfied.  Others may want it.

dls@s.cc.purdue.edu (David L Stevens) (03/16/88)

	You should also be aware that these changes (in an earlier version,
at least) disallow explicit rules for RCS files, as we use. This means that
Makefiles that work with the standard make(1) will generate an error and exit.
	The problem is (or was, at least) with using an explicit rule of the
form:

	${SRC}:
		co $@

	We do this (locally) for all of our Makefiles, rather than hack
make(1). We evaluated Charlie's make(1) and discovered that it generated
the error message:

<blotto> has RCS file and rules.

	Thus, Makefiles from other places that have explicit RCS rules would
require source changes and (worse) you cannot customize an RCS rule.

	I admit that I haven't tried the above on the posted diffs, but I
discussed the problem with Charlie at the time (over a year ago) and there
were some technical difficulties in making it do the "right" thing, which is
to use explicit rules when they are there and only use the implicit rules
when they aren't. I assume this incompatibility persists, but welcome someone
else to give the definitive word.
-- 
					+-DLS  (dls@s.cc.purdue.edu)

gww@beatnix.UUCP (Gary Winiger) (04/03/88)

In article <539@hscfvax.harvard.edu> mohamed@hscfvax.harvard.edu (Mohamed_el_Lozy) writes:
>The two postings about make seem to have something missing.  Applying
>the first patch will produce a program that fails to link, with
>do_include() missing.  If -DINCLUDE is removed from the DFLAGS it will
>make properly.  I very much suspect that do_include() should live in
>files.c, and there are no patches for that file.

Sorry for the length of time it has taken me to reply, I'm only at Elxsi
occassionally at present.

I don't believe that the routine ``do_include'' was missing from the posting.
``do_include'' is in gram.y.  Perhaps Mr. Mohamed_el_Lozy didn't either
clean the make directory before building with -DINCLUDE defined, or didn't
remove gram.c.  Note that make's Makefile does not have very good dependences.

Gary..