text: #include	"mk.h"
  
  int runerrs;
  
  void
  mk(char *target)
  {
  	Node *node;
  	int did = 0;
  
  	nproc();		/* it can be updated dynamically */
  	nrep();			/* it can be updated dynamically */
  	runerrs = 0;
  	node = graph(target);
  	if(DEBUG(D_GRAPH)){
  		dumpn("new target\n", node);
  		Bflush(&bout);
  	}
  	clrmade(node);
  	while(node->flags&NOTMADE){
  		if(work(node, (Node *)0, (Arc *)0))
  			did = 1;	/* found something to do */
  		else {
  			if(waitup(1, (int *)0) > 0){
  				if(node->flags&(NOTMADE|BEINGMADE)){
  					assert("must be run errors", runerrs);
  					break;	/* nothing more waiting */
  				}
  			}
  		}
  	}
  	if(node->flags&BEINGMADE)
  		waitup(-1, (int *)0);
  	while(jobs)
  		waitup(-2, (int *)0);
  	assert("target didn't get done", runerrs || (node->flags&MADE));
  	if(did == 0)
  		Bprint(&bout, "mk: '%s' is up to date\n", node->name);
  }
  
  void
  clrmade(Node *n)
  {
  	Arc *a;
  
  	n->flags &= ~(CANPRETEND|PRETENDING);
  	if(strchr(n->name, '(') ==0 || n->time)
  		n->flags |= CANPRETEND;
  	MADESET(n, NOTMADE);
  	for(a = n->prereqs; a; a = a->next)
  		if(a->n)
  			clrmade(a->n);
  }
  
  static void
  unpretend(Node *n)
  {
  	MADESET(n, NOTMADE);
  	n->flags &= ~(CANPRETEND|PRETENDING);
  	n->time = 0;
  }
  
  int
  work(Node *node, Node *p, Arc *parc)
  {
  	Arc *a, *ra;
  	int weoutofdate;
  	int ready;
  	int did = 0;
  
  	/*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);/**/
  	if(node->flags&BEINGMADE)
  		return(did);
  	if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){
  		if(explain)
  			fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n",
  				node->name, node->time, p->name, p->time);
  		unpretend(node);
  	}
  	/*
  		have a look if we are pretending in case
  		someone has been unpretended out from underneath us
  	*/
  	if(node->flags&MADE){
  		if(node->flags&PRETENDING){
  			node->time = 0;
  		}else
  			return(did);
  	}
  	/* consider no prerequsite case */
  	if(node->prereqs == 0){
  		if(node->time == 0){
  			fprint(2, "mk: don't know how to make '%s'\n", node->name);
  			if(kflag){
  				node->flags |= BEINGMADE;
  				runerrs++;
  			} else
  				Exit();
  		} else
  			MADESET(node, MADE);
  		return(did);
  	}
  	/*
  		now see if we are out of date or what
  	*/
  	ready = 1;
  	weoutofdate = aflag;
  	ra = 0;
  	for(a = node->prereqs; a; a = a->next)
  		if(a->n){
  			did = work(a->n, node, a) || did;
  			if(a->n->flags&(NOTMADE|BEINGMADE))
  				ready = 0;
  			if(outofdate(node, a, 0)){
  				weoutofdate = 1;
  				if((ra == 0) || (ra->n == 0)
  						|| (ra->n->time < a->n->time))
  					ra = a;
  			}
  		} else {
  			if(node->time == 0){
  				if(ra == 0)
  					ra = a;
  				weoutofdate = 1;
  			}
  		}
  	if(ready == 0)	/* can't do anything now */
  		return(did);
  	if(weoutofdate == 0){
  		MADESET(node, MADE);
  		return(did);
  	}
  	/*
  		can we pretend to be made?
  	*/
  	if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND))
  			&& p && ra->n && !outofdate(p, ra, 0)){
  		node->flags &= ~CANPRETEND;
  		MADESET(node, MADE);
  		if(explain && ((node->flags&PRETENDING) == 0))
  			fprint(1, "pretending %s has time %ld\n", node->name, node->time);
  		node->flags |= PRETENDING;
  		return(did);
  	}
  	/*
  		node is out of date and we REALLY do have to do something.
  		quickly rescan for pretenders
  	*/
  	for(a = node->prereqs; a; a = a->next)
  		if(a->n && (a->n->flags&PRETENDING)){
  			if(explain)
  				Bprint(&bout, "unpretending %s because of %s because of %s\n",
  				a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites");
  
  			unpretend(a->n);
  			did = work(a->n, node, a) || did;
  			ready = 0;
  		}
  	if(ready == 0)	/* try later unless nothing has happened for -k's sake */
  		return(did || work(node, p, parc));
  	did = dorecipe(node) || did;
  	return(did);
  }
  
  void
  update(int fake, Node *node)
  {
  	Arc *a;
  
  	MADESET(node, fake? BEINGMADE : MADE);
  	if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
  		node->time = timeof(node->name, 1);
  		node->flags &= ~(CANPRETEND|PRETENDING);
  		for(a = node->prereqs; a; a = a->next)
  			if(a->prog)
  				outofdate(node, a, 1);
  	} else {
  		node->time = 1;
  		for(a = node->prereqs; a; a = a->next)
  			if(a->n && outofdate(node, a, 1))
  				node->time = a->n->time;
  	}
  /*	print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);/**/
  }
  
  static
  pcmp(char *prog, char *p, char *q)
  {
  	char buf[3*NAMEBLOCK];
  	int pid;
  
  	Bflush(&bout);
  	sprint(buf, "%s '%s' '%s'\n", prog, p, q);
  	pid = pipecmd(buf, 0, 0);
  	while(waitup(-3, &pid) >= 0)
  		;
  	return(pid? 2:1);
  }
  
  int
  outofdate(Node *node, Arc *arc, int eval)
  {
  	char buf[3*NAMEBLOCK], *str;
  	Symtab *sym;
  	int ret;
  
  	str = 0;
  	if(arc->prog){
  		sprint(buf, "%s%c%s", node->name, 0377, arc->n->name);
  		sym = symlook(buf, S_OUTOFDATE, 0);
  		if(sym == 0 || eval){
  			if(sym == 0)
  				str = strdup(buf);
  			ret = pcmp(arc->prog, node->name, arc->n->name);
  			if(sym)
  				sym->value = (void *)ret;
  			else
  				symlook(str, S_OUTOFDATE, (void *)ret);
  		} else
  			ret = (int)sym->value;
  		return(ret-1);
  	} else if(strchr(arc->n->name, '(') && arc->n->time == 0)  /* missing archive member */
  		return 1;
  	else
  		return node->time < arc->n->time;
  }
  