diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/ape/cmd/make |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/cmd/make')
-rwxr-xr-x | sys/src/ape/cmd/make/defs.h | 213 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/doname.c | 380 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/dosys.c | 287 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/files.c | 552 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/gram.y | 441 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/ident.c | 125 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/main.c | 423 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/misc.c | 504 | ||||
-rwxr-xr-x | sys/src/ape/cmd/make/mkfile | 26 |
9 files changed, 2951 insertions, 0 deletions
diff --git a/sys/src/ape/cmd/make/defs.h b/sys/src/ape/cmd/make/defs.h new file mode 100755 index 000000000..d7ce537f5 --- /dev/null +++ b/sys/src/ape/cmd/make/defs.h @@ -0,0 +1,213 @@ +/* defs 4.2 85/10/28 */ +#define _POSIX_SOURCE +#define _RESEARCH_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <dirent.h> +#include <limits.h> +#include <stdio.h> +#include <ctype.h> + +#ifndef SHELLCOM +#define SHELLCOM "/bin/sh" +#endif + +typedef char flag; /* represent a few bit flag */ + +#define NO 0 +#define YES 1 + +#define equal(a,b) (! strcmp(a,b)) +#define HASHSIZE 1021 +#define NLEFTS 512 +#define NCHARS 500 +#define NINTS 250 +#define INMAX 20000 +#define OUTMAX 20000 +#define QBUFMAX 20000 +#define MAXDIR 10 +#define MAXPROC 100 +#define MAXINCLUDE 17 +#define PROCLIMIT 3 + +#define ALLDEPS 1 +#define SOMEDEPS 2 + +#define META 01 +#define TERMINAL 02 +extern char funny[128]; + + +#define ALLOC(x) (struct x *) ckalloc(sizeof(struct x)) +#define CHNULL (char *) NULL + +extern int sigivalue; +extern int sigqvalue; +extern int dbgflag; +extern int prtrflag; +extern int silflag; +extern int noexflag; +extern int keepgoing; +extern int noruleflag; +extern int touchflag; +extern int questflag; +extern int oldflag; +extern int ndocoms; +extern int ignerr; +extern int okdel; +extern int forceshell; +extern int inarglist; +extern char **envpp; /* points to slot in environment vector */ +extern char *prompt; +extern int nopdir; + +typedef struct nameblock *nameblkp; +typedef struct depblock *depblkp; +typedef struct lineblock *lineblkp; +typedef struct chain *chainp; + +struct nameblock + { + nameblkp nxtnameblock; + char *namep; + lineblkp linep; + flag done; + flag septype; + flag isarch; + flag isdir; + time_t modtime; + }; + +extern nameblkp mainname; +extern nameblkp firstname; +extern nameblkp *hashtab; +extern int nhashed; +extern int hashsize; +extern int hashthresh; + +struct lineblock + { + lineblkp nxtlineblock; + struct depblock *depp; + struct shblock *shp; + }; +extern lineblkp sufflist; + +struct depblock + { + depblkp nxtdepblock; + nameblkp depname; + char nowait; + } ; + +struct shblock + { + struct shblock *nxtshblock; + char *shbp; + }; + +struct varblock + { + struct varblock *nxtvarblock; + char *varname; + char *varval; + char **export; + flag noreset; + flag used; + }; +extern struct varblock *firstvar; + +struct pattern + { + struct pattern *nxtpattern; + char *patval; + }; +extern struct pattern *firstpat; + +struct dirhd + { + struct dirhd *nxtdirhd; + time_t dirtime; + int dirok; + DIR * dirfc; + char *dirn; + }; +extern struct dirhd *firstod; + + +struct chain + { + chainp nextp; + char *datap; + }; + +struct wild + { + struct wild *next; + lineblkp linep; + char *left; + char *right; + int llen; + int rlen; + int totlen; + }; + +typedef struct wild *wildp; +extern wildp firstwild; +extern wildp lastwild; + + +/* date for processes */ +extern int proclimit; /* maximum spawned processes allowed alive at one time */ +extern int proclive; /* number of spawned processes awaited */ +extern int nproc; /* next slot in process stack to use */ +extern struct process + { + int pid; + flag nohalt; + flag nowait; + flag done; + } procstack[ ]; + +extern void intrupt(int); +extern void enbint(void (*)(int)); +extern int doname(nameblkp, int, time_t *, int); +extern int docom(struct shblock *, int, int); +extern int dosys(char *, int, int, char *); +extern int waitstack(int); +extern void touch(int, char*); +extern time_t exists(char *); +extern time_t prestime(void); +extern depblkp srchdir(char*, int, depblkp); +extern time_t lookarch(char *); +extern void dirsrch(char *); +extern void baddirs(void); +extern nameblkp srchname(char *); +extern nameblkp makename(char *); +extern int hasparen(char *); +extern void newhash(int); +extern nameblkp chkname(char *); +extern char *copys(char *); +extern char *concat(char *, char *, char *); +extern int suffix(char *, char *, char *); +extern int *ckalloc(int); +extern char *subst(char *, char *); +extern void setvar(char *, char *, int); +extern void set3var(char *, char *); +extern int eqsign(char *); +extern struct varblock *varptr(char *); +extern int dynmacro(char *); +extern void fatal1(char *, char *); +extern void fatal(char *); +extern chainp appendq(chainp, char *); +extern char *mkqlist(chainp, char *); +extern wildp iswild(char *); +extern char *wildmatch(wildp, char *, int); +extern char *wildsub(char *, char *); +extern int parse(char *); +extern int yylex(void); diff --git a/sys/src/ape/cmd/make/doname.c b/sys/src/ape/cmd/make/doname.c new file mode 100755 index 000000000..5d8048bf2 --- /dev/null +++ b/sys/src/ape/cmd/make/doname.c @@ -0,0 +1,380 @@ +#include "defs.h" + +static int docom1(char *, int, int, int, int); +static void expand(depblkp); + +/* 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 +*/ + +int +doname(nameblkp p, int reclevel, time_t *tval, int nowait) +{ +int errstat; +int okdel1; +int didwork; +int len; +time_t td, td1, tdep, ptime, ptime1; +depblkp q; +depblkp qtemp, suffp, suffp1; +nameblkp p1, p2; +struct shblock *implcom, *explcom; +lineblkp lp; +lineblkp lp1, lp2; +char sourcename[100], prefix[100], temp[100], concsuff[20]; +char *stem; +char *pnamep, *p1namep; +chainp allchain, qchain; +char qbuf[QBUFMAX], tgsbuf[QBUFMAX]; +wildp wp; +int nproc1; +char *lastslash, *s; + +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 */ +nproc1 = nproc; /* current depth of process stack */ + +qchain = NULL; +allchain = NULL; + +/* define values of Bradford's $$@ and $$/ macros */ +for(s = lastslash = p->namep; *s; ++s) + if(*s == '/') + lastslash = s; +setvar("$@", p->namep, YES); +setvar("$/", lastslash, YES); + + +/* expand any names that have embedded metacharacters */ + +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) + if(q->depname) + { + errstat += doname(q->depname, reclevel+1, &td1, q->nowait); + if(dbgflag) + printf("TIME(%s)=%ld\n",q->depname->namep, td1); + if(td1 > td) + td = td1; + if(ptime < td1) + qchain = appendq(qchain, q->depname->namep); + allchain = appendq(allchain, q->depname->namep); + } + if(p->septype == SOMEDEPS) + { + if(lp->shp) + if( ptime<td || (ptime==0 && td==0) || lp->depp==0) + { + okdel1 = okdel; + okdel = NO; + set3var("@", p->namep); + setvar("?", mkqlist(qchain,qbuf), YES); + setvar("^", mkqlist(allchain,tgsbuf), YES); + qchain = NULL; + if( !questflag ) + errstat += docom(lp->shp, nowait, nproc1); + set3var("@", CHNULL); + 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)) + { + (void)srchdir(concat(prefix,"*",temp), NO, (depblkp) 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, NO); + if(ptime < td) + qchain = appendq(qchain, p2->namep); +if(dbgflag) printf("TIME(%s)=%ld\n", p2->namep, td); + if(td > tdep) tdep = td; + set3var("*", prefix); + set3var("<", copys(sourcename)); + for(lp2=p1->linep ; lp2 ; lp2 = lp2->nxtlineblock) + if(implcom = lp2->shp) break; + goto endloop; + } + } + } + } + +/* Look for implicit dependents, using pattern matching rules */ + +len = strlen(p->namep); +for(wp = firstwild ; wp ; wp = wp->next) + if(stem = wildmatch(wp, p->namep, len) ) + { + lp = wp->linep; + for(q = lp->depp; q; q = q->nxtdepblock) + { + if(dbgflag>1 && q->depname) + fprintf(stderr,"check dep of %s on %s\n", p->namep, + wildsub(q->depname->namep,stem)); + if(q->depname && + ! chkname(wildsub(q->depname->namep,stem))) + break; + } + + if(q) /* some name not found, go to next line */ + continue; + + for(q = lp->depp; q; q = q->nxtdepblock) + { + nameblkp tamep; + if(q->depname == NULL) + continue; + tamep = srchname( wildsub(q->depname->namep,stem)); +/*TEMP fprintf(stderr,"check dep %s on %s =>%s\n",p->namep,q->depname->namep,tamep->namep);*/ +/*TEMP*/if(dbgflag) printf("%s depends on %s. stem=%s\n", p->namep,tamep->namep, stem); + errstat += doname(tamep, reclevel+1, &td, q->nowait); + if(ptime < td) + qchain = appendq(qchain, tamep->namep); + allchain = appendq(allchain, tamep->namep); + if(dbgflag) printf("TIME(%s)=%ld\n", tamep->namep, td); + if(td > tdep) + tdep = td; + set3var("<", copys(tamep->namep) ); + } + set3var("*", stem); + setvar("%", stem, YES); + implcom = lp->shp; + goto endloop; + } + +endloop: + + +if(errstat==0 && (ptime<tdep || (ptime==0 && tdep==0) ) ) + { + ptime = (tdep>0 ? tdep : prestime() ); + set3var("@", p->namep); + setvar("?", mkqlist(qchain,qbuf), YES); + setvar("^", mkqlist(allchain,tgsbuf), YES); + if(explcom) + errstat += docom(explcom, nowait, nproc1); + else if(implcom) + errstat += docom(implcom, nowait, nproc1); + else if(p->septype == 0) + if(p1=srchname(".DEFAULT")) + { + set3var("<", p->namep); + for(lp2 = p1->linep ; lp2 ; lp2 = lp2->nxtlineblock) + if(implcom = lp2->shp) + { + errstat += docom(implcom, nowait,nproc1); + 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); + + set3var("@", CHNULL); + if(noexflag || nowait || (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; +} + +docom(struct shblock *q, int nowait, int nproc1) +{ +char *s; +int ign, nopr, doit; +char string[OUTMAX]; + +++ndocoms; +if(questflag) + return NO; + +if(touchflag) + { + s = varptr("@")->varval; + if(!silflag) + printf("touch(%s)\n", s); + if(!noexflag) + touch(YES, s); + return NO; + } + +if(nproc1 < nproc) + waitstack(nproc1); + +for( ; q ; q = q->nxtshblock ) + { + subst(q->shbp,string); + ign = ignerr; + nopr = NO; + doit = NO; + for(s = string ; ; ++s) + { + switch(*s) + { + case '-': + ign = YES; + continue; + case '@': + nopr = YES; + continue; + case '+': + doit = YES; + continue; + default: + break; + } + break; + } + + if( docom1(s, ign, nopr, doit||!noexflag, nowait&&!q->nxtshblock) && !ign) + return YES; + } +return NO; +} + + +static int +docom1(char *comstring, int nohalt, int noprint, int doit, int nowait) +{ +int status; +char *prefix; + +if(comstring[0] == '\0') + return 0; + +if(!silflag && (!noprint || !doit) ) + prefix = doit ? prompt : "" ; +else + prefix = CHNULL; + +if(dynmacro(comstring) || !doit) + { + if(prefix) + { + fputs(prefix, stdout); + puts(comstring); /* with a newline */ + fflush(stdout); + } + return 0; + } + +status = dosys(comstring, nohalt, nowait, prefix); +baddirs(); /* directories may have changed */ +return status; +} + + +/* + If there are any Shell meta characters in the name, + expand into a list, after searching directory +*/ + +static void +expand(depblkp q) +{ +char *s; +char *s1; +depblkp p; + +s1 = q->depname->namep; +for(s=s1 ; ;) switch(*s++) + { + case '\0': + return; + + case '*': + case '?': + case '[': + if( p = srchdir(s1 , YES, q->nxtdepblock) ) + { + q->nxtdepblock = p; + q->depname = 0; + } + return; + } +} diff --git a/sys/src/ape/cmd/make/dosys.c b/sys/src/ape/cmd/make/dosys.c new file mode 100755 index 000000000..7d28eaa4d --- /dev/null +++ b/sys/src/ape/cmd/make/dosys.c @@ -0,0 +1,287 @@ +#include "defs.h" +#include <sys/wait.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +static int metas(char *); +static int waitproc(int *); +static int doshell(char *, int); +static int doexec(char *); + +int +dosys(char *comstring, int nohalt, int nowait, char *prefix) +{ +int status; +struct process *procp; + +/* make sure there is room in the process stack */ +if(nproc >= MAXPROC) + waitstack(MAXPROC-1); + +/* make sure fewer than proclimit processes are running */ +while(proclive >= proclimit) + { + enbint(SIG_IGN); + waitproc(&status); + enbint(intrupt); + } + +if(prefix) + { + fputs(prefix, stdout); + fputs(comstring, stdout); + } + +procp = procstack + nproc; +procp->pid = (forceshell || metas(comstring) ) ? + doshell(comstring,nohalt) : doexec(comstring); +if(procp->pid == -1) + fatal("fork failed"); +procstack[nproc].nohalt = nohalt; +procstack[nproc].nowait = nowait; +procstack[nproc].done = NO; +++proclive; +++nproc; + +if(nowait) + { + printf(" &%d\n", procp->pid); + fflush(stdout); + return 0; + } +if(prefix) + { + putchar('\n'); + fflush(stdout); + } +return waitstack(nproc-1); +} + +static int +metas(char *s) /* Are there are any Shell meta-characters? */ +{ +char c; + +while( (funny[c = *s++] & META) == 0 ) + ; +return( c ); +} + +static void +doclose(void) /* Close open directory files before exec'ing */ +{ +struct dirhd *od; + +for (od = firstod; od; od = od->nxtdirhd) + if(od->dirfc) + closedir(od->dirfc); +} + +/* wait till none of the processes in the stack starting at k is live */ +int +waitstack(int k) +{ +int npending, status, totstatus; +int i; + +totstatus = 0; +npending = 0; +for(i=k ; i<nproc; ++i) + if(! procstack[i].done) + ++npending; +enbint(SIG_IGN); +if(dbgflag > 1) + printf("waitstack(%d)\n", k); + +while(npending>0 && proclive>0) + { + if(waitproc(&status) >= k) + --npending; + totstatus |= status; + } + +if(nproc > k) + nproc = k; +enbint(intrupt); +return totstatus; +} + +static int +waitproc(int *statp) +{ +pid_t pid; +int status; +int i; +struct process *procp; +char junk[50]; +static int inwait = NO; + +if(inwait) /* avoid infinite recursions on errors */ + return MAXPROC; +inwait = YES; + +pid = wait(&status); +if(dbgflag > 1) + fprintf(stderr, "process %d done, status = %d\n", pid, status); +if(pid == -1) + { + if(errno == ECHILD) /* multiple deaths, no problem */ + { + if(proclive) + { + for(i=0, procp=procstack; i<nproc; ++i, ++procp) + procp->done = YES; + proclive = nproc = 0; + } + return MAXPROC; + } + fatal("bad wait code"); + } +for(i=0, procp=procstack; i<nproc; ++i, ++procp) + if(procp->pid == pid) + { + --proclive; + procp->done = YES; + + if(status) + { + if(procp->nowait) + printf("%d: ", pid); + if( WEXITSTATUS(status) ) + printf("*** Error code %d", WEXITSTATUS(status) ); + else printf("*** Termination code %d", WTERMSIG(status)); + + printf(procp->nohalt ? "(ignored)\n" : "\n"); + fflush(stdout); + if(!keepgoing && !procp->nohalt) + fatal(CHNULL); + } + *statp = status; + inwait = NO; + return i; + } + +sprintf(junk, "spurious return from process %d", pid); +fatal(junk); +/*NOTREACHED*/ +} + +static int +doshell(char *comstring, int nohalt) +{ +pid_t pid; + +if((pid = fork()) == 0) + { + enbint(SIG_DFL); + doclose(); + + execl(SHELLCOM, "sh", (nohalt ? "-c" : "-ce"), comstring, NULL); + fatal("Couldn't load Shell"); + } + +return pid; +} + +static int +doexec(char *str) +{ +char *t, *tend; +char **argv; +char **p; +int nargs; +pid_t pid; + +while( *str==' ' || *str=='\t' ) + ++str; +if( *str == '\0' ) + return(-1); /* no command */ + +nargs = 1; +for(t = str ; *t ; ) + { + ++nargs; + while(*t!=' ' && *t!='\t' && *t!='\0') + ++t; + if(*t) /* replace first white space with \0, skip rest */ + for( *t++ = '\0' ; *t==' ' || *t=='\t' ; ++t) + ; + } + +/* now allocate args array, copy pointer to start of each string, + then terminate array with a null +*/ +p = argv = (char **) ckalloc(nargs*sizeof(char *)); +tend = t; +for(t = str ; t<tend ; ) + { + *p++ = t; + while( *t ) + ++t; + do { + ++t; + } while(t<tend && (*t==' ' || *t=='\t') ); + } +*p = NULL; +/*TEMP for(p=argv; *p; ++p)printf("arg=%s\n", *p);*/ + +if((pid = fork()) == 0) + { + enbint(SIG_DFL); + doclose(); + enbint(intrupt); + execvp(str, argv); + printf("\n"); + fatal1("Cannot load %s",str); + } + +free( (char *) argv); +return pid; +} + +void +touch(int force, char *name) +{ +struct stat stbuff; +char junk[1]; +int fd; + +if( stat(name,&stbuff) < 0) + if(force) + goto create; + else + { + fprintf(stderr, "touch: file %s does not exist.\n", name); + return; + } + +if(stbuff.st_size == 0) + goto create; + +if( (fd = open(name, O_RDWR)) < 0) + goto bad; + +if( read(fd, junk, 1) < 1) + { + close(fd); + goto bad; + } +lseek(fd, 0L, SEEK_SET); +if( write(fd, junk, 1) < 1 ) + { + close(fd); + goto bad; + } +close(fd); +return; + +bad: + fprintf(stderr, "Cannot touch %s\n", name); + return; + +create: + if( (fd = creat(name, 0666)) < 0) + goto bad; + close(fd); +} diff --git a/sys/src/ape/cmd/make/files.c b/sys/src/ape/cmd/make/files.c new file mode 100755 index 000000000..59b8ddf84 --- /dev/null +++ b/sys/src/ape/cmd/make/files.c @@ -0,0 +1,552 @@ +/* POSIX DEPENDENT PROCEDURES */ +#include "defs.h" +#include <sys/stat.h> +#include <ar.h> + +#define NAMESPERBLOCK 32 + +/* DEFAULT RULES FOR POSIX */ + +char *dfltmacro[] = + { + ".SUFFIXES : .o .c .y .l .a .sh .f", + "MAKE=make", + "AR=ar", + "ARFLAGS=rv", + "YACC=yacc", + "YFLAGS=", + "LEX=lex", + "LFLAGS=", + "LDFLAGS=", + "CC=c89", + "CFLAGS=-O", + "FC=fort77", + "FFLAGS=-O 1", + 0 }; + +char *dfltpat[] = + { + "%.o : %.c", + "\t$(CC) $(CFLAGS) -c $<", + + "%.o : %.y", + "\t$(YACC) $(YFLAGS) $<", + "\t$(CC) $(CFLAGS) -c y.tab.c", + "\trm y.tab.c", + "\tmv y.tab.o $@", + + "%.o : %.l", + "\t$(LEX) $(LFLAGS) $<", + "\t$(CC) $(CFLAGS) -c lex.yy.c", + "\trm lex.yy.c", + "\tmv lex.yy.o $@", + + "%.c : %.y", + "\t$(YACC) $(YFLAGS) $<", + "\tmv y.tab.c $@", + + "%.c : %.l", + "\t$(LEX) $(LFLAGS) $<", + "\tmv lex.yy.c $@", + + "% : %.o", + "\t$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<", + + "% : %.c", + "\t$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<", + + 0 }; + + + +char *dfltsuff[] = + { + ".SUFFIXES : .o .c .y .l .a .sh .f", + ".c.o :", + "\t$(CC) $(CFLAGS) -c $<", + + ".f.o :", + "\t$(FC) $(FFLAGS) -c $<", + + ".y.o :", + "\t$(YACC) $(YFLAGS) $<", + "\t$(CC) $(CFLAGS) -c y.tab.c", + "\trm -f y.tab.c", + "\tmv y.tab.o $@", + + ".l.o :", + "\t$(LEX) $(LFLAGS) $<", + "\t$(CC) $(CFLAGS) -c lex.yy.c", + "\trm -f lex.yy.c", + "\tmv lex.yy.o $@", + + ".y.c :", + "\t$(YACC) $(YFLAGS) $<", + "\tmv y.tab.c $@", + + ".l.c :", + "\t$(LEX) $(LFLAGS) $<", + "\tmv lex.yy.c $@", + + ".c.a:", + "\t$(CC) -c $(CFLAGS) $<", + "\t$(AR) $(ARFLAGS) $@ $*.o", + "\trm -f $*.o", + + ".f.a:", + "\t$(FC) -c $(FFLAGS) $<", + "\t$(AR) $(ARFLAGS) $@ $*.o", + "\trm -f $*.o", + + ".c:", + "\t$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<", + + ".f:", + "\t$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<", + + ".sh:", + "\tcp $< $@", + "\tchmod a+x $@", + + 0 }; + + +static struct dirhd *opdir(char *, int); +static void cldir(struct dirhd *, int); +static int amatch(char *, char *); +static int umatch(char *, char *); +static void clarch(void); +static int openarch(char *); +static int getarch(void); + +time_t +exists(char *filename) +{ +struct stat buf; +char *s; + +for(s = filename ; *s!='\0' && *s!='(' && *s!=')' ; ++s) + ; + +if(*s != '\0') + return lookarch(filename); + +if(stat(filename,&buf) < 0) + return 0; +else return buf.st_mtime; +} + + +time_t +prestime(void) +{ +time_t t; +time(&t); +return t; +} + +static char nmtemp[MAXNAMLEN+1]; /* guarantees a null after the name */ +static char *tempend = nmtemp + MAXNAMLEN; + + + +depblkp +srchdir(char *pat, int mkchain, depblkp nextdbl) +{ +DIR *dirf; +struct dirhd *dirptr; +char *dirname, *dirpref, *endir, *filepat, *p, temp[100]; +char fullname[100]; +nameblkp q; +depblkp thisdbl; +struct pattern *patp; + +struct dirent *dptr; + +thisdbl = 0; + +if(mkchain == NO) + for(patp=firstpat ; patp ; patp = patp->nxtpattern) + if(equal(pat, patp->patval)) return 0; + +patp = ALLOC(pattern); +patp->nxtpattern = firstpat; +firstpat = patp; +patp->patval = copys(pat); + +endir = 0; + +for(p=pat; *p!='\0'; ++p) + if(*p=='/') endir = p; + +if(endir==0) + { + dirname = "."; + dirpref = ""; + filepat = pat; + } +else { + dirname = pat; + *endir = '\0'; + dirpref = concat(dirname, "/", temp); + filepat = endir+1; + } + +dirptr = opdir(dirname,YES); +dirf = dirptr->dirfc; + +for( dptr = readdir(dirf) ; dptr ; dptr = readdir(dirf) ) + { + char *p1, *p2; + p1 = dptr->d_name; + p2 = nmtemp; + while( (p2<tempend) && (*p2++ = *p1++)!='\0') + ; + if( amatch(nmtemp,filepat) ) + { + concat(dirpref,nmtemp,fullname); + if( (q=srchname(fullname)) ==0) + q = makename(copys(fullname)); + if(mkchain) + { + thisdbl = ALLOC(depblock); + thisdbl->nxtdepblock = nextdbl; + thisdbl->depname = q; + nextdbl = thisdbl; + } + } + } + + +if(endir) + *endir = '/'; + +cldir(dirptr, YES); + +return thisdbl; +} + +static struct dirhd * +opdir(char *dirname, int stopifbad) +{ +struct dirhd *od; + +for(od = firstod; od; od = od->nxtdirhd) + if(equal(dirname, od->dirn) ) + break; + +if(od == NULL) + { + ++nopdir; + od = ALLOC(dirhd); + od->nxtdirhd = firstod; + firstod = od; + od->dirn = copys(dirname); + } + +if(od->dirfc==NULL && (od->dirfc = opendir(dirname)) == NULL && stopifbad) + { + fprintf(stderr, "Directory %s: ", dirname); + fatal("Cannot open"); + } + +return od; +} + + +static void +cldir(struct dirhd *dp, int used) +{ +if(nopdir >= MAXDIR) + { + closedir(dp->dirfc); + dp->dirfc = NULL; + } +else if(used) + rewinddir(dp->dirfc); /* start over at the beginning */ +} + +/* stolen from glob through find */ + +static int +amatch(char *s, char *p) +{ + int cc, scc, k; + int c, lc; + + scc = *s; + lc = 077777; + switch (c = *p) { + + case '[': + k = 0; + while (cc = *++p) { + switch (cc) { + + case ']': + if (k) + return amatch(++s, ++p); + else + return 0; + + case '-': + k |= (lc <= scc) & (scc <= (cc=p[1]) ) ; + } + if (scc==(lc=cc)) k++; + } + return 0; + + case '?': + caseq: + if(scc) return amatch(++s, ++p); + return 0; + case '*': + return umatch(s, ++p); + case 0: + return !scc; + } + if (c==scc) goto caseq; + return 0; +} + +static int +umatch(char *s, char *p) +{ + if(*p==0) return 1; + while(*s) + if (amatch(s++,p)) return 1; + return 0; +} + +#ifdef METERFILE +#include <pwd.h> +int meteron = 0; /* default: metering off */ + +extern void meter(char *file) +{ +time_t tvec; +char *p; +FILE * mout; +struct passwd *pwd; + +if(file==0 || meteron==0) return; + +pwd = getpwuid(getuid()); + +time(&tvec); + +if( mout = fopen(file,"a") ) + { + p = ctime(&tvec); + p[16] = '\0'; + fprintf(mout, "User %s, %s\n", pwd->pw_name, p+4); + fclose(mout); + } +} +#endif + + +/* look inside archives for notation a(b) + a(b) is file member b in archive a +*/ + +static long arflen; +static long arfdate; +static char arfname[16]; +FILE *arfd; +long int arpos, arlen; + +time_t +lookarch(char *filename) +{ +char *p, *q, *send, s[15], pad; +int i, nc, nsym; + +for(p = filename; *p!= '(' ; ++p) + ; + +*p = '\0'; +if( ! openarch(filename) ) + { + *p = '('; + return 0L; + } +*p++ = '('; +nc = 14; +pad = ' '; + +send = s + nc; +for( q = s ; q<send && *p!='\0' && *p!=')' ; *q++ = *p++ ) + ; +if(p[0]==')' && p[1]!='\0') /* forbid stuff after the paren */ + { + clarch(); + return 0L; + } +while(q < send) + *q++ = pad; +while(getarch()) + { + if( !strncmp(arfname, s, nc)) + { + clarch(); +/*TEMP fprintf(stderr, "found archive member %14s, time=%d\n", s, arfdate); */ + return arfdate; + } + } + +clarch(); +return 0L; +} + +static void +clarch(void) +{ +fclose( arfd ); +} + +static int +openarch(char *f) +{ +char magic[SARMAG]; +int word; +struct stat buf; +nameblkp p; + +stat(f, &buf); +arlen = buf.st_size; + +arfd = fopen(f, "r"); +if(arfd == NULL) + return NO; + /* fatal1("cannot open %s", f); */ + +fread( (char *) &word, sizeof(word), 1, arfd); + +fseek(arfd, 0L, 0); +fread(magic, SARMAG, 1, arfd); +arpos = SARMAG; +if( strncmp(magic, ARMAG, SARMAG) ) + fatal1("%s is not an archive", f); + +if( !(p = srchname(f)) ) + p = makename( copys(f) ); +p->isarch = YES; +arflen = 0; +return YES; +} + + +static int +getarch(void) +{ +struct ar_hdr arhead; + +arpos += (arflen + 1) & ~1L; /* round archived file length up to even */ +if(arpos >= arlen) + return 0; +fseek(arfd, arpos, 0); + +fread( (char *) &arhead, sizeof(arhead), 1, arfd); +arpos += sizeof(arhead); +arflen = atol(arhead.ar_size); +arfdate = atol(arhead.ar_date); +strncpy(arfname, arhead.ar_name, sizeof(arhead.ar_name)); +return 1; +} + +/* find the directory containing name. + read it into the hash table if it hasn't been used before or if + if might have changed since last reference +*/ + +void +dirsrch(char *name) +{ +DIR *dirf; +struct dirhd *dirp; +time_t dirt, objt; +int dirused, hasparen; +char *dirname, *lastslash; +char *fullname, *filepart, *fileend, *s; +struct dirent *dptr; + +lastslash = NULL; +hasparen = NO; + +for(s=name; *s; ++s) + if(*s == '/') + lastslash = s; + else if(*s=='(' || *s==')') + hasparen = YES; + +if(hasparen) + { + if(objt = lookarch(name)) + makename(name)->modtime = objt; + return; + } + +if(lastslash) + { + dirname = name; + *lastslash = '\0'; + } +else + dirname = "."; + +dirused = NO; +dirp = opdir(dirname, NO); +dirf = dirp->dirfc; +if(dirp->dirok || !dirf) + goto ret; +dirt = exists(dirname); +if(dirp->dirtime == dirt) + goto ret; + +dirp->dirok = YES; +dirp->dirtime = dirt; +dirused = YES; + +/* allocate buffer to hold full file name */ +if(lastslash) + { + fullname = (char *) ckalloc(strlen(dirname)+MAXNAMLEN+2); + concat(dirname, "/", fullname); + filepart = fullname + strlen(fullname); + } +else + filepart = fullname = (char *) ckalloc(MAXNAMLEN+1); + + +fileend = filepart + MAXNAMLEN; +*fileend = '\0'; +for(dptr = readdir(dirf) ; dptr ; dptr = readdir(dirf) ) + { + char *p1, *p2; + p1 = dptr->d_name; + p2 = filepart; + while( (p2<fileend) && (*p2++ = *p1++)!='\0') + ; + if( ! srchname(fullname) ) + (void) makename(copys(fullname)); + } + +free(fullname); + +ret: + cldir(dirp, dirused); + if(lastslash) + *lastslash = '/'; +} + + + +void +baddirs(void) +{ +struct dirhd *od; + +for(od = firstod; od; od = od->nxtdirhd) + od->dirok = NO; +} diff --git a/sys/src/ape/cmd/make/gram.y b/sys/src/ape/cmd/make/gram.y new file mode 100755 index 000000000..db83c5148 --- /dev/null +++ b/sys/src/ape/cmd/make/gram.y @@ -0,0 +1,441 @@ +%{#include "defs.h" +%} + +%term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER AMPER AMPERAMPER +%union + { + struct shblock *yshblock; + depblkp ydepblock; + nameblkp ynameblock; + } + +%type <yshblock> SHELLINE, shlist, shellist +%type <ynameblock> NAME, namelist +%type <ydepblock> deplist, dlist + + +%% + +%{ +struct depblock *pp; +static struct shblock *prevshp; + +static struct nameblock *lefts[NLEFTS]; +struct nameblock *leftp; +static int nlefts; + +struct lineblock *lp, *lpp; +static struct depblock *prevdep; +static int sepc; +static int allnowait; + +static struct fstack + { + FILE *fin; + char *fname; + int lineno; + } filestack[MAXINCLUDE]; +static int ninclude = 0; +%} + + +file: + | file comline + ; + +comline: START + | MACRODEF + | START namelist deplist shellist = { + while( --nlefts >= 0) + { + wildp wp; + + leftp = lefts[nlefts]; + if(wp = iswild(leftp->namep)) + { + leftp->septype = SOMEDEPS; + if(lastwild) + lastwild->next = wp; + else + firstwild = wp; + lastwild = wp; + } + + if(leftp->septype == 0) + leftp->septype = sepc; + else if(leftp->septype != sepc) + { + if(! wp) + fprintf(stderr, + "Inconsistent rules lines for `%s'\n", + leftp->namep); + } + else if(sepc==ALLDEPS && leftp->namep[0]!='.' && $4!=0) + { + for(lp=leftp->linep; lp->nxtlineblock; lp=lp->nxtlineblock) + if(lp->shp) + fprintf(stderr, + "Multiple rules lines for `%s'\n", + leftp->namep); + } + + lp = ALLOC(lineblock); + lp->nxtlineblock = NULL; + lp->depp = $3; + lp->shp = $4; + if(wp) + wp->linep = lp; + + if(equal(leftp->namep, ".SUFFIXES") && $3==0) + leftp->linep = 0; + else if(leftp->linep == 0) + leftp->linep = lp; + else { + for(lpp = leftp->linep; lpp->nxtlineblock; + lpp = lpp->nxtlineblock) ; + if(sepc==ALLDEPS && leftp->namep[0]=='.') + lpp->shp = 0; + lpp->nxtlineblock = lp; + } + } + } + | error + ; + +namelist: NAME = { lefts[0] = $1; nlefts = 1; } + | namelist NAME = { lefts[nlefts++] = $2; + if(nlefts>=NLEFTS) fatal("Too many lefts"); } + ; + +deplist: + { + char junk[100]; + sprintf(junk, "%s:%d", filestack[ninclude-1].fname, yylineno); + fatal1("Must be a separator on rules line %s", junk); + } + | dlist + ; + +dlist: sepchar = { prevdep = 0; $$ = 0; allnowait = NO; } + | sepchar AMPER = { prevdep = 0; $$ = 0; allnowait = YES; } + | dlist NAME = { + pp = ALLOC(depblock); + pp->nxtdepblock = NULL; + pp->depname = $2; + pp->nowait = allnowait; + if(prevdep == 0) $$ = pp; + else prevdep->nxtdepblock = pp; + prevdep = pp; + } + | dlist AMPER = { if(prevdep) prevdep->nowait = YES; } + | dlist AMPERAMPER + ; + +sepchar: COLON = { sepc = ALLDEPS; } + | DOUBLECOLON = { sepc = SOMEDEPS; } + ; + +shellist: = {$$ = 0; } + | shlist = { $$ = $1; } + ; + +shlist: SHELLINE = { $$ = $1; prevshp = $1; } + | shlist SHELLINE = { $$ = $1; + prevshp->nxtshblock = $2; + prevshp = $2; + } + ; + +%% + +static char *zznextc; /* null if need another line; + otherwise points to next char */ +static int yylineno; +static FILE * fin; +static int retsh(char *); +static int nextlin(void); +static int isinclude(char *); + +int yyparse(void); + +int +parse(char *name) +{ +FILE *stream; + +if(name == CHNULL) + { + stream = NULL; + name = "(builtin-rules)"; + } +else if(equal(name, "-")) + { + stream = stdin; + name = "(stdin)"; + } +else if( (stream = fopen(name, "r")) == NULL) + return NO; +filestack[0].fname = copys(name); +ninclude = 1; +fin = stream; +yylineno = 0; +zznextc = 0; + +if( yyparse() ) + fatal("Description file error"); + +if(fin) + fclose(fin); +return YES; +} + +int +yylex(void) +{ +char *p; +char *q; +char word[INMAX]; + +if(! zznextc ) + return nextlin() ; + +while( isspace(*zznextc) ) + ++zznextc; +switch(*zznextc) + { + case '\0': + return nextlin() ; + + case '|': + if(zznextc[1]==':') + { + zznextc += 2; + return DOUBLECOLON; + } + break; + case ':': + if(*++zznextc == ':') + { + ++zznextc; + return DOUBLECOLON; + } + return COLON; + case '>': + ++zznextc; + return GREATER; + case '&': + if(*++zznextc == '&') + { + ++zznextc; + return AMPERAMPER; + } + return AMPER; + case ';': + return retsh(zznextc) ; + } + +p = zznextc; +q = word; + +while( ! ( funny[*p] & TERMINAL) ) + *q++ = *p++; + +if(p != zznextc) + { + *q = '\0'; + if((yylval.ynameblock=srchname(word))==0) + yylval.ynameblock = makename(word); + zznextc = p; + return NAME; + } + +else { + char junk[100]; + sprintf(junk, "Bad character %c (octal %o), line %d of file %s", + *zznextc, *zznextc, yylineno, filestack[ninclude-1].fname); + fatal(junk); + } +return 0; /* never executed */ +} + + + + +static int +retsh(char *q) +{ +register char *p; +struct shblock *sp; + +for(p=q+1 ; *p==' '||*p=='\t' ; ++p) ; + +sp = ALLOC(shblock); +sp->nxtshblock = NULL; +sp->shbp = (fin ? copys(p) : p ); +yylval.yshblock = sp; +zznextc = 0; +return SHELLINE; +} + +static int +nextlin(void) +{ +static char yytext[INMAX]; +static char *yytextl = yytext+INMAX; +char *text, templin[INMAX]; +char c; +char *p, *t; +char lastch, *lastchp; +extern char **linesptr; +int incom; +int kc; + +again: + + incom = NO; + zznextc = 0; + +if(fin == NULL) + { + if( (text = *linesptr++) == 0) + return 0; + ++yylineno; + } + +else { + for(p = text = yytext ; p<yytextl ; *p++ = kc) + switch(kc = getc(fin)) + { + case '\t': + if(p == yytext) + incom = YES; + break; + + case ';': + incom = YES; + break; + + case '#': + if(! incom) + kc = '\0'; + break; + + case '\n': + ++yylineno; + if(p==yytext || p[-1]!='\\') + { + *p = '\0'; + goto endloop; + } + p[-1] = ' '; + while( (kc=getc(fin))=='\t' || kc==' ' || kc=='\n') + if(kc == '\n') + ++yylineno; + + if(kc != EOF) + break; + case EOF: + *p = '\0'; + if(ninclude > 1) + { + register struct fstack *stp; + fclose(fin); + --ninclude; + stp = filestack + ninclude; + fin = stp->fin; + yylineno = stp->lineno; + free(stp->fname); + goto again; + } + return 0; + } + + fatal("line too long"); + } + +endloop: + + if((c = text[0]) == '\t') + return retsh(text) ; + + if(isalpha(c) || isdigit(c) || c==' ' || c=='.'|| c=='_') + for(p=text+1; *p!='\0'; ) + if(*p == ':') + break; + else if(*p++ == '=') + { + eqsign(text); + return MACRODEF; + } + +/* substitute for macros on dependency line up to the semicolon if any */ + +for(t = yytext ; *t!='\0' && *t!=';' ; ++t) + ; + +lastchp = t; +lastch = *t; +*t = '\0'; /* replace the semi with a null so subst will stop */ + +subst(yytext, templin); /* Substitute for macros on dependency lines */ + +if(lastch) /* copy the stuff after the semicolon */ + { + *lastchp = lastch; + strcat(templin, lastchp); + } + +strcpy(yytext, templin); + +/* process include files after macro substitution */ +if(strncmp(text, "include", 7) == 0) { + if (isinclude(text+7)) + goto again; +} + +for(p = zznextc = text ; *p ; ++p ) + if(*p!=' ' && *p!='\t') + return START; +goto again; +} + + +static int +isinclude(char *s) +{ +char *t; +struct fstack *p; + +for(t=s; *t==' ' || *t=='\t' ; ++t) + ; +if(t == s) + return NO; + +for(s = t; *s!='\n' && *s!='#' && *s!='\0' ; ++s) + if(*s == ':') + return NO; +*s = '\0'; + +if(ninclude >= MAXINCLUDE) + fatal("include depth exceeded"); +p = filestack + ninclude; +p->fin = fin; +p->lineno = yylineno; +p->fname = copys(t); +if( (fin = fopen(t, "r")) == NULL) + fatal1("Cannot open include file %s", t); +yylineno = 0; +++ninclude; +return YES; +} + + +int +yyerror(char *s, ...) +{ +char buf[100]; + +sprintf(buf, "line %d of file %s: %s", + yylineno, filestack[ninclude-1].fname, s); +fatal(buf); +} diff --git a/sys/src/ape/cmd/make/ident.c b/sys/src/ape/cmd/make/ident.c new file mode 100755 index 000000000..00df0b9de --- /dev/null +++ b/sys/src/ape/cmd/make/ident.c @@ -0,0 +1,125 @@ +char *xxxvers = "\n@(#) MAKE. VERSION 2.78 22 MAY 1986\n" ; +static char *sccsid = "@(#)ident.c 8th Edition (Bell Labs) 85/10/28"; + +/* +2.1 4/24/76 Base version + +2.2 4/26/76 Error found by SRB in overriding pattern rules; + corrected gram.y + +2.3 4/27/76 Further correction for overriding pattern rules; + corrected doname.c + +2.4 Removed .CLEAR name, added .IGNORE. + A .SUFFIXES rule without dependents clears the list + +2.5 Stripped output + +2.6 Changed doshell to accomodate new shell. + +2.7 Following SRB's sugestion, added ${...} as + alternate macro name + +2.8 Defined macros AS and DTGEN in files.c. + +2.9 Put in a fix to prevent removal of files + upon interrupt in a :: rule. + +2.10 Fixed bugs involving messages for :: + and closing standard input + +2.11 Changed time test from <= to < + (equal times are considered in sync) + +2.12 Installed -t flag (touch and update time of + files rather than issue commands) + Fixed bug in dosys + +2.13 Fixed lex.c to allow sharps (#) in commands + +2.14 Added .DEFAULT rule + +2.15 Changed to <lS> I/O System (stdio.h) + +2.16 Removed references to double floats and macro HAVELONGS; + committed to use of long ints for times. +2.17 Corrected metacharacter list in dosys.c. +2.18 Miscellaneous fixes +2.19 Updated files.c to use include file stat.h +2.20 Added -q flag for Mike Lesk +2.21 Added AWK rules and .w suffix to files.c +2.22 Added colon to the list of metacharacters +2.23 Macro substitutions on dependency lines. + Redid argument and macro setting. + Close files before exec'ing. + Print > at beginning of command lines. + No printing of commands beginnng with @. +2.24 Parametrized propt sequence in doname.c (4/1/77) +2.25 Added $? facility +2.26 Fixed bug in macro expansion +2.27 Repaired interrupt handling +2.28 Repaired bug in -n +2.29 Repaired bug in file closing and $? string creation +2.30 Repaired bug in grammar about command lines +2.31 Added -k flag, modified doname.c and defs +2.32 Made "keepgoing" the default, added -S flag, + changed handling of funny characters internally +2.3 Small fixups to interrupt and quit handling. + Changed default back to -k. +2.34 Added .PRECIOUS rule for interrupts +2.35 Added references to include files (due to TLL) +2.36 Fixed bug in lex.c so = permitted in rules on :; line +2.37 Miscellaneous code cleanups +2.38 Sleep one second after each touch in -t mode +2.39 Extended string[] declaration in doname.c +2.40 Permit recursive macro references +2.41 Separated YYLMAX into INMAX and OUTMAX macros, specifying longest + input and output lines respectively. +2.42 Fixed bug involving :: lines without dependents +2.43 Main name is first name that contains a slash or doesn't + begin with a dot +2.44 Fixed bug involving $$ on command line +2.45 Changed files.c to put .f before .e, .r and to use f77 instead of fc. +2.46 Changed dosys.c to eliminate copying and to call execvp. +2.47 Changed files.c to add ".out" suffix and rules. +2.48 Changed misc.c to permit tabs preceding = in macro definition +2.49 Added reference to <ctyp.h>. Removed -lS references from files.c +2.50 General cleanup to reduce lint messages. (changes in declarations + and in uses of variables) +2.51 Further cleanup making use of new Yacc features. +2.52 +2.53 Changed handling of "touch" +2.54 Fixed bug involving comments in lexical analyzer. +2.55 Ignore commands that begin with a # are comments. +2.56 Added = to list of META characters (to permit shell commands) +2.57 Changed lookarch and getobj to fix bugs. +2.58 Fixed interrupt handling. +2.59 Changed references to sprintf to accomodate new function definition + Also fixed extern declarations. +2.60 Limited the number of open directories. +2.61 Added code to handle archives with ascii headers. +2.62 Joe Condon Fixes to archive formats +2.63 Pattern Matching (%) stuff. +2.64 Reinstalled $(TGS) as $^ from other version +2.65 Installed dynamic macros ( := commands). +2.66 Sped up pattern matching code +2.67 Changed pattern matching code to permit multiple dependents +2.68 Added + (do it despite -n) prefix to command lines. + Fixed bug involving metacharacter expansions on dependency lines. +2.69 Added & to dependency lines and new background process spawning +2.70 Added Bradford's macros: $/, $@, *D, *F, <D, <F, @D, @F. +2.71 Added include stack to input. + Added check for sccs makefiles: s.[Mm]akefile +2.72 Load environment into macro tables. Added Bradford's -e flag. +2.73 Pass changed environment macros out to commands. +2.74 Fixed limit on args in dosys.c. + Non-existent archives now treated as other non-existent files. +2.75 Fixed bug in rehash. +2.76 Fixed bug when pattern searching in non-existent directory + Fixed infinite loop when awaiting failed process + Now wait till all subjobs finish before returning + make, unless a subjob fails +2.77 Added -z option that always forces shell invocation + rather than direct fork-exec +2.78 Check for error (-1) returned from fork +*/ diff --git a/sys/src/ape/cmd/make/main.c b/sys/src/ape/cmd/make/main.c new file mode 100755 index 000000000..26853e86b --- /dev/null +++ b/sys/src/ape/cmd/make/main.c @@ -0,0 +1,423 @@ +# include "defs.h" +/* +command make to update programs. +Posix Flags: + 'e' use environment macros after rather than before makefiles + 'f' the next argument is the name of the description file; + "makefile" is the default + 'i' ignore error codes from the shell + 'k' continue to update other targets that don't depend + on target if error occurs making a target + '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' clear the builtin suffix list and don't use built-in rules + 's' silent mode--don't print out commands + 'S' stop after any command fails (default; opposite of -k) + 't' touch (update time of) files but don't issue command + +Nonposix Flags: + 'd' print out debugging comments + 'N' use % patterns instead of old suffix rules + 'Pn' set process limit to n + 'z' always use shell, never issue commands directly + +*/ + +nameblkp mainname = NULL; +nameblkp firstname = NULL; +lineblkp sufflist = NULL; +struct varblock *firstvar = NULL; +struct pattern *firstpat = NULL; +struct dirhd *firstod = NULL; +wildp firstwild = NULL; +wildp lastwild = NULL; +nameblkp *hashtab; +int nhashed; +int hashsize; +int hashthresh; + +int proclimit = PROCLIMIT; +int nproc = 0; +int proclive = 0; +struct process procstack[MAXPROC]; + +int sigivalue = 0; +int sigqvalue = 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 oldflag = YES; +int ndocoms = NO; +int ignerr = NO; /* default is to stop on error */ +int forceshell = NO; +int okdel = YES; +int envlast = NO; +int inarglist = NO; +char **envpp = NULL; + +extern char *dfltmacro[]; +extern char *dfltpat[]; +extern char *dfltsuff[]; +extern char **environ; +char **linesptr; + +char *prompt = ""; +int nopdir = 0; +char funny[128]; + +static void loadenv(void); +static int isprecious(char *); +static int rddescf(char *); +static void rdarray(char **); +static void printdesc(int); + +void +main(int argc, char **argv) +{ +nameblkp p; +int i, j; +int descset, nfargs; +int nowait = NO; +time_t tjunk; +char c, *s, *mkflagp; +static char makeflags[30] = "-"; +static char onechar[2] = "X"; + +descset = 0; +mkflagp = makeflags+1; + +funny['\0'] = (META | TERMINAL); +for(s = "=|^();&<>*?[]:$`'\"\\\n" ; *s ; ++s) + funny[*s] |= META; +for(s = "\n\t :;&>|" ; *s ; ++s) + funny[*s] |= TERMINAL; + + +newhash(HASHSIZE); + +inarglist = YES; +for(i=1; i<argc; ++i) + if(argv[i]!=0 && argv[i][0]!='-' && eqsign(argv[i])) + argv[i] = 0; + +setvar("$", "$", NO); +inarglist = NO; + +for(i=1; i<argc; ++i) + if(argv[i]!=0 && argv[i][0]=='-') + { + for(j=1 ; (c=argv[i][j])!='\0' ; ++j) switch(c) + { + case 'd': + ++dbgflag; + *mkflagp++ = 'd'; + break; + + case 'e': + envlast = YES; + *mkflagp++ = 'e'; + break; + + 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; + + case 'i': + ignerr = YES; + *mkflagp++ = 'i'; + break; + + case 'k': + keepgoing = YES; + *mkflagp++ = 'k'; + break; + + case 'n': + noexflag = YES; + *mkflagp++ = 'n'; + break; + + case 'N': + oldflag = NO; + *mkflagp++ = 'N'; + break; + + case 'p': + prtrflag = YES; + break; + + case 'P': + if(isdigit(argv[i][j+1])) + { + proclimit = argv[i][++j] - '0'; + if(proclimit < 1) + proclimit = 1; + } + else + fatal("illegal proclimit parameter"); + *mkflagp++ = 'P'; + *mkflagp++ = argv[i][j]; + break; + + case 'q': + questflag = YES; + *mkflagp++ = 'q'; + break; + + case 'r': + noruleflag = YES; + *mkflagp++ = 'r'; + break; + + case 's': + silflag = YES; + *mkflagp++ = 's'; + break; + + case 'S': + keepgoing = NO; + *mkflagp++ = 'S'; + break; + + case 't': + touchflag = YES; + *mkflagp++ = 't'; + break; + + case 'z': + forceshell = YES; + *mkflagp++ = 'z'; + break; + + default: + onechar[0] = c; /* to make lint happy */ + fatal1("Unknown flag argument %s", onechar); + } + + argv[i] = NULL; + } + +if(mkflagp > makeflags+1) + setvar("MAKEFLAGS", makeflags, NO); + +if( !descset ) +if( !rddescf("makefile") && + !rddescf("Makefile") && + (exists(s = "s.makefile") || exists(s = "s.Makefile")) ) + { + char junk[20]; + concat("get ", s, junk); + (void) dosys(junk, NO, NO, junk); + rddescf(s+2); + unlink(s+2); + } + + +if(envlast) + loadenv(); +if(!noruleflag && !oldflag) + rdarray(dfltpat); + +if(prtrflag) printdesc(NO); + +if( srchname(".IGNORE") ) + ignerr = YES; +if( srchname(".SILENT") ) + silflag = YES; +if( srchname(".OLDFLAG") ) + oldflag = YES; +if( p=srchname(".SUFFIXES") ) + sufflist = p->linep; +if( !sufflist && !firstwild) + fprintf(stderr,"No suffix or %% pattern list.\n"); +/* +if(sufflist && !oldflag) + fprintf(stderr, "Suffix lists are old-fashioned. Use %% patterns\n); +*/ + + sigivalue = (int) signal(SIGINT, SIG_IGN); + sigqvalue = (int) signal(SIGQUIT, SIG_IGN); + enbint(intrupt); + +nfargs = 0; + +for(i=1; i<argc; ++i) + if(s = argv[i]) + { + if((p=srchname(s)) == NULL) + p = makename(s); + ++nfargs; + if(i+1<argc && argv[i+1] != 0 && equal(argv[i+1], "&") ) + { + ++i; + nowait = YES; + } + else + nowait = NO; + doname(p, 0, &tjunk, nowait); + 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 { + doname(mainname, 0, &tjunk, NO); + if(dbgflag) printdesc(YES); + } + +if(!nowait) + waitstack(0); +exit(0); +} + + +void +intrupt(int sig) +{ +char *p; + +if(okdel && !noexflag && !touchflag && + (p = varptr("@")->varval) && exists(p)>0 && !isprecious(p) ) + { + fprintf(stderr, "\n*** %s removed.", p); + remove(p); + } + +fprintf(stderr, "\n"); +exit(2); +} + + + +static int +isprecious(char *p) +{ +lineblkp lp; +depblkp dp; +nameblkp np; + +if(np = srchname(".PRECIOUS")) + for(lp = np->linep ; lp ; lp = lp->nxtlineblock) + for(dp = lp->depp ; dp ; dp = dp->nxtdepblock) + if(equal(p, dp->depname->namep)) + return YES; + +return NO; +} + + +void +enbint(void (*k)(int)) +{ +if(sigivalue == 0) + signal(SIGINT,k); +if(sigqvalue == 0) + signal(SIGQUIT,k); +} + +static int +rddescf(char *descfile) +{ +static int firstrd = YES; + +/* read and parse description */ + +if(firstrd) + { + firstrd = NO; + if( !noruleflag ) + { + rdarray(dfltmacro); + if(oldflag) + rdarray(dfltsuff); + } + if(!envlast) + loadenv(); + + } + +return parse(descfile); +} + +static void +rdarray(char **s) +{ +linesptr = s; +parse(CHNULL); +} + +static void +loadenv(void) +{ +for(envpp = environ ; *envpp ; ++envpp) + eqsign(*envpp); +envpp = NULL; +} + +static void +printdesc(int prntflag) +{ +nameblkp p; +depblkp dp; +struct varblock *vp; +struct dirhd *od; +struct shblock *sp; +lineblkp lp; + +if(prntflag) + { + printf("Open directories:\n"); + for (od = firstod; od; od = od->nxtdirhd) + printf("\t%s\n", od->dirn); + } + +if(firstvar != 0) printf("Macros:\n"); +for(vp = firstvar; vp ; vp = vp->nxtvarblock) + printf("\t%s = %s\n" , vp->varname , vp->varval ? vp->varval : "(null)"); + +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 ; sp = sp->nxtshblock) + printf("\t%s\n", sp->shbp); + } + } + } +printf("\n"); +fflush(stdout); +} diff --git a/sys/src/ape/cmd/make/misc.c b/sys/src/ape/cmd/make/misc.c new file mode 100755 index 000000000..cd7a990d2 --- /dev/null +++ b/sys/src/ape/cmd/make/misc.c @@ -0,0 +1,504 @@ +#include "defs.h" + +static int hasslash(char *); +static int haspercent(char *); +static void rehash(void); + +/* simple linear hash. hash function is sum of + characters mod hash table size. +*/ +static int +hashloc(char *s) +{ +int i; +int hashval; +char *t; + +hashval = 0; + +for(t=s; *t!='\0' ; ++t) + hashval += *t; + +hashval %= hashsize; + +for(i=hashval; + hashtab[i]!=0 && !equal(s,hashtab[i]->namep); + i = i >= hashsize-1 ? 0 : i+1) ; + +return i; +} + + +nameblkp +srchname(char *s) +{ +return hashtab[hashloc(s)] ; +} + + + +nameblkp +makename(char *s) +{ +nameblkp p; + +if(nhashed > hashthresh) + rehash(); + +++nhashed; +hashtab[hashloc(s)] = p = ALLOC(nameblock); +p->nxtnameblock = firstname; +p->namep = copys(s); /* make a fresh copy of the string s */ +/* p->linep = 0; p->done = 0; p->septype = 0; p->modtime = 0; */ + +firstname = p; +if(mainname==NULL && !haspercent(s) && (*s!='.' || hasslash(s)) ) + mainname = p; + +return p; +} + + +static int +hasslash(char *s) +{ +for( ; *s ; ++s) + if(*s == '/') + return YES; +return NO; +} + +static int +haspercent(char *s) +{ +for( ; *s ; ++s) + if(*s == '%') + return YES; +return NO; +} + +int +hasparen(char *s) +{ +for( ; *s ; ++s) + if(*s == '(') + return YES; +return NO; +} + +static void +rehash(void) +{ +nameblkp *ohash; +nameblkp p, *hp, *endohash; +hp = ohash = hashtab; +endohash = hashtab + hashsize; + +newhash(2*hashsize); + +while( hp<endohash ) + if(p = *hp++) + hashtab[hashloc(p->namep)] = p; + +free( (char *) ohash); +} + + +void +newhash(int newsize) +{ +hashsize = newsize; +hashtab = (nameblkp *) ckalloc(hashsize * sizeof(nameblkp)); +hashthresh = (2*hashsize)/3; +} + + + +nameblkp chkname(char *s) +{ +nameblkp p; +time_t k; +/*TEMP NEW */ +if(hasparen(s)) + { + k = lookarch(s); +/*TEMP fprintf(stderr, "chkname(%s): look=%d\n", s, k); */ + if(k == 0) + return NULL; + } +if(p = srchname(s)) + return p; +dirsrch(s); +return srchname(s); +} + + + +char * +copys(char *s) +{ +char *t; + +if( (t = malloc( strlen(s)+1 ) ) == NULL) + fatal("out of memory"); +strcpy(t, s); +return t; +} + + + +char * +concat(char *a, char *b, char *c) /* c = concatenation of a and b */ +{ +char *t; +t = c; + +while(*t = *a++) t++; +while(*t++ = *b++); +return c; +} + + +int +suffix(char *a, char *b, char *p) /* is b the suffix of a? if so, set p = prefix */ +{ +char *a0,*b0; +a0 = a; +b0 = b; + +while(*a++); +while(*b++); + +if( (a-a0) < (b-b0) ) return 0; + +while(b>b0) + if(*--a != *--b) return 0; + +while(a0<a) *p++ = *a0++; +*p = '\0'; + +return 1; +} + +int * +ckalloc(int n) +{ +int *p; + +if( p = (int *) calloc(1,n) ) + return p; + +fatal("out of memory"); +/* NOTREACHED */ +} + +/* copy string a into b, substituting for arguments */ +char * +subst(char *a, char *b) +{ +static depth = 0; +char *s; +char vname[100]; +struct varblock *vbp; +char closer; + +if(++depth > 100) + fatal("infinitely recursive macro?"); +if(a) while(*a) + { + if(*a!='$' || a[1]=='\0' || *++a=='$') + /* if a non-macro character copy it. if $$ or $\0, copy $ */ + *b++ = *a++; + else { + s = vname; + if( *a=='(' || *a=='{' ) + { + closer = ( *a=='(' ? ')' : '}'); + ++a; + while(*a == ' ') ++a; + while(*a!=' ' && *a!=closer && *a!='\0') *s++ = *a++; + while(*a!=closer && *a!='\0') ++a; + if(*a == closer) ++a; + } + else *s++ = *a++; + + *s = '\0'; + if( (vbp = varptr(vname)) ->varval != 0) + { + b = subst(vbp->varval, b); + vbp->used = YES; + } + } + } + +*b = '\0'; +--depth; +return b; +} + +void +setvar(char *v, char *s, int dyn) +{ +struct varblock *p; + +p = varptr(v); +if( ! p->noreset ) + { + p->varval = s; + p->noreset = inarglist; + if(p->used && !dyn) + fprintf(stderr, "Warning: %s changed after being used\n",v); + if(p->export) + { + /* change string pointed to by environment to new v=s */ + char *t; + int lenv; + lenv = strlen(v); + *(p->export) = t = (char *) ckalloc(lenv + strlen(s) + 2); + strcpy(t,v); + t[lenv] = '='; + strcpy(t+lenv+1, s); + } + else + p->export = envpp; + } +} + + +/* for setting Bradford's *D and *F family of macros whens setting * etc */ +void +set3var(char *macro, char *value) +{ +char *s; +char macjunk[8], *lastslash, *dirpart, *filepart; + +setvar(macro, value, YES); +if(value == CHNULL) + dirpart = filepart = CHNULL; +else + { + lastslash = CHNULL; + for(s = value; *s; ++s) + if(*s == '/') + lastslash = s; + if(lastslash) + { + dirpart = copys(value); + filepart = dirpart + (lastslash-value); + filepart[-1] = '\0'; + } + else + { + dirpart = ""; + filepart = value; + } + } +setvar(concat(macro, "D", macjunk), dirpart, YES); +setvar(concat(macro, "F", macjunk), filepart, YES); +} + + +int +eqsign(char *a) /*look for arguments with equal signs but not colons */ +{ +char *s, *t; +char c; + +while(*a == ' ') ++a; +for(s=a ; *s!='\0' && *s!=':' ; ++s) + if(*s == '=') + { + for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ; ++t ); + c = *t; + *t = '\0'; + + for(++s; *s==' ' || *s=='\t' ; ++s); + setvar(a, copys(s), NO); + *t = c; + return YES; + } + +return NO; +} + +struct varblock * +varptr(char *v) +{ +struct varblock *vp; + +/* for compatibility, $(TGS) = $^ */ +if(equal(v, "TGS") ) + v = "^"; +for(vp = firstvar; vp ; vp = vp->nxtvarblock) + if(equal(v , vp->varname)) + return vp; + +vp = ALLOC(varblock); +vp->nxtvarblock = firstvar; +firstvar = vp; +vp->varname = copys(v); +vp->varval = 0; +return vp; +} + +int +dynmacro(char *line) +{ +char *s; +char endc, *endp; +if(!isalpha(line[0])) + return NO; +for(s=line+1 ; *s && (isalpha(*s) | isdigit(*s)) ; ++s) + ; +endp = s; +while( isspace(*s) ) + ++s; +if(s[0]!=':' || s[1]!='=') + return NO; + +endc = *endp; +*endp = '\0'; +setvar(line, copys(s+2), YES); +*endp = endc; + +return YES; +} + + +void +fatal1(char *s, char *t) +{ +char buf[100]; +sprintf(buf, s, t); +fatal(buf); +} + + +void +fatal(char *s) +{ +fflush(stdout); +if(s) + fprintf(stderr, "Make: %s. Stop.\n", s); +else + fprintf(stderr, "\nStop.\n"); + +waitstack(0); +exit(1); +} + + + +/* appends to the chain for $? and $^ */ +chainp +appendq(chainp head, char *tail) +{ +chainp p, q; + +p = ALLOC(chain); +p->datap = tail; + +if(head) + { + for(q = head ; q->nextp ; q = q->nextp) + ; + q->nextp = p; + return head; + } +else + return p; +} + + + + + +/* builds the value for $? and $^ */ +char * +mkqlist(chainp p, char *qbuf) +{ +char *qbufp, *s; + +if(p == NULL) + return ""; + +qbufp = qbuf; + +for( ; p ; p = p->nextp) + { + s = p->datap; + if(qbufp+strlen(s) > &qbuf[QBUFMAX-3]) + { + fprintf(stderr, "$? list too long\n"); + break; + } + while (*s) + *qbufp++ = *s++; + *qbufp++ = ' '; + } +*--qbufp = '\0'; +return qbuf; +} + +wildp +iswild(char *name) +{ +char *s; +wildp p; + +for(s=name; *s; ++s) + if(*s == '%') + { + p = ALLOC(wild); + *s = '\0'; + p->left = copys(name); + *s = '%'; + p->right = copys(s+1); + p->llen = strlen(p->left); + p->rlen = strlen(p->right); + p->totlen = p->llen + p->rlen; + return p; + } +return NULL; +} + + +char * +wildmatch(wildp p, char *name, int len) +{ +char *stem; +char *s; +char c; + +if(len < p->totlen || + strncmp(name, p->left, p->llen) || + strncmp(s = name+len-p->rlen, p->right, p->rlen) ) + return CHNULL; + +/*TEMP fprintf(stderr, "wildmatch(%s)=%s%%%s)\n", name,p->left,p->right); */ +c = *s; +*s = '\0'; +stem = copys(name + p->llen); +*s = c; +return stem; +} + + + +/* substitute stem for any % marks */ +char * +wildsub(char *pat, char *stem) +{ +static char temp[100]; +char *s, *t; + +s = temp; +for(; *pat; ++pat) + if(*pat == '%') + for(t = stem ; *t; ) + *s++ = *t++; + else + *s++ = *pat; +*s = '\0'; +return temp; +} diff --git a/sys/src/ape/cmd/make/mkfile b/sys/src/ape/cmd/make/mkfile new file mode 100755 index 000000000..b7669386c --- /dev/null +++ b/sys/src/ape/cmd/make/mkfile @@ -0,0 +1,26 @@ +APE=/sys/src/ape +<$APE/config + +TARG=make +OFILES=ident.$O\ + main.$O\ + doname.$O\ + dosys.$O\ + gram.$O\ + misc.$O\ + files.$O\ + +HFILES=defs.h +YFILES=gram.y + +BIN=$APEBIN +</sys/src/cmd/mkone + +CFLAGS=-c -DSHELLCOM'="/bin/sh"' +YFLAGS=-S + +gram.c: y.tab.c + mv $prereq $target + +nuke clean:V: + rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG gram.c |