BSD 4 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Mon, 8 Sep 1980 11:03:27 +0000 (03:03 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Mon, 8 Sep 1980 11:03:27 +0000 (03:03 -0800)
Work on file usr/src/cmd/make/defs
Work on file usr/src/cmd/make/doname.c
Work on file usr/src/cmd/make/dosys.c
Work on file usr/src/cmd/make/gcos.c
Work on file usr/src/cmd/make/gram.y
Work on file usr/src/cmd/make/main.c
Work on file usr/src/cmd/make/misc.c

Synthesized-from: CSRG//cd1/4.0

usr/src/cmd/make/defs [new file with mode: 0644]
usr/src/cmd/make/doname.c [new file with mode: 0644]
usr/src/cmd/make/dosys.c [new file with mode: 0644]
usr/src/cmd/make/gcos.c [new file with mode: 0644]
usr/src/cmd/make/gram.y [new file with mode: 0644]
usr/src/cmd/make/main.c [new file with mode: 0644]
usr/src/cmd/make/misc.c [new file with mode: 0644]

diff --git a/usr/src/cmd/make/defs b/usr/src/cmd/make/defs
new file mode 100644 (file)
index 0000000..4d78617
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <ctype.h>
+
+#define SHELLCOM "/bin/sh"
+
+typedef long int TIMETYPE;
+
+#ifdef unix
+/*  to install metering, add a statement like */
+#define METERFILE "/usr/sif/make/Meter"
+/* to turn metering on, set external variable meteron to 1 */
+#endif
+
+/* define FSTATIC to be static on systems with C compilers
+   supporting file-static; otherwise define it to be null
+*/
+#define FSTATIC static
+
+#define NO 0
+#define YES 1
+
+#define unequal strcmp
+#define HASHSIZE 1021
+#define NLEFTS 512
+#define NCHARS 500
+#define NINTS  250
+#define INMAX 2500
+#define OUTMAX 3500
+#define QBUFMAX 2500
+#define MAXDIR 10
+
+#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))
+
+extern int sigivalue;
+extern int sigqvalue;
+extern int waitpid;
+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 ndocoms;
+extern int ignerr;
+extern int okdel;
+extern int inarglist;
+extern char *prompt;
+extern int nopdir;
+extern char junkname[ ];
+
+
+
+struct nameblock
+       {
+       struct nameblock *nxtnameblock;
+       char *namep;
+       struct lineblock *linep;
+       int done:3;
+       int septype:3;
+       TIMETYPE modtime;
+       };
+
+extern struct nameblock *mainname ;
+extern struct nameblock *firstname;
+
+struct lineblock
+       {
+       struct lineblock *nxtlineblock;
+       struct depblock *depp;
+       struct shblock *shp;
+       };
+extern struct lineblock *sufflist;
+
+struct depblock
+       {
+       struct depblock *nxtdepblock;
+       struct nameblock *depname;
+       };
+
+struct shblock
+       {
+       struct shblock *nxtshblock;
+       char *shbp;
+       };
+
+struct varblock
+       {
+       struct varblock *nxtvarblock;
+       char *varname;
+       char *varval;
+       int noreset:1;
+       int used:1;
+       };
+extern struct varblock *firstvar;
+
+struct pattern
+       {
+       struct pattern *nxtpattern;
+       char *patval;
+       };
+extern struct pattern *firstpat;
+
+struct opendir
+       {
+       struct opendir *nxtopendir;
+       FILE * dirfc;
+       char *dirn;
+       };
+extern struct opendir *firstod;
+
+
+struct chain
+       {
+       struct chain *nextp;
+       char *datap;
+       };
+
+char *copys(), *concat(), *subst();
+int *ckalloc();
+struct nameblock *srchname(), *makename();
+TIMETYPE exists();
diff --git a/usr/src/cmd/make/doname.c b/usr/src/cmd/make/doname.c
new file mode 100644 (file)
index 0000000..407b57a
--- /dev/null
@@ -0,0 +1,299 @@
+#include "defs"
+
+/*  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
+*/
+
+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("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("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;
+                               }
+                       }
+               }
+       }
+
+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);
+}
+\f
+docom(q)
+struct shblock *q;
+{
+char *s;
+struct varblock *varptr();
+int ign, nopr;
+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);
+       }
+
+else for( ; q ; q = q->nxtshblock )
+       {
+       subst(q->shbp,string);
+
+       ign = ignerr;
+       nopr = NO;
+       for(s = string ; *s=='-' || *s=='@' ; ++s)
+               if(*s == '-')  ign = YES;
+               else nopr = YES;
+
+       if( docom1(s, ign, nopr) && !ign)
+               if(keepgoing)
+                       return(YES);
+               else    fatal( (char *) NULL);
+       }
+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>>8 )
+               printf("*** Error code %d", status>>8 );
+       else    printf("*** Termination code %d", status );
+
+       if(nohalt) printf(" (ignored)\n");
+       else    printf("\n");
+       fflush(stdout);
+       }
+
+return(status);
+}
+\f
+
+/*
+   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;
+
+       case '*':
+       case '?':
+       case '[':
+               if( p = srchdir(s1 , YES, q->nxtdepblock) )
+                       {
+                       q->nxtdepblock = p;
+                       q->depname = 0;
+                       }
+               return;
+       }
+}
diff --git a/usr/src/cmd/make/dosys.c b/usr/src/cmd/make/dosys.c
new file mode 100644 (file)
index 0000000..8c8c164
--- /dev/null
@@ -0,0 +1,184 @@
+#include "defs"
+#include <signal.h>
+
+dosys(comstring,nohalt)
+register char *comstring;
+int nohalt;
+{
+register int status;
+
+if(metas(comstring))
+       status = doshell(comstring,nohalt);
+else   status = doexec(comstring);
+
+return(status);
+}
+
+
+
+metas(s)   /* Are there are any  Shell meta-characters? */
+register char *s;
+{
+register char c;
+
+while( (funny[c = *s++] & META) == 0 )
+       ;
+return( c );
+}
+\f
+doshell(comstring,nohalt)
+char *comstring;
+int nohalt;
+{
+#ifdef SHELLENV
+char *getenv(), *rindex();
+char *shellcom = getenv("SHELL");
+char *shellstr;
+#endif
+if((waitpid = vfork()) == 0)
+       {
+       enbint(SIG_DFL);
+       doclose();
+
+#ifdef SHELLENV
+       if (shellcom == 0) shellcom = SHELLCOM;
+       shellstr = rindex(shellcom, '/') + 1;
+       execl(shellcom, shellstr, (nohalt ? "-c" : "-ce"), comstring, 0);
+#else
+       execl(SHELLCOM, "sh", (nohalt ? "-c" : "-ce"), comstring, 0);
+#endif
+       fatal("Couldn't load Shell");
+       }
+
+return( await() );
+}
+
+
+
+
+int intrupt();
+
+await()
+{
+int status;
+register int pid;
+
+enbint(SIG_IGN);
+while( (pid = wait(&status)) != waitpid)
+       if(pid == -1)
+               fatal("bad wait code");
+waitpid = 0;
+enbint(intrupt);
+return(status);
+}
+
+
+
+
+
+
+doclose()      /* Close open directory files before exec'ing */
+{
+register struct opendir *od;
+
+for (od = firstod; od; od = od->nxtopendir)
+       if (od->dirfc != NULL)
+               /* fclose(od->dirfc); */
+               close(od->dirfc->_file);
+}
+\f
+
+
+
+
+doexec(str)
+register char *str;
+{
+register char *t;
+char *argv[200];
+register char **p;
+
+while( *str==' ' || *str=='\t' )
+       ++str;
+if( *str == '\0' )
+       return(-1);     /* no command */
+
+p = argv;
+for(t = str ; *t ; )
+       {
+       *p++ = t;
+       while(*t!=' ' && *t!='\t' && *t!='\0')
+               ++t;
+       if(*t)
+               for( *t++ = '\0' ; *t==' ' || *t=='\t'  ; ++t)
+                       ;
+       }
+
+*p = NULL;
+
+if((waitpid = vfork()) == 0)
+       {
+       enbint(SIG_DFL);
+       doclose();
+       enbint(intrupt);
+       execvp(str, argv);
+       fatal1("Cannot load %s",str);
+       }
+
+return( await() );
+}
+\f
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+
+
+touch(force, name)
+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, 2)) < 0)
+       goto bad;
+
+if( read(fd, junk, 1) < 1)
+       {
+       close(fd);
+       goto bad;
+       }
+lseek(fd, 0L, 0);
+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/usr/src/cmd/make/gcos.c b/usr/src/cmd/make/gcos.c
new file mode 100644 (file)
index 0000000..1c19413
--- /dev/null
@@ -0,0 +1,330 @@
+/* GCOS DEPENDENT PROCEDURES */
+
+
+/* DEFAULT RULES FOR GCOS */
+
+char *builtin[]
+       {
+       ".SUFFIXES : .d .c .y .lib",
+       ".d.c:",
+       "\t./dtgen $<",
+       ".y.c:",
+       "\t./yacc $<",
+       "\tcopy y.tab.c; /$@",
+       ".y.lib:",
+       "\t./yacc $<",
+       "\t./cc y.tab.c r=$@",
+       ".c.lib:",
+       "\t./cc $< r=$@",
+       0 };
+\f
+# define MAXCSIZE 500
+# define YZERO 60
+
+int gtcalled 0;
+
+/* all kinds of static declarations that must be used.. */
+
+static double day { 64*1000*60*60*24 };  /* length of day in clock ticks */
+
+struct { int lhs:18, rhs:18; };
+struct catb {
+       int words[6],
+       name1, name2,
+       passw1, passw2,
+       word10, word11,
+       datcreat, datmod,  datused,
+       stuff[6],
+       jjjj:18, tused:18;
+       };
+struct { int :3, slot:18; };  /* slot where time from cat. block fits */
+
+struct catdesc {
+       int cat1, cat2, cpass1, cpass2,
+           file1, file2, filep1, filep2,
+           endmark; };
+
+extern int _q_reg, _a_reg;
+
+
+# define A10(x,y) 10*x + y
+
+/*     interpret the mm/dd/yy format */
+
+struct d9 { int        :5, m1:4, :5, m2:4, :9,
+               :5, d1:4, :5, d2:4, :9,
+               :5, y1:4, :5, y2:4  ;};
+
+struct d6 { int        :2, m61:4, :2, m62:4,
+               :2, d61:4, :2, d62:4,
+               :2, y61:4, :2, y62:4; };
+
+static day6( d6word ){ /* return the day number of a word in bci format */
+       int m, y, d;
+
+       y = A10( d6word.y61, d6word.y62 );
+       m = A10( d6word.m61, d6word.m62 );
+       d = A10( d6word.d61, d6word.d62 );
+
+       return( d + 31*( m + 12*(y-YZERO) ) );
+       }
+
+static day9( p ) register int *p; {
+
+       int m, y, d;
+
+       y = A10( p->y1, p->y2 );
+       m = A10( p->m1, p->m2 );
+       d = A10( p->d1, p->d2 );
+
+       return( d + 31*( m + 12*(y-YZERO) ) );
+       }
+
+
+static int dfold( dayno, timeno ){
+       int kk;
+       kk = ( day*dayno + timeno) / 32768.;
+       }
+
+int prestime(){
+       int date[2];
+       drldrl( 021, date );
+       return( dfold( day9(date), _q_reg ) );
+       }
+
+
+
+# define DODRL ar[0] = status; ar[1] = &b.cat1; drldrl(30,sp1,sp2); p=ar[0]<<18;
+
+static struct { int fn1, fn2;  int ftm; } fbb[MAXCSIZE];
+static int catsiz;
+
+getcat() {
+
+       register i, *p, j;
+       int asname[4];
+       struct catdesc b;
+       int sp1, sp2, temp;
+       int ar[2], status[2];
+       int filbuf[380];
+
+       gtcalled = 1;
+
+       sp1 = ar;
+       sp1 =>> 18;
+       sp2 = filbuf;
+       sp2 =>>18;
+       sp2.lhs = 19;
+
+       b.cat1 = b.cat2 = b.file1 = -1;
+       b.cpass1 = b.cpass2 = 0202020202020;
+
+       DODRL
+       sp2.lhs++;
+       for( i=0; p!=0 && i<MAXCSIZE; ++i ){
+
+               fbb[i].fn1 = b.file1 = p->name1;
+               fbb[i].fn2 = b.file2 = p->name2;
+               b.filep1 = p->passw1;
+               b.filep2 = p->passw2;
+               b.endmark = -1;
+               temp = 0;
+               temp.slot = p->tused;
+               fbb[i].ftm = dfold( day6(p->datmod), temp );
+               DODRL
+               }
+       catsiz = i;
+       }
+
+ exists( cp ) char *cp; {
+       char *s, name[13];
+       int i, *p, bcd[2];
+
+/*
+   cheat about names with slashes -- try opening;
+   if it is openable, it exists, and assume it was made
+   at t=1 (long time ago); otherwise, assume it
+   does not exist
+*/
+
+for(s=cp ; *s ; ++s)
+       if(*s == '/')
+               if(i = copen(cp,'r') < 0)
+                       return(0);
+               else    {
+                       cclose(i);
+                       return(1);
+                       }
+
+if(gtcalled == 0)  getcat();
+
+       p = name;
+       for( i=0; *cp; ++i ) name[i] = *cp++;
+       while( i<12 ) name[i++] = ' ';
+       f9to6( *p, bcd[0], 12 );
+       for ( i=0; i<catsiz; ++i ){
+               if( fbb[i].fn1 == bcd[0] && fbb[i].fn2 == bcd[1] )
+                       return( fbb[i].ftm );
+               }
+       return( 0 );
+       }
+
+\f
+#include "defs"
+
+static char n13[13];
+static char *n13end &n13[12];
+
+
+
+struct depblock *srchdir(pat, mkchain, nextdbl)
+
+char *pat; /* pattern to be matched in directory */
+int mkchain;  /* nonzero if results to be remembered */
+struct depblock *nextdbl;  /* final value for chain */
+{
+int dirf;
+int i, nread;
+char *dirname, *dirpref, *endir, *filepat, *p, temp[100];
+char fullname[100], *p1, *p2, *copys();
+struct nameblock *q;
+struct depblock *thisdbl;
+struct pattern *patp;
+int *intp1, *intp2;
+
+if(gtcalled == 0)  getcat();
+thisdbl=0;
+
+if(mkchain == 0)
+       for(patp=firstpat ; patp!=0 ; patp = patp->nxtpattern)
+               if(! unequal(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   {
+fatal("File name has an embedded slash");
+       dirname = pat;
+       *endir = '\0';
+       dirpref = concat(dirname, "/", temp);
+       filepat = endir+1;
+       }
+
+for(i=0;i<catsiz;++i)
+       {
+       intp1 = &fbb[i].fn1;
+       intp2 = n13;
+       f6to9(*intp1, *intp2, 12);
+       for(p1=n13; p1<n13end && *p1!=' ' ; ++p1) 
+               if('A'<=*p1 && *p1<='Z') *p1 =+ ('a'-'A');
+               *p1 = '\0';
+
+       if( amatch(n13,filepat) )
+               {
+               concat(dirpref,n13,fullname);
+               if( (q=srchname(fullname)) ==0)
+                       q = makename(copys(fullname));
+               if(mkchain)
+                       {
+                       thisdbl = ALLOC(depblock);
+                       thisdbl->nextp = nextdbl;
+                       thisdbl->depname = q;
+                       nextdbl = thisdbl;
+                       }
+               }
+       }
+
+if(endir != 0)  *endir = '/';
+
+return(thisdbl);
+}
+\f
+/* stolen from glob through find */
+
+amatch(s, p)
+char *s, *p;
+{
+       register 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);
+}
+
+umatch(s, p)
+char *s, *p;
+{
+       if(*p==0) return(1);
+       while(*s)
+               if (amatch(s++,p)) return(1);
+       return(0);
+}
+\f
+
+
+dosys(comstring,nohalt)
+char *comstring;
+int nohalt;
+{
+char *p;
+
+for(p=comstring ; *p!='\0' ; ++p);
+if( p-comstring > 80)
+       fatal("Command string longer than 80 characters");
+
+system(comstring);
+
+return(0);
+}
+
+
+touch(s)
+char *s;
+{
+fprintf(stderr, "touch not yet implemented on GCOS\n");
+cexit(2);
+}
diff --git a/usr/src/cmd/make/gram.y b/usr/src/cmd/make/gram.y
new file mode 100644 (file)
index 0000000..60fda2c
--- /dev/null
@@ -0,0 +1,306 @@
+%{#include "defs"
+%}
+
+%term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER
+%union
+       {
+       struct shblock *yshblock;
+       struct depblock *ydepblock;
+       struct nameblock *ynameblock;
+       }
+
+%type <yshblock> SHELLINE, shlist, shellist
+%type <ynameblock> NAME, namelist
+%type <ydepblock> deplist, dlist
+
+
+%%
+
+%{
+struct depblock *pp;
+FSTATIC struct shblock *prevshp;
+
+FSTATIC struct nameblock *lefts[NLEFTS];
+struct nameblock *leftp;
+FSTATIC int nlefts;
+
+struct lineblock *lp, *lpp;
+FSTATIC struct depblock *prevdep;
+FSTATIC int sepc;
+%}
+
+
+file:
+       | file comline
+       ;
+
+comline:  START
+       | MACRODEF
+       | START namelist deplist shellist = {
+           while( --nlefts >= 0)
+               {
+               leftp = lefts[nlefts];
+               if(leftp->septype == 0)
+                       leftp->septype = sepc;
+               else if(leftp->septype != sepc)
+                       fprintf(stderr, "Inconsistent rules lines for `%s'\n",
+                               leftp->namep);
+               else if(sepc==ALLDEPS && *(leftp->namep)!='.' && $4!=0)
+                       {
+                       for(lp=leftp->linep; lp->nxtlineblock!=0; 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(! unequal(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[10];
+               sprintf(junk, "%d", yylineno);
+               fatal1("Must be a separator on rules line %s", junk);
+               }
+       | dlist
+       ;
+
+dlist:  sepchar        = { prevdep = 0;  $$ = 0; }
+       | dlist NAME    = {
+                         pp = ALLOC(depblock);
+                         pp->nxtdepblock = NULL;
+                         pp->depname = $2;
+                         if(prevdep == 0) $$ = pp;
+                         else  prevdep->nxtdepblock = pp;
+                         prevdep = pp;
+                         }
+       ;
+
+sepchar:  COLON        = { sepc = ALLDEPS; }
+       | DOUBLECOLON   = { sepc = SOMEDEPS; }
+       ;
+
+shellist:      = {$$ = 0; }
+       | shlist = { $$ = $1; }
+       ;
+
+shlist:        SHELLINE   = { $$ = $1;  prevshp = $1; }
+       | shlist SHELLINE = { $$ = $1;
+                       prevshp->nxtshblock = $2;
+                       prevshp = $2;
+                       }
+       ;
+
+%%
+\f
+char *zznextc; /* zero if need another line; otherwise points to next char */
+int yylineno;
+extern FILE * fin;
+
+yylex()
+{
+register char *p;
+register char *q;
+char word[INMAX];
+
+if(zznextc == 0)
+       return( nextlin() );
+
+while( isspace(*zznextc) )
+       ++zznextc;
+
+if(*zznextc == '\0')
+       return( nextlin() );
+
+if(*zznextc == ':')
+       {
+       if(*++zznextc == ':')
+               {
+               ++zznextc;
+               return(DOUBLECOLON);
+               }
+       else    return(COLON);
+       }
+
+if(*zznextc == '>')
+       {
+       ++zznextc;
+       return(GREATER);
+       }
+
+if(*zznextc == ';')
+       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   {
+       fprintf(stderr,"Bad character %c (octal %o), line %d",
+               *zznextc,*zznextc,yylineno);
+       fatal( (char *) NULL );
+       }
+return(0);     /* never executed */
+}
+
+
+
+
+
+retsh(q)
+char *q;
+{
+register char *p;
+struct shblock *sp;
+char *copys();
+
+for(p=q+1 ; *p==' '||*p=='\t' ; ++p)  ;
+
+sp = ALLOC(shblock);
+sp->nxtshblock = NULL;
+sp->shbp = (fin == NULL ? p : copys(p) );
+yylval.yshblock = sp;
+zznextc = 0;
+return(SHELLINE);
+}
+\f
+nextlin()
+{
+static char yytext[INMAX];
+static char *yytextl   = yytext+INMAX;
+char *text, templin[INMAX];
+register char c;
+register 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)
+                                       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';
+                               return(0);
+                       }
+
+       fatal("line too long");
+       }
+
+endloop:
+
+       if((c = text[0]) == '\t')
+               return( retsh(text) );
+       
+       if(isalpha(c) || isdigit(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';
+
+subst(yytext, templin);                /* Substitute for macros on dependency lines */
+
+if(lastch)
+       {
+       for(t = templin ; *t ; ++t)
+               ;
+       *t = lastch;
+       while( *++t = *++lastchp ) ;
+       }
+
+p = templin;
+t = yytext;
+while( *t++ = *p++ )
+       ;
+
+for(p = zznextc = text ; *p ; ++p )
+       if(*p!=' ' && *p!='\t')
+               return(START);
+goto again;
+}
diff --git a/usr/src/cmd/make/main.c b/usr/src/cmd/make/main.c
new file mode 100644 (file)
index 0000000..fa6ceff
--- /dev/null
@@ -0,0 +1,370 @@
+# include "defs"
+/*
+command make to update programs.
+Flags: 'd'  print out debugging comments
+       'p'  print out a version of the input graph
+       's'  silent mode--don't print out commands
+       'f'  the next argument is the name of the description file;
+            "makefile" is the default
+       'i'  ignore error codes from the shell
+       'S'  stop after any command fails (normally do parallel work)
+       'n'   don't issue, just print, commands
+       't'   touch (update time of) files but don't issue command
+       'q'   don't do anything, but check if object is up to date;
+             returns exit code 0 if up to date, -1 if not
+*/
+
+struct nameblock *mainname     = NULL;
+struct nameblock *firstname    = NULL;
+struct lineblock *sufflist     = NULL;
+struct varblock *firstvar      = NULL;
+struct pattern *firstpat       = NULL;
+struct opendir *firstod                = NULL;
+
+#include <signal.h>
+int sigivalue  = 0;
+int sigqvalue  = 0;
+int waitpid    = 0;
+
+int dbgflag    = NO;
+int prtrflag   = NO;
+int silflag    = NO;
+int noexflag   = NO;
+int keepgoing  = NO;
+int noruleflag = NO;
+int touchflag  = NO;
+int questflag  = NO;
+int ndocoms    = NO;
+int ignerr     = NO;    /* default is to stop on error */
+int okdel      = YES;
+int inarglist;
+#ifdef pwb
+char *prompt   = ">";  /* other systems -- pick what you want */
+#else
+char *prompt   = "";   /* other systems -- pick what you want */
+#endif
+int nopdir     = 0;
+char junkname[20];
+char funny[128];
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+register struct nameblock *p;
+int i, j;
+int descset, nfargs;
+TIMETYPE tjunk;
+char c, *s;
+static char onechar[2] = "X";
+#ifdef unix
+int intrupt();
+
+
+
+#endif
+
+#ifdef METERFILE
+meter(METERFILE);
+#endif
+
+descset = 0;
+
+funny['\0'] = (META | TERMINAL);
+for(s = "=|^();&<>*?[]:$`'\"\\\n" ; *s ; ++s)
+       funny[*s] |= META;
+for(s = "\n\t :;&>|" ; *s ; ++s)
+       funny[*s] |= TERMINAL;
+
+
+inarglist = 1;
+for(i=1; i<argc; ++i)
+       if(argv[i]!=0 && argv[i][0]!='-' && eqsign(argv[i]))
+               argv[i] = 0;
+
+setvar("$","$");
+inarglist = 0;
+
+for(i=1; i<argc; ++i)
+    if(argv[i]!=0 && argv[i][0]=='-')
+       {
+       for(j=1 ; (c=argv[i][j])!='\0' ; ++j)  switch(c)
+               {
+               case 'd':
+                       dbgflag = YES;
+                       break;
+
+               case 'p':
+                       prtrflag = YES;
+                       break;
+
+               case 's':
+                       silflag = YES;
+                       break;
+
+               case 'i':
+                       ignerr = YES;
+                       break;
+
+               case 'S':
+                       keepgoing = NO;
+                       break;
+
+               case 'k':
+                       keepgoing = YES;
+                       break;
+
+               case 'n':
+                       noexflag = YES;
+                       break;
+
+               case 'r':
+                       noruleflag = YES;
+                       break;
+
+               case 't':
+                       touchflag = YES;
+                       break;
+
+               case 'q':
+                       questflag = YES;
+                       break;
+
+               case 'f':
+                       if(i >= argc-1)
+                         fatal("No description argument after -f flag");
+                       if( rddescf(argv[i+1]) )
+                               fatal1("Cannot open %s", argv[i+1]);
+                       argv[i+1] = 0;
+                       ++descset;
+                       break;
+
+               default:
+                       onechar[0] = c; /* to make lint happy */
+                       fatal1("Unknown flag argument %s", onechar);
+               }
+
+       argv[i] = 0;
+       }
+
+if( !descset )
+#ifdef unix
+       if( rddescf("makefile") )  rddescf("Makefile");
+#endif
+#ifdef gcos
+       rddescf("makefile");
+#endif
+
+if(prtrflag) printdesc(NO);
+
+if( srchname(".IGNORE") ) ++ignerr;
+if( srchname(".SILENT") ) silflag = 1;
+if(p=srchname(".SUFFIXES")) sufflist = p->linep;
+if( !sufflist ) fprintf(stderr,"No suffix list.\n");
+
+#ifdef unix
+sigivalue = (int) signal(SIGINT, SIG_IGN) & 01;
+sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01;
+enbint(intrupt);
+#endif
+
+nfargs = 0;
+
+for(i=1; i<argc; ++i)
+       if((s=argv[i]) != 0)
+               {
+               if((p=srchname(s)) == 0)
+                       {
+                       p = makename(s);
+                       }
+               ++nfargs;
+               doname(p, 0, &tjunk);
+               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);
+               if(dbgflag) printdesc(YES);
+               }
+
+exit(0);
+}
+
+
+
+#ifdef unix
+intrupt()
+{
+struct varblock *varptr();
+char *p;
+TIMETYPE exists();
+
+if(okdel && !noexflag && !touchflag &&
+       (p = varptr("@")->varval) && exists(p)>0 && !isprecious(p) )
+               {
+               fprintf(stderr, "\n***  %s removed.", p);
+               unlink(p);
+               }
+
+if(junkname[0])
+       unlink(junkname);
+fprintf(stderr, "\n");
+exit(2);
+}
+
+
+
+
+isprecious(p)
+char *p;
+{
+register struct lineblock *lp;
+register struct depblock *dp;
+register struct nameblock *np;
+
+if(np = srchname(".PRECIOUS"))
+       for(lp = np->linep ; lp ; lp = lp->nxtlineblock)
+               for(dp = lp->depp ; dp ; dp = dp->nxtdepblock)
+                       if(! unequal(p, dp->depname->namep))
+                               return(YES);
+
+return(NO);
+}
+
+
+enbint(k)
+int (*k)();
+{
+if(sigivalue == 0)
+       signal(SIGINT,k);
+if(sigqvalue == 0)
+       signal(SIGQUIT,k);
+}
+#endif
+\f
+extern char *builtin[];
+
+char **linesptr        = builtin;
+
+FILE * fin;
+int firstrd    = 0;
+
+
+rddescf(descfile)
+char *descfile;
+{
+FILE * k;
+
+/* read and parse description */
+
+if( !firstrd++ )
+       {
+       if( !noruleflag )
+               rdd1( (FILE *) NULL);
+
+#ifdef pwb
+               {
+               char *nlog, s[100];
+               nlog = logdir();
+               if ( (k=fopen( concat(nlog,"/makecomm",s), "r")) != NULL)
+                       rdd1(k);
+               else if ( (k=fopen( concat(nlog,"/Makecomm",s), "r")) != NULL)
+                       rdd1(k);
+       
+               if ( (k=fopen("makecomm", "r")) != NULL)
+                       rdd1(k);
+               else if ( (k=fopen("Makecomm", "r")) != NULL)
+                       rdd1(k);
+               }
+#endif
+
+       }
+if(! unequal(descfile, "-"))
+       return( rdd1(stdin) );
+
+if( (k = fopen(descfile,"r")) != NULL)
+       return( rdd1(k) );
+
+return(1);
+}
+
+
+
+
+rdd1(k)
+FILE * k;
+{
+extern int yylineno;
+extern char *zznextc;
+
+fin = k;
+yylineno = 0;
+zznextc = 0;
+
+if( yyparse() )
+       fatal("Description file error");
+
+if(fin != NULL)
+       fclose(fin);
+
+return(0);
+}
+\f
+printdesc(prntflag)
+int prntflag;
+{
+struct nameblock *p;
+struct depblock *dp;
+struct varblock *vp;
+struct opendir *od;
+struct shblock *sp;
+struct lineblock *lp;
+
+#ifdef unix
+if(prntflag)
+       {
+       printf("Open directories:\n");
+       for (od = firstod; od; od = od->nxtopendir)
+               printf("\t%d: %s\n", fileno(od->dirfc), od->dirn);
+       }
+#endif
+
+if(firstvar != 0) printf("Macros:\n");
+for(vp = firstvar; vp ; vp = vp->nxtvarblock)
+       printf("\t%s = %s\n" , vp->varname , vp->varval);
+
+for(p = firstname; p; p = p->nxtnameblock)
+       {
+       printf("\n\n%s",p->namep);
+       if(p->linep != 0) printf(":");
+       if(prntflag) printf("  done=%d",p->done);
+       if(p==mainname) printf("  (MAIN NAME)");
+       for(lp = p->linep ; lp ; lp = lp->nxtlineblock)
+               {
+               if( dp = lp->depp )
+                       {
+                       printf("\n depends on:");
+                       for(; dp ; dp = dp->nxtdepblock)
+                               if(dp->depname != 0)
+                                       printf(" %s ", dp->depname->namep);
+                       }
+       
+               if(sp = lp->shp)
+                       {
+                       printf("\n commands:\n");
+                       for( ; sp!=0 ; sp = sp->nxtshblock)
+                               printf("\t%s\n", sp->shbp);
+                       }
+               }
+       }
+printf("\n");
+fflush(stdout);
+}
diff --git a/usr/src/cmd/make/misc.c b/usr/src/cmd/make/misc.c
new file mode 100644 (file)
index 0000000..9a18441
--- /dev/null
@@ -0,0 +1,339 @@
+#include "defs"
+
+FSTATIC struct nameblock *hashtab[HASHSIZE];
+FSTATIC int nhashed    = 0;
+
+
+/* simple linear hash.  hash function is sum of
+   characters mod hash table size.
+*/
+hashloc(s)
+char *s;
+{
+register int i;
+register int hashval;
+register char *t;
+
+hashval = 0;
+
+for(t=s; *t!='\0' ; ++t)
+       hashval += *t;
+
+hashval %= HASHSIZE;
+
+for(i=hashval;
+       hashtab[i]!=0 && unequal(s,hashtab[i]->namep);
+       i = (i+1)%HASHSIZE ) ;
+
+return(i);
+}
+
+
+struct nameblock *srchname(s)
+char *s;
+{
+return( hashtab[hashloc(s)] );
+}
+
+
+
+struct nameblock *makename(s)
+char *s;
+{
+/* make a fresh copy of the string s */
+
+char *copys();
+register struct nameblock *p;
+
+if(nhashed++ > HASHSIZE-3)
+       fatal("Hash table overflow");
+
+p = ALLOC(nameblock);
+p->nxtnameblock = firstname;
+p->namep = copys(s);
+p->linep = 0;
+p->done = 0;
+p->septype = 0;
+p->modtime = 0;
+
+firstname = p;
+if(mainname == NULL)
+       if(s[0]!='.' || hasslash(s) )
+               mainname = p;
+
+hashtab[hashloc(s)] = p;
+
+return(p);
+}
+
+
+
+hasslash(s)
+char *s;
+{
+for( ; *s ; ++s)
+       if(*s == '/')
+               return(YES);
+return(NO);
+}
+\f
+
+
+char *copys(s)
+register char *s;
+{
+char *calloc();
+register char *t, *t0;
+
+if( (t = t0 = calloc( strlen(s)+1 , sizeof(char)) ) == NULL)
+       fatal("out of memory");
+while(*t++ = *s++)
+       ;
+return(t0);
+}
+
+
+
+char *concat(a,b,c)   /* c = concatenation of a and b */
+register char *a,*b;
+char *c;
+{
+register char *t;
+t = c;
+
+while(*t = *a++) t++;
+while(*t++ = *b++);
+return(c);
+}
+
+
+
+suffix(a,b,p)  /* is b the suffix of a?  if so, set p = prefix */
+register char *a,*b,*p;
+{
+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(n)
+register int n;
+{
+register int *p;
+
+if( p = (int *) calloc(1,n) )
+       return(p);
+
+fatal("out of memory");
+/* NOTREACHED */
+}
+\f
+/* copy string a into b, substituting for arguments */
+char *subst(a,b)
+register char *a,*b;
+{
+static depth   = 0;
+register char *s;
+char vname[100];
+struct varblock *varptr(), *vbp;
+char closer;
+
+if(++depth > 100)
+       fatal("infinitely recursive macro?");
+if(a!=0)  while(*a)
+       {
+       if(*a != '$') *b++ = *a++;
+       else if(*++a=='\0' || *a=='$')
+               *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);
+}
+
+
+setvar(v,s)
+char *v, *s;
+{
+struct varblock *varptr(), *p;
+
+p = varptr(v);
+if(p->noreset == 0)
+       {
+       p->varval = s;
+       p->noreset = inarglist;
+       if(p->used && unequal(v,"@") && unequal(v,"*")
+           && unequal(v,"<") && unequal(v,"?") )
+               fprintf(stderr, "Warning: %s changed after being used\n",v);
+       }
+}
+
+
+eqsign(a)   /*look for arguments with equal signs but not colons */
+char *a;
+{
+register char *s, *t;
+
+while(*a == ' ') ++a;
+for(s=a  ;   *s!='\0' && *s!=':'  ; ++s)
+       if(*s == '=')
+               {
+               for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ;  ++t );
+               *t = '\0';
+
+               for(++s; *s==' ' || *s=='\t' ; ++s);
+               setvar(a, copys(s));
+               return(YES);
+               }
+
+return(NO);
+}
+
+
+struct varblock *varptr(v)
+char *v;
+{
+register struct varblock *vp;
+
+for(vp = firstvar; vp ; vp = vp->nxtvarblock)
+       if(! unequal(v , vp->varname))
+               return(vp);
+
+vp = ALLOC(varblock);
+vp->nxtvarblock = firstvar;
+firstvar = vp;
+vp->varname = copys(v);
+vp->varval = 0;
+return(vp);
+}
+
+
+fatal1(s, t)
+char *s, *t;
+{
+char buf[100];
+sprintf(buf, s, t);
+fatal(buf);
+}
+
+
+
+fatal(s)
+char *s;
+{
+if(s) fprintf(stderr, "Make: %s.  Stop.\n", s);
+else fprintf(stderr, "\nStop.\n");
+#ifdef unix
+exit(1);
+#endif
+#ifdef gcos
+exit(0);
+#endif
+}
+
+
+
+yyerror(s)
+char *s;
+{
+char buf[50];
+extern int yylineno;
+
+sprintf(buf, "line %d: %s", yylineno, s);
+fatal(buf);
+}
+
+
+
+struct chain *appendq(head, tail)
+struct chain *head;
+char *tail;
+{
+register struct chain *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);
+}
+
+
+
+
+
+char *mkqlist(p)
+struct chain *p;
+{
+register char *qbufp, *s;
+static char qbuf[QBUFMAX];
+
+if(p == NULL)
+       {
+       qbuf[0] = '\0';
+       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);
+}