#include "defs.h"
#include <exec/memory.h>
#include <proto/all.h>

/*  BASIC PROCEDURE.  RECURSIVE.  */

/*
p->done = 0   don't know what to do yet
p->done = 1   file in process of being updated
p->done = 2   file already exists in current state
p->done = 3   file make failed
*/

/**********************************************************************\
*                                                                      *
*  KNK     Implemented Command Prefix and CommandSuffix macro          *
*          processing.                                                 *
*                                                                      *
\**********************************************************************/

#define	MEMFLAGS	(MEMF_PUBLIC | MEMF_CLEAR)
doname(p, reclevel, tval)
register struct nameblock *p;
int reclevel;
TIMETYPE *tval;
{
    int								 errstat;
    int								 okdel1;
    int								 didwork;
    TIMETYPE						 td,
									 td1,
									 tdep,
									 ptime,
									 ptime1,
									 prestime();
    register	struct	depblock	*q;
    			struct	depblock	*qtemp,
									*srchdir(),
									*suffp,
									*suffp1;
				struct	nameblock	*p1,
									*p2;
				struct	shblock		*implcom,
									*explcom;
	register	struct	lineblock	*lp;
				struct	lineblock	*lp1,
									*lp2;
						char		 sourcename[100],
									 prefix[100],
									 temp[100],
									 concsuff[20];
						char		*pnamep,
									*p1namep;
						char		*mkqlist();
				struct	chain		*qchain,
									*appendq();


    if(p == 0) {
		*tval = 0;
		return(0);
    	}

    if(dbgflag) {
		printf("doname(%s,%d)\n",p->namep,reclevel);
		fflush(stdout);
	    }

    if(p->done > 0) {
		*tval = p->modtime;
		return(p->done == 3);
	    }

    errstat = 0;
    tdep = 0;
    implcom = 0;
    explcom = 0;
    ptime = exists(p->namep);
    ptime1 = 0;
    didwork = NO;
    p->done = 1;    /* avoid infinite loops */

    qchain = NULL;

    /* Expand any names that have embedded metacharaters */

    for(lp = p->linep ; lp ; lp = lp->nxtlineblock)
		for(q = lp->depp ; q ; q=qtemp ) {
		    qtemp = q->nxtdepblock;
		    expand(q);
		}

    /* make sure all dependents are up to date */

    for(lp = p->linep ; lp ; lp = lp->nxtlineblock) {
		td = 0;
		for(q = lp->depp ; q ; q = q->nxtdepblock) {
		    errstat += doname(q->depname, reclevel+1, &td1);
		    if(dbgflag)
				printf("Part 1:TIME(%s)=%ld\n", q->depname->namep, td1);
		    if(td1 > td)
				td = td1;
		    if(ptime < td1)
				qchain = appendq(qchain, q->depname->namep);
			}
		if(p->septype == SOMEDEPS) {
		    if(lp->shp!=0)
				if( ptime<td || (ptime==0 && td==0) || lp->depp==0) {
				    okdel1 = okdel;
					okdel = NO;
				    setvar("@", p->namep);
				    setvar("?", mkqlist(qchain) );
				    qchain = NULL;
				    if( !questflag )
						errstat += docom(lp->shp);
				    setvar("@", (char *) NULL);
				    okdel = okdel1;
				    ptime1 = prestime();
				    didwork = YES;
					}
			}

		else {
		    if(lp->shp != 0) {
				if(explcom)
				    fprintf(stderr, "Too many command lines for `%s'\n", p->namep);
				else
					explcom = lp->shp;
			    }

	    	if(td > tdep)
				tdep = td;
			}
	    }

    /* Look for implicit dependents, using suffix rules */

    for(lp = sufflist ; lp ; lp = lp->nxtlineblock)
		for(suffp = lp->depp ; suffp ; suffp = suffp->nxtdepblock) {
		    pnamep = suffp->depname->namep;
		    if(suffix(p->namep , pnamep , prefix)) {
				srchdir( concat(prefix,"*",temp) , NO, (struct depblock *) NULL);
				for(lp1 = sufflist ; lp1 ; lp1 = lp1->nxtlineblock)
				    for(suffp1=lp1->depp ; suffp1 ; suffp1 = suffp1->nxtdepblock) {
						p1namep = suffp1->depname->namep;
						if( (p1=srchname(concat(p1namep, pnamep ,concsuff))) &&
							    (p2=srchname(concat(prefix, p1namep ,sourcename))) ) {
						    errstat += doname(p2, reclevel+1, &td);
			    			if(ptime < td)
								qchain = appendq(qchain, p2->namep);
			    			if(dbgflag)
								printf("Part 2:TIME(%s)=%ld\n", p2->namep, td);
						    if(td > tdep)
								tdep = td;
						    setvar("*", prefix);
						    setvar("<", copys(sourcename));
						    for(lp2=p1->linep ; lp2 ; lp2 = lp2->nxtlineblock)
								if(implcom = lp2->shp)
									break;
						    goto endloop;
							}
					    }
					setvar("*", &prefix[(ULONG)rindex(prefix, '/') - (ULONG)prefix]);
			    }
			}

endloop:


    if(errstat==0 && (ptime<tdep || (ptime==0 && tdep==0) ) ) {
		ptime = (tdep>0 ? tdep : prestime() );
		setvar("@", p->namep);
		setvar("?", mkqlist(qchain) );
		if(explcom)
		    errstat += docom(explcom);
		else if(implcom)
		    errstat += docom(implcom);
		else if(p->septype == 0)
	    	if(p1=srchname(".DEFAULT")) {
				setvar("<", p->namep);
				for(lp2 = p1->linep ; lp2 ; lp2 = lp2->nxtlineblock)
				    if(implcom = lp2->shp) {
						errstat += docom(implcom);
						break;
					    }
			    }
	    else if(keepgoing) {
			printf("Don't know how to make %s\n", p->namep);
			++errstat;
	    	}
	    else
			fatal1(" Don't know how to make %s", p->namep);

		setvar("@", (char *) NULL);
		if(noexflag || (ptime = exists(p->namep)) == 0)
	    	ptime = prestime();
	    }

    else if(errstat!=0 && reclevel==0)
		printf("`%s' not remade because of errors\n", p->namep);

    else if(!questflag && reclevel==0  &&  didwork==NO)
		printf("`%s' is up to date.\n", p->namep);

    if(questflag && reclevel==0)
		exit(ndocoms>0 ? -1 : 0);

    p->done = (errstat ? 3 : 2);
    if(ptime1 > ptime)
		ptime = ptime1;
    p->modtime = ptime;
    *tval = ptime;
    return(errstat);
}

static	char	*PREFIXER = "$(CMDPREFIX)";
static	char	*SUFFIXER = "$(CMDSUFFIX)";

docom(q)
struct shblock *q;
{
    char			*s;
    char			*TempString;
    struct varblock *varptr();
    int		 		 ign,
					 nopr;
    char 			 string[OUTMAX];
    int				 oldsilflag;
    int				 modifiedsilflag;
    long			 BufferLen;

    ++ndocoms;
    if(questflag)
		return(NO);

    if(touchflag) {
		s = varptr("@")->varval;
		if(!silflag)
		    printf("touch(%s)\n", s);
		if(!noexflag)
		    touch(YES, s);
	    }

    else for( ; q ; q = q->nxtshblock ) {
    	if(*(q->shbp) == '@') {
    		q->shbp++;
    		oldsilflag = silflag;
    		silflag = -1;
    		modifiedsilflag = 1;
    		}
    	else
    		modifiedsilflag = 0;
    	
		BufferLen = (ULONG)(strlen(q->shbp)) + (ULONG)(strlen(PREFIXER)) + (ULONG)(strlen(SUFFIXER)) + 1L;
    	TempString = (char *)AllocMem(BufferLen, MEMFLAGS);
    	if(!TempString)
    		fatal("Could not allocate memory for temporary command expansion");
    	strcpy(TempString,PREFIXER);
    	strcat(TempString,q->shbp);
    	strcat(TempString,SUFFIXER);
		subst(TempString,string);
		FreeMem(TempString, BufferLen);
		

		ign = ignerr;
		nopr = NO;
		for(s = string ; *s=='-' || *s=='@' ; ++s)
		    if(*s == '-')
				ign = YES;
		    else
				nopr = YES;

		if( docom1(s, ign, nopr) && !ign) {
			if(modifiedsilflag) {
				silflag = oldsilflag;
				q->shbp--;
				}
		    if(keepgoing)
				return(YES);
		    else
				fatal( (char *) NULL);
			}
		else if (modifiedsilflag)
			silflag = oldsilflag;
			q->shbp--;
	    }
	    
    return(NO);
}



docom1(comstring, nohalt, noprint)
register	char	*comstring;
			int		 nohalt,
					 noprint;
{
    register int status;

    if(comstring[0] == '\0') return(0);

    if(!silflag && (!noprint || noexflag) ) {
		printf("%s%s\n", (noexflag ? "" : prompt), comstring);
		fflush(stdout);
	    }

    if(noexflag)
		return(0);

    if( status = dosys(comstring, nohalt) ) {
		if(status)
		    printf("*** Error code %d", status);

		if(nohalt)
			printf(" (ignored)\n");
		else
			printf("\n");

		fflush(stdout);
	    }

    return(status);
}


/*
   If there are any Shell meta characters in the name,
   expand into a list, after searching directory
*/

expand(q)
register struct depblock *q;
{
    register	char				*s;
    			char				*s1;
    			struct	depblock	*p,
									*srchdir();

    s1 = q->depname->namep;
    for(s=s1 ; ;)
		switch(*s++) {
		    case '\0':
				return(0);

		    case '*':
		    case '?':
		    case '[':
				if( p = srchdir(s1 , YES, q->nxtdepblock) ) {
				    q->nxtdepblock = p;
				    q->depname = 0;
					}
				return(0);
		    }
}
