static char *RcsId = 
    "$Header: /src/bin/make/m/main.c,v 4.9 84/04/24 21:14:19 crl Exp $";

/* static char *sccsid = "@(#)main.c	4.1 (Berkeley) 81/02/28"; */

/*
 * command make to update programs.
 * Flags:
 *	'c'  don't check out RCS files
 *	'C'  check out RCS files (default)
 *	'd'  print out debugging comments
 *	'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
 *	'n'   don't issue, just print, commands
 *	'p'  print out a version of the input graph
 *	'q'   don't do anything, but check if object is up to date;
 *	      returns exit code 0 if up to date, -1 if not
 *	'r'  don't use default rules
 *	's'  silent mode--don't print out commands
 *	't'   touch (update time of) files but don't issue command
 *	'u'  don't unlink RCS working files
 *	'U'  unlink RCS working files automatically checked out (default)
 *
 *	This version has been heavily modified to understand RCS
 *	(Revision Control System) and handle the dependencies properly
 *	Comments, bugs, questions, etc can be addressed to:
 *		Charles LaBrec
 *		Purdue University
 *		Physics Dept.
 *		W. Lafayette, IN 47907
 *	or by using electronic mail:
 *		Physics:crl @ purdue.arpa
 *		{decvax,ucbvax,and more}!pur-ee!Physics:crl
 *	at least for a while
 *
 * $Log:	/src/bin/make/m/main.c,v $
 * Revision 4.9  84/04/24  21:14:19  crl
 * Set progname to be tail component of argv[0], and added some portability
 * 	casts.
 * 
 * Revision 4.8  84/04/13  01:13:24  crl
 * Prepped for distribution.
 * 
 * Revision 4.7  83/12/11  23:47:59  crl
 * Removed some casts for lint.
 * Fixed bug in super-user check in intrupt() due to precedence of '&' 
 * 	and '=='.
 * 
 * Revision 4.6  83/12/04  17:30:26  crl
 * In intrupt(), don't unlink directories if super-user.
 * 
 * Revision 4.5  83/10/31  01:33:04  crl
 * Added catching of SIGHUP and SIGTERM.
 * Corrected check of directory status of RCS.
 * Added RCSsuf and dotRCS vars.
 * 
 * Revision 4.4  83/10/22  19:19:12  crl
 * Initialize co_cmd from the target ".CO" (and turn off coflag if null)
 * 
 * Revision 4.3  83/07/23  14:49:29  crl
 * Added rmchain for later use.
 * Reversed meanings of -c[C] and -[uU] flags since this seems to make
 * 	more sense.
 * Replace TIMETYPE by time_t.
 * Include sys/types.h in defs.h instead.
 * 
 * Revision 4.2  83/07/22  14:14:49  crl
 * Made to work transparently with RCS.
 * 
 * Revision 4.1  83/03/01  00:43:54  crl
 * Vanilla 4.1 version
 */

#include "defs.h"
#include <signal.h>

#ifdef RCS
struct shblock *co_cmd		= NULL;
struct chain *rmchain		= NULL;
#endif
struct nameblock *mainname	= NULL;
struct nameblock *firstname	= NULL;
struct lineblock *sufflist	= NULL;
struct varblock *firstvar	= NULL;
struct pattern *firstpat	= NULL;
struct opendir *firstod		= NULL;

#ifdef RCS
#include <sys/stat.h>

int rmflag = YES;
int coflag = YES;
char *RCSdir = RCS;
char *RCSsuf = RCS_SUF;
int dotRCS = NO;
#endif

int sigivalue	= 0;
int sigqvalue	= 0;
int sighvalue	= 0;
int sigtvalue	= 0;

int waitpid	= 0;

int dbgflag	= NO;
int prtrflag	= NO;
int silflag	= NO;
int noexflag	= NO;
int keepgoing	= NO;
int noruleflag	= NO;
int touchflag	= NO;
int questflag	= NO;
int ndocoms	= NO;
int ignerr	= NO;    /* default is to stop on error */
int okdel	= YES;
int inarglist;

char *progname;		/* filled in with tail of argv[0] */
char *prompt	= PROMPT;

int nopdir	= 0;
char funny[128];

main(argc,argv)
int argc;
char *argv[];
{
	register struct nameblock *p;
	int i, j;
	int descset, nfargs;
	time_t tjunk;
	char c, *s;
	static char onechar[2] = "X";
	struct chain *ch;
#ifdef unix
	int intrupt();
#endif
#ifdef RCS
	struct lineblock *lp;
	struct stat sbuf;
#endif

	if ((progname = rindex(argv[0], '/')) == NULL)	/* set up our name */
		progname = argv[0];
	else
		progname++;

#ifdef METERFILE
	meter(METERFILE);
#endif

	descset = 0;

	funny['\0'] = (META | TERMINAL);
	for(s = "=|^();&<>*?[]:$`'\"\\\n" ; *s ; ++s)
		funny[*s] |= META;
	for(s = "\n\t :;&>|" ; *s ; ++s)
		funny[*s] |= TERMINAL;


	inarglist = 1;
	for(i=1; i<argc; ++i)
		if(argv[i]!=0 && argv[i][0]!='-' && eqsign(argv[i]))
			argv[i] = 0;

	setvar("$","$");
	inarglist = 0;

	for(i=1; i<argc; ++i)
		if(argv[i]!=0 && argv[i][0]=='-') {
			for(j=1 ; (c=argv[i][j])!='\0' ; ++j)
				switch(c) {
#ifdef RCS
				case 'c':
					coflag = NO;
					break;
				case 'C':
					coflag = YES;
					break;
#endif
				case 'd':
					dbgflag = YES;
					break;
				case 'p':
					prtrflag = YES;
					break;
				case 's':
					silflag = YES;
					break;
				case 'i':
					ignerr = YES;
					break;
				case 'S':
					keepgoing = NO;
					break;
				case 'k':
					keepgoing = YES;
					break;
				case 'n':
					noexflag = YES;
					break;
				case 'r':
					noruleflag = YES;
					break;
				case 't':
					touchflag = YES;
					break;
				case 'q':
					questflag = YES;
					break;
#ifdef RCS
				case 'u':
					rmflag = NO;
					break;
				case 'U':
					rmflag = YES;
					break;
#endif
				case 'f':
					if(i >= argc-1)
						fatal("No description argument after -f flag");
					if( rddescf(argv[i+1]) )
						fatal1("Cannot open %s", argv[i+1]);
					argv[i+1] = 0;
					++descset;
					break;
	
				default:
					onechar[0] = c;	/* to make lint happy */
					fatal1("Unknown flag argument %s", onechar);
				}
	
				argv[i] = 0;
			}

	if( !descset )
#ifdef unix
		if( rddescf("makefile") )
			rddescf("Makefile");
#endif
#ifdef gcos
		rddescf("makefile");
#endif

	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
	if( srchname(".IGNORE") )
		++ignerr;
	if( srchname(".SILENT") )
		silflag = 1;
	if(p = srchname(".SUFFIXES"))
		sufflist = p->linep;
	if( !sufflist )
		fprintf(stderr,"No suffix list.\n");

#ifdef unix
	sigivalue = signal(SIGINT, SIG_IGN) == SIG_IGN;
	sigqvalue = signal(SIGQUIT, SIG_IGN) == SIG_IGN;
	sighvalue = signal(SIGHUP, SIG_IGN) == SIG_IGN;
	sigtvalue = signal(SIGTERM, SIG_IGN) == SIG_IGN;
	enbint(intrupt);
#endif

#ifdef RCS
	if (stat(RCSdir, &sbuf) == 0 && (sbuf.st_mode & S_IFMT) == S_IFDIR)
		dotRCS = YES;		/* fast check for ./RCS */
#endif

	nfargs = 0;

	for(i=1; i<argc; ++i)
		if((s=argv[i]) != 0) {
			if((p=srchname(s)) == 0)
				p = makename(s);
			++nfargs;
			ch = NULL;
			doname(p, 0, &tjunk, &ch);
			if(dbgflag)
				printdesc(YES);
		}

	/*
	 * If no file arguments have been encountered, make the first
	 * name encountered that doesn't start with a dot
	 */

	if(nfargs == 0)
		if(mainname == 0)
			fatal("No arguments or description file");
		else {
			ch = NULL;
			doname(mainname, 0, &tjunk, &ch);
			if(dbgflag)
				printdesc(YES);
		}
	quit(0);
}

#ifdef unix
intrupt()
{
	char *p;
	struct stat sb;

	if(okdel && !noexflag && !touchflag && (p = varptr("@")->varval) 
			&& exists(srchname(p), (struct chain **) NULL) > 0 
			&& !isprecious(p)) {
		if(getuid() != 0) {
			if(unlink(p) == 0)
				printf("\n***  %s removed.", p);
		} else {
			if ((stat(p,&sb) == 0)
					&& ((sb.st_mode&S_IFMT) == S_IFREG))
				if (unlink(p) == 0)
					printf("\n***  %s removed.", p);
		}
	}
	printf("\n");
	fflush(stdout);
	quit(2);
}

int
isprecious(p)
char *p;
{
	register struct lineblock *lp;
	register struct depblock *dp;
	register struct nameblock *np;

	if(np = srchname(".PRECIOUS"))
		for(lp = np->linep ; lp ; lp = lp->nxtlineblock)
			for(dp = lp->depp ; dp ; dp = dp->nxtdepblock)
				if(! unequal(p, dp->depname->namep))
					return(YES);
	return(NO);
}

enbint(k)
int (*k)();
{
	if(sigivalue == 0)
		signal(SIGINT,k);
	if(sigqvalue == 0)
		signal(SIGQUIT,k);
	if(sighvalue == 0)
		signal(SIGHUP,k);
	if(sigtvalue == 0)
		signal(SIGTERM,k);
}
#endif

extern char *builtin[];

char **linesptr	= builtin;

FILE * fin;
int firstrd	= 0;

rddescf(descfile)
char *descfile;
{
	FILE * k;

	/* read and parse description */

	if( !firstrd++ ) {
		if( !noruleflag )
			rdd1((FILE *) NULL);

#ifdef pwb
		{
			char *nlog, s[100];
			nlog = logdir();
			if ((k = fopen(concat(nlog, "/makecomm", s), "r")) != NULL)
				rdd1(k);
			else if ((k = fopen(concat(nlog, "/Makecomm", s), "r")) != NULL)
				rdd1(k);

			if ((k=fopen("makecomm", "r")) != NULL)
				rdd1(k);
			else if ((k=fopen("Makecomm", "r")) != NULL)
				rdd1(k);
		}
#endif

	}
	if(! unequal(descfile, "-"))
		return(rdd1(stdin) );

	if( (k = fopen(descfile,"r")) != NULL)
		return(rdd1(k) );

	return(1);
}

rdd1(k)
FILE * k;
{
	extern int yylineno;
	extern char *zznextc;

	fin = k;
	yylineno = 0;
	zznextc = 0;

	if (yyparse())
		fatal("Description file error");

	if(fin != NULL)
		fclose(fin);

	return(0);
}

printdesc(prntflag)
int prntflag;
{
	struct nameblock *p;
	struct depblock *dp;
	struct varblock *vp;
	struct opendir *od;
	struct shblock *sp;
	struct lineblock *lp;

#ifdef unix
	if(prntflag) {
		printf("Open directories:\n");
		for (od = firstod; od; od = od->nxtopendir)
			printf("\t%d: %s\n", od->dirfc->dd_fd, od->dirn);
	}
#endif

	if(firstvar != 0)
		printf("Macros:\n");
	for(vp = firstvar; vp ; vp = vp->nxtvarblock)
		printf("\t%s = %s\n" , vp->varname , vp->varval);
	for(p = firstname; p; p = p->nxtnameblock) {
		printf("\n\n%s",p->namep);
		if (p->linep != 0)
			printf(":");
		if (prntflag)
			printf("  done=%d",p->done);
		if (p == mainname)
			printf("  (MAIN NAME)");
		for(lp = p->linep ; lp ; lp = lp->nxtlineblock) {
			if( dp = lp->depp ) {
				printf("\n depends on:");
				for(; dp ; dp = dp->nxtdepblock)
					if(dp->depname != 0)
						printf(" %s ", dp->depname->namep);
			}
			if(sp = lp->shp) {
				printf("\n commands:\n");
				for( ; sp!=0 ; sp = sp->nxtshblock)
					printf("\t%s\n", sp->shbp);
			}
		}
	}
	printf("\n");
	fflush(stdout);
}
