File:  [MW Coherent from dump] / coherent / d / bin / make / o.make.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * make -- maintain program groups
 * td 80.09.17
 * things done:
 *	20-Oct-82	Made nextc properly translate "\\\n[ 	]*" to ' '.
 *	15-Jan-85	Made portable enough for z-8000, readable enough for
 *			human beings.
 *	06-Nov-85	Added free(t) to make() to free used space.
 *	07-Nov-85	Modified docmd() to call varexp() only if 'cmd'
 *			actually contains macros, for efficiency.
 *	24-Feb-86	Minor fixes by rec to many things.  Deferred
 *			macro expansion in actions until needed, deferred
 *			getmdate() until needed, added canonicalization in
 *			archive searches, allowed ${NAME} in actions for
 *			shell to expand, put macro definitions in malloc,
 *			entered environ into macros.
 */

#include	"make.h"

char usage[] = "Usage: make [-isrntqpd] [-f file] [macro=value] [target]";
char nospace[] = "Out of space";
char badmac[] = "Bad macro name";
char incomp[] = "Incomplete line at end of file";

int iflag;			/* ignore command errors */
int sflag;			/* don't print command lines */
int rflag;			/* don't read built-in rules */
int nflag;			/* don't execute commands */
int tflag;			/* touch files rather than run commands */
int qflag;			/* zero exit status if file up to date */
int pflag;			/* print macro defns, target descriptions */
int dflag;			/* debug mode -- verbose printout */
int eflag;			/* make environ macros protected */


FILE *fd;
int defining = 0;		/* nonzero => do not expand macros */
time_t now;
unsigned char backup[NBACKUP];
int nbackup = 0;
int lastc;
int lineno;
char macroname[NMACRONAME+1];
struct token{
	struct token *next;
	char *value;
};
char *token;
char tokbuf[NTOKBUF];
int toklen;
char *tokp;
struct macro {
	struct macro *next;
	char *value;
	char *name;
	int protected;
};
struct macro *macro;
char *deftarget = NULL;
struct sym{
	struct sym *next;
	char *action;
	char *name;
	struct dep *deplist;
	int type;
	time_t moddate;
};
struct sym *sym = NULL;
struct sym *suffixes;
struct sym *deflt;

struct dep{
	struct dep *next;
	char *action;
	struct sym *symbol;
};

struct stat statbuf;
char	*mvarval[4];		/* list of macro variable values */

/* Interesting function declarations */

char *mexists();
char *extend();
char *mmalloc();
struct token *listtoken();
struct sym *sexists();
struct sym *dexists();
struct sym *lookup();
struct dep *adddep();

/* cry and die */
die(str)
char	*str;
{
	fprintf(stderr, "make: %r\n", &str);
	exit(ERROR);
}
/* print lineno, cry and die */
err(s)
char *s;
{
	fprintf(stderr, "make: %d: %r\n", lineno, &s);
	exit(ERROR);
}

/* Malloc nbytes and abort on failure */
char *mmalloc(n) int n;
{
	char *p;
	if (p = malloc(n))
		return p;
	err(nospace);
}

/* read characters from backup (where macros have been expanded) or from
 * whatever the open file of the moment is. keep track of line #s.
 */

readc()
{
	if(nbackup!=0)
		return(backup[--nbackup]);
	if(lastc=='\n')
		lineno++;
	lastc=getc(fd);
	return(lastc);
}

/* put c into backup[] */

putback(c)
{
	if(c==EOF)
		return;
	if (nbackup == NBACKUP)
		err("Macro definition too long");
	backup[nbackup++]=c;
}

/* put s into backup */

unreads(s)
register char *s;
{
	register char *t;

	t = &s[strlen(s)];
	while (t > s)
		putback(*--t);
}

/* return a pointer to the macro definition assigned to macro name s.
 * return NULL if the macro has not been defined.
 */

char *mexists(s) register char *s;
{
	register struct macro *i;

	for (i = macro; i != NULL; i=i->next)
		if (Streq(s, i->name))
			return (i->value);
	return (NULL);
}

/* install macro with name name and value value in macro[]. Overwrite an
 * existing value if it is not protected.
 */

define(name, value, protected)
register char *name, *value;
{
	register struct macro *i;

	if(dflag)
		printf("define %s = %s\n", name, value);
	for (i = macro; i != NULL; i=i->next)
		if (Streq(name, i->name)) {
			if (!i->protected) {
				free(i->value);
				i->value = value;
				i->protected = protected;
			} else if (dflag)
				printf("... definition suppressed\n");
			return;
		}
	i = (struct macro *)mmalloc(sizeof(*i));
	i->name = name;
	i->value = value;
	i->protected = protected;
	i->next = macro;
	macro = i;
}

/* Accept single letter user defined macros */
ismacro(c) register int c;
{
	if ((c>='0'&&c<='9')
	 || (c>='a'&&c<='z')
	 || (c>='A'&&c<='Z'))
		return 1;
	return 0;
}
/* return the next character from the input file. eat comments, return EOS
 * for a newline not followed by an action, \n for newlines that are followed
 * by actions;  if not in a macro definition or action specification
 * then expand the macro in backup or complain about the name.
 */

nextc()
{
	register char *s;
	register c;

Again:
	if((c=readc())=='#'){
		do
			c=readc();
		while(c!='\n' && c!=EOF);
	}
	if(c=='\n'){
		if((c=readc())!=' ' && c!='\t'){
			putback(c);
			return(EOS);
		}
		do
			c=readc();
		while(c==' ' || c=='\t');
		putback(c);
		return('\n');
	}
	if(c=='\\'){
		c=readc();
		if(c=='\n') {
			while ((c=readc())==' ' || c=='\t')
				;
			putback(c);
			return(' ');
		}
		putback(c);
		return('\\');
	}
	if(!defining && c=='$'){
		c=readc();
		if(c=='(') {
			s=macroname;
			while(' '<(c=readc()) && c<0177 && c!=')')
				if(s!=&macroname[NMACRONAME])
					*s++=c;
			if (c != ')')
				err(badmac);
			*s++ = '\0';
		} else if (ismacro(c)) {
			macroname[0]=c;
			macroname[1]='\0';
		} else
			err(badmac);
		if((s=mexists(macroname))!=NULL)
			unreads(s);
		goto Again;
	}
	return(c);
}

/* Get a block of l0+l1 bytes copy s0 and s1 into it, and return a pointer to
 * the beginning of the block.
 */

char *
extend(s0, l0, s1, l1)
char *s0, *s1;
{
	register char *t;

 	if (s0 == NULL)
 		t = mmalloc(l1);
 	else {
 		if ((t = realloc(s0, l0 + l1)) == NULL)
			err(nospace);
	}
	strncpy(t+l0, s1, l1);
	return(t);
}

/* Return 1 if c is EOS, EOF, or one of the characters in s */

delim(c, s)
register char	c;
char	*s;
{
	return (c == EOS || c == EOF || index(s, c) != NULL);
}

/* Prepare to copy a new token string into the token buffer; if the old value
 * in token wasn't saved, tough matzohs.
 */

starttoken()
{
	token=NULL;
	tokp=tokbuf;
	toklen=0;
}

/* Put c in the token buffer; if the buffer is full, copy its contents into
 * token and start agin at the beginning of the buffer.
 */

addtoken(c)
{
	if(tokp==&tokbuf[NTOKBUF]){
		token=extend(token, toklen-NTOKBUF, tokbuf, NTOKBUF);
		tokp=tokbuf;
	}
	*tokp++=c;
	toklen++;
}

/* mark the end of the token in the buffer and save it in token. */

endtoken()
{
	addtoken('\0');
	token=extend(token, toklen-(tokp-tokbuf), tokbuf, tokp-tokbuf);
}

/* Install value at the end of the token list which begins with next; return
 * a pointer to the beginning of the list, which is the one just installed if
 * next was NULL.
 */

struct token *
listtoken(value, next)
char *value;
struct token *next;
{
	register struct token *p;
	register struct token *t;

	t=(struct token *)mmalloc(sizeof *t);	/*Necessaire ou le contraire?*/
	t->value=value;
	t->next=NULL;
	if(next==NULL)
		return(t);
	for(p=next;p->next!=NULL;p=p->next);
	p->next=t;
	return(next);
}

/* Free the overhead of a token list */
struct token *freetoken(t) register struct token *t;
{
	register struct token *tp;
	while (t != NULL) {
		tp = t->next;
		free(t);
		t = tp;
	}
	return t;
}

/* Read macros, dependencies, and actions from the file with name file, or
 * from whatever file is already open. The first string of tokens is saved
 * in a list pointed to by tp; if it was a macro, the definition goes in 
 * token, and we install it in macro[]; if tp points to a string of targets,
 * its depedencies go in a list pointed to by dp, and the action to recreate
 * it in token, and the whole shmear is installed.
 */

input(file)
char *file;
{
	struct token *tp = NULL, *dp = NULL;
	register c;
	char *action;
	int twocolons;

	if(file!=NULL && (fd=fopen(file, "r"))==NULL)
		die("can't open %s", file);
	lineno=1;
	lastc=EOF;
	for(;;){
		c=nextc();
		for(;;){
			while(c==' ' || c=='\t')
				c=nextc();
			if(delim(c, "=:;\n"))
				break;
			starttoken();
			while(!delim(c, " \t\n=:;")){
				addtoken(c);
				c=nextc();
			}
			endtoken();
			tp=listtoken(token, tp);
		}
		switch(c){
		case EOF:
			if(tp!=NULL)
				err(incomp);
			fclose(fd);
			return;
		case EOS:
			if(tp==NULL)
				break;
		case '\n':
			err("Newline after target or macroname");
		case ';':
			err("; after target or macroname");
		case '=':
			if(tp==NULL || tp->next!=NULL)
				err("= without macro name or in token list");
			defining++;
			while((c=nextc())==' ' || c=='\t');
			starttoken();
			while(c!=EOS && c!=EOF) {
				addtoken(c);
				c=nextc();
			}
			endtoken();
			define(tp->value, token, 0);
			defining=0;
			break;
		case ':':
			if(tp==NULL)
				err(": without preceding target");
			c=nextc();
			if(c==':'){
				twocolons=1;
				c=nextc();
			} else
				twocolons=0;
			for(;;){
				while(c==' ' || c=='\t')
					c=nextc();
				if(delim(c, "=:;\n"))
					break;
				starttoken();
				while(!delim(c, " \t\n=:;")){
					addtoken(c);
					c=nextc();
				}
				endtoken();
				dp=listtoken(token, dp);
			}
			switch(c){
			case ':':
				err("::: or : in or after dependency list");
			case '=':
				err("= in or after dependency");
			case EOF:
				err(incomp);
			case ';':
			case '\n':
				++defining;
				starttoken();
				while((c=nextc())!=EOS && c!=EOF)
					addtoken(c);
				endtoken();
				defining = 0;
				action=token;
				break;
			case EOS:
				action=NULL;
			}
			install(tp, dp, action, twocolons);
		}
		tp = freetoken(tp);
		dp = freetoken(dp);
		dp = NULL;
	}
}

/* Input with library lookup */
inlib(file) char *file;
{
	register char *p, *cp;
	if ((p = getenv("LIBPATH")) == NULL)
		p = DEFLIBPATH;
	cp = path(p, file, AREAD);
	input(cp ? cp : file);
}

/* Input first file in list which is found via path */
inpath(file) char *file;
{
	register char **vp, *p, *cp;
	if ((p = getenv("PATH")) == NULL)
		p = DEFPATH;
	for (vp = &file; *vp != NULL; vp += 1)
		if ((cp = path(p, *vp, AREAD)) != NULL)
			break;
	input(cp ? cp : file);
}

/* Return the last modified date of file with name name. If it's an archive,
 * open it up and read the insertion date of the pertinent member.
 */

time_t
getmdate(name)
char	*name;
{
	char	*subname;
	char	*lwa;
	int	fd;
	int	magic;
	time_t	result;
	struct ar_hdr	hdrbuf;

	if (stat(name, &statbuf) ==0)
		return(statbuf.st_mtime);
	subname = index(name, '(');
	if (subname == NULL)
		return (0);
	lwa = &name[strlen(name) - 1];
	if (*lwa != ')')
		return (0);
	*subname = NUL;
	fd = open(name, READ);
	*subname++ = '(';
	if (fd == EOF)
		return (0);
	if (read(fd, &magic, sizeof magic) != sizeof magic) {
		close(fd);
		return (0);
	}
	canint(magic);
	if (magic != ARMAG) {
		close(fd);
		return (0);
	}
	*lwa = NUL;
	result = 0;
	while (read(fd, &hdrbuf, sizeof hdrbuf) == sizeof hdrbuf) {
		if (strcmp(hdrbuf.ar_name, subname) == 0) {
			cantime(hdrbuf.ar_date);
			result = hdrbuf.ar_date;
			break;
		}
		canlong(hdrbuf.ar_size);
		lseek(fd, hdrbuf.ar_size, REL);
	}
	*lwa = ')';
	return (result);
}


/* Does file name exist? */

fexists(name)
char *name;
{
	return(stat(name, &statbuf)>=0);
}

/* Return a pointer to the symbol table entry with name "name", NULL if it's
 * not there.
 */

struct sym *sexists(name) register char *name;
{
	register struct sym *sp;

	for(sp=sym;sp!=NULL;sp=sp->next)
		if(Streq(name, sp->name))
			return(sp);
	return(NULL);
}

/*
 * Return a pointer to the member of deplist which has name as the last
 * part of it's pathname, otherwise return NULL.
 */
struct sym *dexists(name, dp) register char *name; register struct dep *dp;
{
	register char *p;
	while (dp != NULL) {
		if ((p = rindex(dp->symbol->name, PATHSEP)) && Streq(name, p+1))
			return dp->symbol;
		else
			dp = dp->next;
	}
	return NULL;
}
/* Look for symbol with name "name" in the symbol table; install it if it's
 * not there; initialize the action and dependency lists to NULL, the type to
 * unknown, zero the modification date, and return a pointer to the entry.
 */

struct sym *
lookup(name)
char *name;
{
	register struct sym *sp;

	if((sp=sexists(name))!=NULL)
		return(sp);
	sp = (struct sym *)mmalloc(sizeof (*sp));	/*necessary?*/
	sp->name=name;
	sp->action=NULL;
	sp->deplist=NULL;
	sp->type=T_UNKNOWN;
	sp->moddate=0;
	sp->next=sym;
	sym=sp;
	return(sp);
}

/* Install a dependency with symbol having name "name", action "action" in 
 * the end of the dependency list pointed to by next. If s has already 
 * been noted as a file in the dependency list, install action. Return a 
 * pointer to the beginning of the dependency list.
 */

struct dep *
adddep(name, action, next)
char *name, *action;
struct dep *next;
{
	register struct dep *v;
	register struct sym *s;
	struct dep *dp;

	s=lookup(name);
	for(v=next;v!=NULL;v=v->next)
		if(s==v->symbol){
			if (action != NULL) {
				if(v->action!=NULL)
					err("Multiple detailed actions for %s",
						s->name);
				v->action=action;
			}
			return(next);
		}
	v = (struct dep *)malloc(sizeof (*v));	/*necessary?*/
	v->symbol=s;
	v->action=action;
	v->next=NULL;
	if(next==NULL)
		return(v);
	for(dp=next;dp->next!=NULL;dp=dp->next);
	dp->next=v;
	return(next);
}

/* Do everything for a dependency with left-hand side cons, r.h.s. ante, 
 * action "action", and one or two colons. If cons is the first target in the
 * file, it becomes the default target. Mark each target in cons as detailed
 * if twocolons, undetailed if not, and install action in the symbol table 
 * action slot for cons in the latter case. Call adddep() to actually create
 * the dependency list.
 */

install(cons, ante, action, twocolons)
struct token *ante, *cons;
char *action;
{
	struct sym *cp;
	struct token *ap;

	if(deftarget==NULL && cons->value[0]!='.')
		deftarget=cons->value;
	if(dflag){
		printf("Ante:");
		ap=ante;
		while(ap!=NULL){
			printf(" %s", ap->value);
			ap=ap->next;
		}
		printf("\nCons:");
		ap=cons;
		while(ap!=NULL){
			printf(" %s", ap->value);
			ap=ap->next;
		}
		printf("\n");
		if(action!=NULL)
			printf("Action: '%s'\n", action);
		if(twocolons)
			printf("two colons\n");
	}
	for (; cons != NULL; cons = cons->next) {
		cp=lookup(cons->value);
		if(cp==suffixes && ante==NULL)
			cp->deplist=NULL;
		else{
			if(twocolons){
				if(cp->type==T_UNKNOWN)
					cp->type=T_DETAIL;
				else if(cp->type!=T_DETAIL)
					err("'::' not allowed for %s",
						cp->name);
			} else {
				if(cp->type==T_UNKNOWN)
					cp->type=T_NODETAIL;
				else if(cp->type!=T_NODETAIL)
					err("Must use '::' for %s", cp->name);
				if (action != NULL) {
					if(cp->action != NULL)
						err("Multiple actions for %s",
							cp->name);
					cp->action = action;
				}
			}
			for(ap=ante;ap!=NULL;ap=ap->next)
				cp->deplist=adddep(ap->value,
					twocolons?action:NULL, cp->deplist);
		}
	}
}

/* Make s; first, make everything s depends on; if the target has detailed
 * actions, execute any implicit actions associated with it, then execute
 * the actions associated with the dependencies which are newer than s. 
 * Otherwise, put the dependencies that are newer than s in token ($?), 
 * make s if it doesn't exist, and call docmd.
 */

make(s)
register struct sym *s;
{
	register struct dep *dep;
	register char *t;
	int update;
	int type;

	if(s->type==T_DONE)
		return;
	if(dflag)
		printf("Making %s\n", s->name);
	type=s->type;
	s->type=T_DONE;
	s->moddate=getmdate(s->name);
	for(dep=s->deplist;dep!=NULL;dep=dep->next)
		make(dep->symbol);
	if(type==T_DETAIL){
		implicit(s, "", 0);
		for(dep=s->deplist;dep!=NULL;dep=dep->next)
			if(dep->symbol->moddate>s->moddate)
				docmd(s, dep->action, s->name,
					dep->symbol->name, "", "");
	} else {
		update=0;
		starttoken();
		for(dep=s->deplist;dep!=NULL;dep=dep->next){
			if(dflag)
				printf("%s time=%ld %s time=%ld\n",
				    dep->symbol->name, dep->symbol->moddate,
				    s->name, s->moddate);
			if(dep->symbol->moddate>s->moddate){
				update++;
				addtoken(' ');
				for(t=dep->symbol->name;*t;t++)
					addtoken(*t);
			}
		}
		endtoken();
		t = token;
		if (!update && !fexists(s->name)) {
			update = TRUE;
			if (dflag)
				printf("'%s' made due to non-existence\n",
					s->name);
		}
		if(s->action==NULL)
			implicit(s, t, update);
		else if(update)
			docmd(s, s->action, s->name, t, "", "");
		free(t);
	}
}

/*
 * Expand substitutes the macros in actions and returns the string.
 */
expand(str) register char *str;
{
	register int c;
	register char *p;
	while (c = *str++) {
		if (c == '$') {
			c = *str++;
			switch (c) {
			case 0: err(badmac);
			case '$': addtoken(c); continue;
			case '{': addtoken('$'); addtoken(c); continue;
			case '@': p = mvarval[0]; break;
			case '?': p = mvarval[1]; break;
			case '<': p = mvarval[2]; break;
			case '*': p = mvarval[3]; break;
			case '(':
				p = str;
				do c = *str++; while (c!=0 && c!=')');
				if (c == 0)
					err(badmac);
				*--str = 0;
				p = mexists(p);
				*str++ = ')';
				break;
			default:
				if ( ! ismacro(c))
					err(badmac);
				c = *str;
				*str = 0;
				p = mexists(str-1);
				*str = c;
				break;
			}
			if (p != NULL)
				expand(p);
		} else
			addtoken(c);
	}
}

/* Mark s as modified; if tflag, touch s, otherwise execute the necessary
 * commands.
 */
docmd(s, cmd, at, ques, less, star)
struct sym *s;
char *cmd, *at, *ques, *less, *star;
{
	static char	touch[] = "touch $@";

	if (dflag)
		printf("ex '%s'\n\t$@='%s'\n\t$?='%s'\n\t$<='%s'\n\t$*='%s'\n",
			cmd, at, ques, less, star);
	if (qflag)
		exit(NOTUTD);
	s->moddate = now;
	if (tflag)
		cmd = touch;
	if (cmd == NULL)
		return;
	mvarval[0] = at;
	mvarval[1] = ques;
	mvarval[2] = less;
	mvarval[3] = star;
	starttoken();
	expand(cmd);
	endtoken();
	doit(token);
	free(token);
}


/* look for '-' (ignore errors) and '@' (silent) in cmd, then execute it
 * and note the return status.
 */

doit(cmd)
register char	*cmd;
{
	register char *mark;
	int sflg, iflg, rstat;

	if (nflag) {
		printf("%s\n", cmd);
		return;
	}
	do {
		mark = index(cmd, '\n');
		if (mark != NULL)
			*mark = NUL;
		if (*cmd == '-') {
			++cmd;
			iflg = TRUE;
		} else
			iflg = iflag;
		if (*cmd == '@') {
			++cmd;
			sflg = TRUE;
		} else
			sflg = sflag;
		if (!sflg)
			printf("%s\n", cmd);
		fflush(stdout);
		rstat = system(cmd);
		if (rstat != 0 && !iflg)
			if (sflg)
				die("%s	exited with status %d",
					cmd, rstat);
			else
				die("	exited with status %d", rstat);
		cmd = mark + 1;
	} while (mark != NULL && *cmd != NUL);
}


/* Find the implicit rule to generate obj and execute it. Put the name of 
 * obj up to '.' in prefix, and look for the rest in the dependency list 
 * of .SUFFIXES. Find the file "prefix.foo" upon which obj depends, where
 * foo appears in the dependency list of suffixes after the suffix of obj.
 * Then make obj according to the rule from makeactions. If we can't find 
 * any rules, use .DEFAULT, provided we're definite.
 */

implicit(obj, ques, definite)
struct sym *obj;
char *ques;
{
	register char *s;
	register struct dep *d;
	char *prefix, *file, *rulename, *suffix;
	struct sym *rule;
	struct sym *subj;

	if(dflag)
		printf("Implicit %s (%s)\n", obj->name, ques);
	if ((suffix=rindex(obj->name, '.')) == NULL
	 || suffix==obj->name) {
		if (definite)
			defalt(obj, ques);
		return;
	}
	starttoken();
	for(s=obj->name; s<suffix; s++)
		addtoken(*s);
	endtoken();
	prefix=token;
	for(d=suffixes->deplist;d!=NULL;d=d->next)
		if(Streq(suffix, d->symbol->name))
			break;
	if(d==NULL){
		free(prefix);
		if (definite)
			defalt(obj, ques);
		return;
	}
	while((d=d->next)!=NULL){
		starttoken();
		for(s=obj->name; s!=suffix; s++)
			addtoken(*s);
		for(s=d->symbol->name;*s;s++)
			addtoken(*s);
		endtoken();
		file=token;
		subj=NULL;
		if(fexists(file) || (subj=dexists(file, obj->deplist))){
			starttoken();
			for(s=d->symbol->name;*s!='\0';s++)
				addtoken(*s);
			for(s=suffix;*s!='\0';s++)
				addtoken(*s);
			endtoken();
			rulename=token;
			if((rule=sexists(rulename))!=NULL){
				if (subj != NULL || (subj=sexists(file))) {
					free(file);
					file=subj->name;
				} else
					subj=lookup(file);
				make(subj);
				if(definite || subj->moddate>obj->moddate)
					docmd(obj, rule->action,
						obj->name, ques, file, prefix);
				free(prefix);
				free(rulename);
				return;
			}
			free(rulename);
		}
		free(file);
	}
	free(prefix);
	if (definite)
		defalt(obj, ques);
}


/*
 * Deflt uses the commands associated to '.DEFAULT' to make the object
 * 'obj'.
 */

defalt(obj, ques)
struct sym	*obj;
char		*ques;
{
	if (deflt == NULL)
		die("Don't know how to make %s", obj->name);
	docmd(obj, deflt->action, obj->name, ques, "", "");
}


main(argc, argv, envp) char *argv[], *envp[];
{
	register char	*s, *value;
	register int c;
	struct token	*fp = NULL;
	struct sym	*sp;
	struct dep	*d;
	struct macro	*mp;

	time(&now);
	++argv;
	--argc;
	while (argc > 0 && argv[0][0] == '-')
		for (--argc, s = *argv++; *++s != NUL;)
			switch (*s) {
			case 'i': iflag++; break;
			case 's': sflag++; break;
			case 'r': rflag++; break;
			case 'n': nflag++; break;
			case 't': tflag++; break;
			case 'q': qflag++; break;
			case 'p': pflag++; break;
			case 'd': dflag++; break;
			case 'e': eflag++; break;
			case 'f':
				if (--argc < 0)
					Usage();
				fp=listtoken(*argv++, fp);
				break;
			default:
				Usage();
			}
	while (argc > 0 && (value = index(*argv, '=')) != NULL) {
		s = *argv;
		while (*s != ' ' && *s != '\t' && *s != '=')
			++s;
		*s = '\0';
		define(*argv++, value+1, 1);
		--argc;
	}
	while (*envp != NULL) {
		if ((value = index(*envp, '=')) != NULL
		 && index(value, '$') == NULL) {
			s = *envp;
			while ((c=*s) != ' ' && c != '\t' && c != '=')
				++s;
			*s = 0;
			if (eflag)
				define(*envp, value+1, 1);
			else {
				starttoken();
				while (*++value) addtoken(*value);
				endtoken();
				define(*envp, token, 0);
			}
			*s = c;
		}
		++envp;
	}
	suffixes=lookup(".SUFFIXES");
	if (!rflag)
		inlib(MACROFILE);
	deftarget = NULL;
	if (fp == NULL)
		inpath("makefile", "Makefile", NULL);
	else {
		fd = stdin;
		do {
			input( strcmp(fp->value, "-") == 0 ? NULL : fp->value);
			fp = fp->next;
		} while (fp != NULL);
	}
	if (!rflag)
		inlib(ACTIONFILE);
	if (sexists(".IGNORE") != NULL)
		++iflag;
	if (sexists(".SILENT") != NULL)
		++sflag;
	deflt = sexists(".DEFAULT");
	if(pflag){
		if(macro != NULL) {
			printf("Macros:\n");
			for (mp = macro; mp != NULL; mp=mp->next)
				printf("%s=%s\n", mp->name, mp->value);
		}
		printf("Rules:\n");
		for(sp=sym;sp!=NULL;sp=sp->next){
			if(sp->type!=T_UNKNOWN){
				printf("%s:", sp->name);
				if(sp->type==T_DETAIL)
					putchar(':');
				for(d=sp->deplist;d!=NULL;d=d->next)
					printf(" %s", d->symbol->name);
				printf("\n");
				if(sp->action)
					printf("\t%s\n", sp->action);
			}
		}
	}
	if(argc > 0){
		do{
			make(lookup(*argv++));
		} while (--argc > 0);
	} else
		make(lookup(deftarget));
	exit(ALLOK);
}

/* Whine about usage and then quit */

Usage()
{
	fprintf(stderr, "%s\n", usage);
	exit(1);
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.