# /* * IFEXPR: * * * if[n]defs extended to handle expressions rather than the * mention of a single name, binary operators supported are * | (or) and & (and), ! (not) is only unary operator supported. * Nested expressions are supported using ( and ). * Precedence of evaluation is !(not) &(and) |(or). * ifndef adopts an unusual convention with respect to ots effect * i.e. * #ifndef a|b * is equivalent to * #ifdef !(a|b) * * #else added. * i.e. * #ifdef abc * ..... * #endif * #ifndef abc * ..... * #endif * is equivalent to * #ifdef abc * ..... * #else * ..... * #endif * * ANDREW HUME & IAN JOHNSTONE * 17-08-77 * 4-04-78 * * BETTER_FILES: * * use 'mktemp' to create temporary files * this solves duplicate tmp file problem. * GREG ROSE * 30-03-78 * * LIST: * * Produce line numbered listings of the source that C is actually * going to compile - in other words take note of if[n]defs etc... * Line numbers that appear on listing file (*.l) are actual line numbers * in the file in which the line appears. Include files may also be listed. * Of course characters in strings, character constants, defines, * macros and comments are all handled as you would expect - PROPERLY * * -L[O][I] * L produce listing * O listing only - no compilation, no .i file etc... * I include included files in listing * V list all lines not generating code * ( no line numbers/listing levels ) * * sample: * 0001 -- main() * 0002 0- { * 0003 -- int a; * 0004 -0 } * * errors: * too many '}'s (unmatched) give rise to an error * message "too many '}'s" * COMMENT: * A SIDE EFFECT of this alteration is that comments are now handle * in a more consistent way with respect to line numbering, e.g. * 0001 -- <<<error>>> ; /* a very * 0002 -- long * 0003 -- comment */ * under the old cc the error diagnostic for the above error would refer * to line 3 (yes it did) under the new scheme it will refer to line 1 * (a little more sensible). * IAN JOHNSTONE * 3-04-78 * * OUTPUT: * * For those of you who are sick and tired of " cc -o apple apple.c " * then this mod is for you. If -o is used then a quick check is made * to determine if a output file has been specified if none is present * then the name (no suffix) of the first mentioned file (*.s,*.o,*.c) * appearing after the option is used as the output file. NOTE the entire * pathname is not used only that portion appearing after the last '/' * and before the . of the suffix. So "cc -o apple.c" is equivalent to * the above. * IAN JOHNSTONE * 3-04-78 * * OPT: * * IF you've always wanted to print out the stats from the C optimiser * you now can ( yes virginia there is a santa claus ). * All that need be done is to place any non-null char after '-O' * and bingo as it were. * IAN JOHNSTONE * 4-04-78 * */ #define IFEXPR /***/ #define BETTER_FILES /***/ #define LIST /***/ #define OUTPUT /***/ #define OPT /***/ /*#define TEST /* to include some test code - have a look if ya like */ #ifdef LIST #define COMMENT #endif /* C command */ # define SBSIZE 10000 # define MAXINC 10 char sbf[SBSIZE]; #ifdef LIST char itoabuf[20]; #endif LIST char *tmp0; char *tmp1; char *tmp2; char *tmp3; char *tmp4; char *tmp5; char *outfile; # define CHSPACE 1000 char ts[CHSPACE+50]; # define EXPSIZE 500 char *tsa ts; char *tsp ts; char *av[50]; char *clist[50]; char *llist[50]; int instring; #ifdef COMMENT int incomment; #endif int pflag; int sflag; #ifdef LIST int llflag; /* listing flag */ #define LLLIS 01 /* produce listing */ #define LLINCL 02 /* list includes too */ #define LLONLY 04 /* listing only */ #define LLVERB 08 /* list all lines even those not gening code */ #endif LIST int cflag; int eflag; int exflag; int oflag; int proflag; int depth; int *ibuf; int *ibufs[MAXINC]; int ifno; int *obuf; extern int fout; char *lp; char *line; char *predef; char *sprefix "/usr/include"; int lineno[MAXINC]; int exfail; struct symtab { char name[8]; char *value; } *symtab; # define symsiz 400 struct symtab *defloc; struct symtab *incloc; struct symtab *eifloc; struct symtab *ifdloc; struct symtab *ifnloc; struct symtab *unxloc; struct symtab *lneloc; struct symtab *prdloc; #ifdef IFEXPR struct symtab *elsloc; /* * the following two variables values are altered by getline * in response to #ifdefs,#ifndefs,#endifs and #elses it may * encounter. The net effect of theses changes is to control * the compilation of the desired program segments: * * if( flslvl != 0 ) then no compile - just flush input * until an appropriate #endif of #else * is encountered. * flslvl is in effect the number of FALSE * plus the number of subsequent TRUE * nested #ifdefs or #ifndefs * if( flslvl == 0 ) compile all input. * trulvl is in effect the number of TRUE * nested #ifdefs or #ifndefs before the * first FALSE #if */ #endif IFEXPR int trulvl; int flslvl; char *stringbuf; char *pass0 "/lib/c0"; char *pass1 "/lib/c1"; char *pass2 "/lib/c2"; char *pref "/lib/crt0.o"; main(argc, argv) char *argv[]; { char *t; char *savetsp; char *assource; int nc, nl, i, j, c, f20, nxo; int dexit(); i = nc = nl = f20 = nxo = 0; while(++i < argc) { if(*argv[i] == '-') switch (argv[i][1]) { default: goto passa; case 'S': sflag++; cflag++; break; #ifdef LIST case 'L': llflag=LLLIS; t = &argv[i][2]; while( c = *t++ ) { switch( c ) { case 'i': case 'I': llflag =| LLINCL; break; case 'o': case 'O': llflag =| LLONLY; pflag++; cflag++; break; case 'v': case 'V': llflag =| LLVERB; break; } } break; #endif LIST case 'o': if (++i < argc) { outfile = argv[i]; #ifndef OUTPUT if ((t=getsuf(outfile))=='c'||t=='o') { error("Would overwrite %s", outfile); exit(8); #endif OUTPUT #ifdef OUTPUT if ((t=getsuf(outfile))=='c'||t=='o'||*argv[i]=='-') { i--; outfile = -1; #endif OUTPUT } } break; case 'O': #ifndef OPT oflag++; #endif OPT #ifdef OPT oflag=1; if( argv[i][2] != 0 ) oflag=2; #endif OPT break; case 'p': proflag++; pref = "/lib/mcrt0.o"; break; case 'E': exflag++; case 'P': pflag++; case 'c': cflag++; break; case 'f': pref = "/lib/fcrt0.o"; pass0 = "/lib/fc0"; pass1 = "/lib/fc1"; break; case 'D': predef = argv[i]+2; break; case 'I': sprefix=argv[i]+2; break; #ifdef TEST case '2': if(argv[i][2] == '\0') pref = "/lib/crt2.o"; else { pref = "/lib/crt20.o"; f20 = 1; } break; case 't': if (argv[i][2]=='0') pass0 = "/sys/c/c0"; if (argv[i][2]=='1') pass1 = "/sys/c/c1"; if (argv[i][2]=='2') pass2 = "/sys/c/c2"; break; case 'B': pass0 = "/sys/c/oc0"; pass1 = "/sys/c/oc1"; break; #endif TEST } else { passa: t = argv[i]; #ifdef LIST if( ((c=getsuf(t))=='h') && (llflag&LLONLY) ) { clist[nc++] = t; } else #endif LIST if((c=getsuf(t))=='c' || c=='s'|| exflag) { clist[nc++] = t; t = setsuf(t, 'o'); } if (nodup(llist, t)) { llist[nl++] = t; if (getsuf(t)=='o') { nxo++; #ifdef OUTPUT if( outfile == -1 ) { /* no output file specified to this point but '-o' specified so use filename of first pathname encountered for output, regardless of whether is was a .s or .c or .o pathname */ t = outfile = setsuf( t , 0 ); while( *t++ ) ; t[-2] = 0; } #endif OUTPUT } } } } if(nc==0) goto nocom; if (pflag==0) { #ifndef BETTER_FILES tmp0 = copy("/tmp/ctm0a"); #endif BETTER_FILES #ifdef BETTER_FILES tmp0 = mktemp( copy("/tmp/ctm0.XXXXX")); #endif BETTER_FILES while((c=open(tmp0, 0))>=0) { close(c); tmp0[9]++; } while((creat(tmp0, 0400))<0) tmp0[9]++; } if ((signal(2, 1) & 01) == 0) /* interrupt */ signal(2, dexit); if ((signal(15, 1) & 01) == 0) /* terminate */ signal(15, dexit); (tmp1 = copy(tmp0))[8] = '1'; (tmp2 = copy(tmp0))[8] = '2'; (tmp3 = copy(tmp0))[8] = '3'; if (oflag) (tmp5 = copy(tmp0))[8] = '5'; if (pflag==0) (tmp4 = copy(tmp0))[8] = '4'; for (i=0; i<nc; i++) { if (nc>1) printf("%s:\n", clist[i]); if (getsuf(clist[i])=='s') { assource = clist[i]; goto assemble; } else assource = tmp3; av[0] = "c0"; #ifndef LIST if (pflag) #endif LIST #ifdef LIST if( pflag && !(llflag&LLONLY) ) #endif LIST tmp4 = setsuf(clist[i], 'i'); savetsp = tsp; av[1] = expand(clist[i]); tsp = savetsp; if (pflag || exfail) continue; if (av[1] == 0) { cflag++; eflag++; continue; } av[2] = tmp1; av[3] = tmp2; if (proflag) { av[4] = "-P"; av[5] = 0; } else av[4] = 0; if (callsys(pass0, av)) { cflag++; eflag++; continue; } av[0] = "c1"; av[1] = tmp1; av[2] = tmp2; if (sflag) assource = tmp3 = setsuf(clist[i], 's'); av[3] = tmp3; if (oflag) av[3] = tmp5; av[4] = 0; if(callsys(pass1, av)) { cflag++; eflag++; continue; } if (oflag) { av[0] = "c2"; #ifndef OPT av[1] = tmp5; av[2] = tmp3; av[3] = 0; #endif OPT #ifdef OPT j = 1; if( oflag==2 ) av[j++] = "-"; av[j++] = tmp5; av[j++] = tmp3; av[j++] = 0; #endif OPT if (callsys(pass2, av)) { cflag++; eflag++; continue; } unlink(tmp5); } if (sflag) continue; assemble: av[0] = "as"; av[1] = "-o"; av[2] = setsuf(clist[i], 'o'); av[3] = "-u"; av[4] = assource; av[5] = 0; cunlink(tmp1); cunlink(tmp2); cunlink(tmp4); if (callsys("/bin/as", av) > 1) { cflag++; eflag++; continue; } } nocom: if (cflag==0 && nl!=0) { i = 0; av[0] = "ld"; av[1] = "-X"; av[2] = pref; j = 3; if (outfile) { av[j++] = "-o"; av[j++] = outfile; } while(i<nl) av[j++] = llist[i++]; if(f20) av[j++] = "-l2"; else { av[j++] = "-lc"; av[j++] = "-l"; } av[j++] = 0; eflag =| callsys("/bin/ld", av); if (nc==1 && nxo==1 && eflag==0) cunlink(setsuf(clist[0], 'o')); } dexit(); } dexit() { if (!pflag) { cunlink(tmp1); cunlink(tmp2); if (sflag==0) cunlink(tmp3); cunlink(tmp4); cunlink(tmp5); cunlink(tmp0); } exit(eflag); } # define LINELEN 500 #ifdef LIST char lline[LINELEN+8] "nnnn -- "; char *llinep; int llevel 0; #endif LIST char *fnames[MAXINC]; expand(file) char *file; { int ob[259]; struct symtab stab[symsiz]; char ln[LINELEN]; register int c; register char *rlp; #ifdef LIST int llbuf[259]; #endif LIST exfail = 0; ifno=0; if (ibufs[0]==0) ibufs[0] = sbrk(518); ibuf=ibufs[0]; fnames[ifno] = file; if (fopen(file, ibuf)<0) { error("No file %s", file); return(file); } obuf = ob; symtab = stab; for (c=0; c<symsiz; c++) { stab[c].name[0] = '\0'; stab[c].value = 0; } insym(&defloc, "define"); insym(&incloc, "include"); insym(&eifloc, "endif"); insym(&ifdloc, "ifdef"); insym(&ifnloc, "ifndef"); insym(&unxloc, "unix"); insym(&lneloc, "line"); #ifdef IFEXPR insym(&elsloc, "else"); #endif IFEXPR if (predef) insym(&prdloc, predef); stringbuf = sbf; trulvl = 0; flslvl = 0; line = ln; lineno[0] = 1; if (exflag==0) { #ifdef LIST if( (llflag&LLONLY)==0 ) { #endif LIST if (fcreat(tmp4, obuf) < 0) { printf("Can't creat %s\n", tmp4); dexit(); } #ifdef LIST } else obuf[0] = -1; /* lets not bother with the i/o */ /* a liitle kludgy but.... */ /* about a zillion tests required otherwise */ #endif LIST } else { obuf = &fout; fout = dup(1); } #ifdef LIST if( llflag ) { if( fcreat(setsuf(file,'l'),llbuf) < 0 ) { printf("Can't create %s\n",setsuf(file,'l')); dexit(); } } #endif LIST puts("# 1 \""); puts(file); puts("\"\n"); #ifdef LIST llinep = &lline[8]; llevel = -1; #endif LIST while(getline()) { #ifdef LIST putline(llbuf); #endif LIST if (ln[0] != '#' && flslvl==0) for (rlp = line; c = *rlp++;) putc(c, obuf); putc('\n', obuf); } for(rlp=line; c = *rlp++;) putc(c,obuf); #ifdef LIST if( llflag ) { fflush(llbuf); close( llbuf[0] ); } #endif LIST #ifdef IFEXPR if( flslvl || trulvl ) errexit("missing endif"); #endif IFEXPR fflush(obuf); if (obuf != &fout) close(obuf[0]); close(ibuf[0]); return(tmp4); } #ifdef LIST putline(llbuf) int *llbuf; { static char levelchars[] "?0123456789abcdefghijklmnopqrstuvwxyz"; register char *rlp; register int c; register int cs; int css; int blevel,elevel; int blflag,elflag; css = ifno; while( lineno[css]-1 == 0 ) css--; /* cope with includes */ if( (flslvl!=0) || (llflag==0) ) { if( llflag&LLVERB ) { verbose: if( !(llflag&LLINCL) && ifno != 0) goto done; pfnm( css , llbuf ); for( cs = 0 ; cs <8 ; cs ++ ) putc( ' ' , llbuf); for (rlp = &lline[8]; rlp<llinep;) putc( *rlp++ , llbuf); } goto done; } if( ( (ifno!=0) && (lineno[ifno]>1) ) && !(llflag&LLINCL) ) goto done; blflag = elflag = 1; if( lline[8] == '#' ) { for( rlp = &lline[9]; *rlp == ' ' || *rlp == '\t'; rlp++ ) ; if( eq("include", rlp) || eq("define", rlp)) goto skip; if( llflag&LLVERB ) goto verbose; else goto done; } blevel = - (elevel = 32767) ; cs = 0; for (rlp = line; c = *rlp++;) { if( cs ) { if( cs == c ) cs=0; else if( c == '\\' ) rlp++; } else if( c=='\'' || c=='"' ) cs = c; else if( c=='{' ) { blflag=0; if( ++llevel>blevel ) blevel=llevel; } else if( c=='}' ) { elflag=0; if( --llevel<elevel ) elevel=llevel+1; } } if( elevel<0 ) error("too many '}'s "); skip: pfnm( css , llbuf ); itoa( lineno[css]-1 ); lline[0] = itoabuf[15]; lline[1] = itoabuf[16]; lline[2] = itoabuf[17]; lline[3] = itoabuf[18]; lline[5] = blflag ? '-' : levelchars[(blevel<0)||(blevel>(sizeof levelchars-1)) ? 0 : blevel+1]; lline[6] = elflag ? '-' : levelchars[(elevel<0)||(elevel>(sizeof levelchars-1)) ? 0 : elevel+1]; for (rlp =lline; rlp<llinep;) putc( *rlp++ , llbuf); done: llinep = &lline[8]; } pfnm( cs , llbuf ) register int cs; int *llbuf; { register char c,*rlp; if( llflag&LLINCL ) { /* the following is a triffle inefficient but it don't happen that often so forget it */ cs = rlp = fnames[cs]; while( *rlp ) if( *rlp++ == '/' ) cs = rlp; rlp = cs; c = 0; while( *rlp ) { c++ ; putc( *rlp++ , llbuf ); } if( c<8 ) putc( '\t' , llbuf ); putc( '\t' , llbuf ); } } eq(s1,s2) register char *s1,*s2; { register char c; while( (c = *s1++) == *s2++ ); return( c==0 ); } #endif LIST getline() { register int c, sc, state; struct symtab *np; char *namep, *filname, *cp; #ifdef IFEXPR int ifval[40]; char ifop[40]; int *ifv; char *ifo; ifv = ifval; *(ifo = ifop) = 0; #endif IFEXPR lp = line; *lp = '\0'; state = 0; if ((c=getch()) == '#') state = 1; while (c!='\n' && c!='\0') { if ('a'<=c && c<='z' || 'A'<=c && c<='Z' || c=='_') { namep = lp; sch(c); while ('a'<=(c=getch()) && c<='z' ||'A'<=c && c<='Z' ||'0'<=c && c<='9' ||c=='_') sch(c); sch('\0'); lp--; if (state>3) { #ifndef IFEXPR if (flslvl==0 &&(state+!lookup(namep,-1)->name[0])==5) trulvl++; else flslvl++; out: while (c!='\n' && c!= '\0') c = getch(); return(c); #endif IFEXPR #ifdef IFEXPR *++ifv = lookup(namep,-1)->name[0] ? 1 : 0 ; if(*ifo == '!') { *ifv = !*ifv; ifo--; } if(*ifo == '&') { ifv--; *ifv =& ifv[1]; ifo--; } continue; #endif IFEXPR } if (state==3) /* include */ if (*namep != '"' && *namep != '<') { error("Bad include syntax", 0); state=1; } if (state!=2 || flslvl==0) { ungetc(c); np = lookup(namep, state); c = getch(); } if (state==1) { if (np==defloc) state = 2; else if (np==incloc) state = 3; else if (np==ifnloc) state = 4; else if (np==ifdloc) state = 5; else if (np==eifloc) { if (flslvl) --flslvl; else if (trulvl) --trulvl; else { errback("If-less #endif"); dexit(); } goto out; } #ifdef IFEXPR else if (np==elsloc) { switch(flslvl) { case 0: if(trulvl == 0) { errback("If-less #else"); dexit(); } else { trulvl--; flslvl++; } break; case 1: trulvl++; flslvl = 0; default: break; } goto out; } #endif IFEXPR else if (np==lneloc) { puts("# "); lp=line; for(; c !='\n' && c != '\0'; c=getch()) if (!pflag || exflag) sch(c); sch('\0'); return(c); } else { errback("Undefined control"); #ifdef IFEXPR out: #endif IFEXPR while (c!='\n' && c!='\0') c = getch(); return(c); } } else if (state==2) { if (flslvl) goto out; np->value = stringbuf; if (c != '\n' && c != 0) { savch(c); while ((c=getch())!='\n' && c!='\0') savch(c); } savch('\0'); return(1); } continue; } else if ((sc=c) == '\'' || sc== '"' || (state==3 && sc== '<')) { sch(sc); filname = lp; if (sc== '<') { sc= '>'; for(cp=sprefix; *cp; cp++) *lp++ = *cp; *lp++= '/'; } instring++; while ((c=getch())!=sc && c!='\n' && c!='\0') { sch(c); if (c=='\\') sch(getch()); } instring = 0; if (flslvl) goto out; if (state==3) { if (flslvl) goto out; *lp = '\0'; while ((c=getch())!='\n' && c!='\0'); if (ifno+1 >=MAXINC) error("Unreasonable include nesting",0); if(ibufs[++ifno]==0) ibufs[ifno]=sbrk(518); if (fopen(filname, ibufs[ifno])<0) { ifno--; errback("Missing file %s", filname); dexit(); } else ibuf = ibufs[ifno]; puts("\n# 1 \""); puts(filname); puts("\""); lineno[ifno]=1; fnames[ifno] = copy(filname); return(c); } } #ifdef IFEXPR else if(state > 3) switch(c) { case '(': case '|': case '&': case '!': *++ifo = c; break; case ' ': case '\t': break; case ')': for(;*ifo == '|'; ifo--) { ifv--; *ifv =| ifv[1]; } if(*ifo == '(') ifo--; else errexit("'(' expected"); if(*ifo == '!') { *ifv = !*ifv; ifo--; } if(*ifo == '&') { ifv--; *ifv =& ifv[1]; ifo--; } break; default: errexit("illegal char '%o' oct",c); break; } #endif IFEXPR sch(c); c = getch(); } sch('\0'); #ifdef IFEXPR for(;*ifo == '|'; ifo--) { ifv--; *ifv =| ifv[1]; } if(state == 4 || state == 5) if( (state + !(*ifv--)) == 5 && flslvl == 0) trulvl++; else flslvl++; if((ifv != ifval) || (ifo != ifop)) { errexit("if%cdef expression error",state==4 ? 'n' : 0); } state = 0; #endif IFEXPR if (state>1) errback("Control syntax"); return(c); } #ifdef IFEXPR errexit(s,x) { lineno[ifno]--; error(s,x); dexit(); } #endif IFEXPR insym(sp, namep) struct symtab **sp; char *namep; { register struct symtab *np; *sp = np = lookup(namep, 1); np->value = np->name; } error(s, x) { int olfout; olfout = fout; flush(); if (exflag) fout=2; if (fnames[ifno]) printf("%s: %d: ", fnames[ifno], lineno[ifno]); printf(s, x); putchar('\n'); flush(); fout=olfout; exfail++; cflag++; eflag++; } errback(s,x) { lineno[ifno]--; error(s,x); lineno[ifno]++; } sch(c) { register char *rlp; rlp = lp; if (rlp==line+LINELEN-2) error("Line overflow"); *rlp++ = c; if (rlp>line+LINELEN-1) rlp = line+LINELEN-1; lp = rlp; } savch(c) { *stringbuf++ = c; if (stringbuf-sbf < SBSIZE) return; error("Too much defining"); dexit(); } getch() { register int c; #ifdef COMMENT if( incomment ) goto commentprocessing; #endif COMMENT loop: if ((c=getc1())=='/' && !instring) { if ((c=getc1())!='*') { ungetc(c); return('/'); } for(;;) { incomment++; #ifdef COMMENT commentprocessing: #endif COMMENT c = getc1(); cloop: switch (c) { case '\0': return('\0'); case '*': if ((c=getc1())=='/') { #ifdef COMMENT incomment = 0; #endif COMMENT goto loop; } goto cloop; case '\n': #ifdef COMMENT return('\n'); #endif COMMENT #ifndef COMMENT putc('\n', obuf); continue; #endif COMMENT } } } return(c); } char pushbuff[EXPSIZE]; char *pushp pushbuff; ungetc(c) { *++pushp = c; if (pushp>pushbuff+EXPSIZE) { error("too much backup"); dexit(8); } } getc1() { register c; register flag = 0; if (*pushp !=0) return(*pushp--); depth=0; if ((c = getc(ibuf)) < 0 && ifno>0) { close(ibuf[0]); ibuf = ibufs[--ifno]; puts("\n# "); puts(itoa(lineno[ifno])); puts(" \""); puts(fnames[ifno]); puts("\"\n"); c = getc1(); flag++; if (c=='\n') lineno[ifno]--; } if (c<0) return(0); if (c=='\n' ) lineno[ifno]++; #ifdef LIST if( (llflag) && (flag==0) ) *llinep++ = c; #endif LIST return(c); } lookup(namep, enterf) char *namep; { register char *np, *snp; register struct symtab *sp; int i, c, around; np = namep; around = i = 0; while (c = *np++) i =+ c; i =% symsiz; sp = &symtab[i]; while (sp->name[0]) { snp = sp; np = namep; while (*snp++ == *np) if (*np++ == '\0' || np==namep+8) { if (!enterf) subst(namep, sp); return(sp); } if (++sp >= &symtab[symsiz]) if (around++) { error("too many defines"); dexit(); } else sp = symtab; } if (enterf>0) { snp = namep; for (np = &sp->name[0]; np < &sp->name[8];) if (*np++ = *snp) snp++; } return(sp); } char revbuff[200], *bp; backsch(c) { if (bp-revbuff > 200) error("Excessive define looping", bp--); *bp++ = c; } subst(np, sp) char *np; struct symtab *sp; { register char *vp; int macflg; lp = np; bp = revbuff; if (depth++>100) { error("define recursion loop\n"); return; } if ((vp = sp->value) == 0) return; macflg= (*vp == '('); /* arrange that define unix unix still has no effect, avoiding rescanning */ while (blank(*vp)) vp++; if (streq(sp->name,vp)) { while (*vp) sch(*vp++); return; } if (macflg) expdef(vp); else while (*vp) backsch(*vp++); while (bp>revbuff) ungetc(*--bp); } getsuf(as) char as[]; { register int c; register char *s; register int t; s = as; c = 0; while(t = *s++) if (t=='/') c = 0; else c++; s =- 3; if (c<=14 && c>2 && *s++=='.') return(*s); return(0); } setsuf(as, ch) char as[]; { register char *s, *s1; s = s1 = copy(as); while(*s) if (*s++ == '/') s1 = s; s[-1] = ch; return(s1); } callsys(f, v) char f[], *v[]; { int t, status; if ((t=fork())==0) { execv(f, v); printf("Can't find %s\n", f); exit(100); } else if (t == -1) { printf("Try again\n"); return(100); } while(t!=wait(&status)); if ((t=(status&0377)) != 0 && t!=14) { if (t!=2) /* interrupt */ { printf("Fatal error in %s\n", f); eflag = 8; } dexit(); } return((status>>8) & 0377); } copy(as) char as[]; { register char *otsp, *s; int i; otsp = tsp; s = as; while(*tsp++ = *s++); if (tsp >tsa+CHSPACE) { tsp = tsa = i = alloc(CHSPACE+50); if (i== -1){ error("no space for file names"); dexit(8); } } return(otsp); } nodup(l, os) char **l, *os; { register char *t, *s; register int c; s = os; if (getsuf(s) != 'o') return(1); while(t = *l++) { while(c = *s++) if (c != *t++) break; if (*t=='\0' && c=='\0') return(0); s = os; } return(1); } cunlink(f) char *f; { if (f==0) return(0); return(unlink(f)); } expdef(proto) char *proto; { char buffer[EXPSIZE], *parg[20], *pval[20], name[20], *cspace, *wp; char protcop[EXPSIZE], *pr; int narg, k, c; pr = protcop; while (*pr++ = *proto++); if (pr>protcop+EXPSIZE){ error("define prototype too big"); dexit(8); } proto= protcop; for (narg=0; (parg[narg] = token(&proto)) != 0; narg++) ; /* now scan input */ cspace = buffer; while ((c=getch()) == ' '); if (c != '(') { error("defined function requires arguments"); return; } ungetc(c); for(k=0; pval[k] = coptok(&cspace, buffer+EXPSIZE); k++); if (k!=narg) { error("define argument mismatch"); return; } while (c= *proto++) { if (!letter(c)) backsch(c); else { wp = name; *wp++ = c; while (letnum(*proto)) *wp++ = *proto++; *wp = 0; for (k=0; k<narg; k++) if(streq(name,parg[k])) break; wp = k <narg ? pval[k] : name; while (*wp) backsch(*wp++); } } } token(cpp) char **cpp; { char *val; int stc; stc = **cpp; *(*cpp)++ = '\0'; if (stc==')') return(0); while (**cpp == ' ') (*cpp)++; for (val = *cpp; (stc= **cpp) != ',' && stc!= ')'; (*cpp)++) { if (!letnum(stc) || (val == *cpp && !letter(stc))) { error("define prototype argument error"); return(0); } } return(val); } coptok (cpp, clim) char **cpp, *clim; { char *val; int stc, stop,paren; paren = stop = 0; val = *cpp; if (getch() == ')') return(0); while (((stc = getch()) != ',' && stc != ')' ) || paren > 0 || stop >0) { if (stc == '\0') { error("non terminated macro call"); val = 0; break; } if (stop == 0 && (stc == '"' || stc == '\'')) stop = stc; else if (stc==stop) stop = 0; if ( stc == '\\') { stc = getch(); if (stop>0 || (stc != ',' && stc != '\\')) *(*cpp)++ = '\\'; *(*cpp)++ = stc; } else { *(*cpp)++ = stc; if (stop==0) { if (stc == '(') paren++; if (stc == ')') paren--; } } if (*cpp >= clim) { error("define argument too long",0); dexit(8); } } *(*cpp)++ = 0; ungetc(stc); return(val); } letter(c) { if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) return (1); else return(0); } letnum(c) { if (letter(c) || (c >= '0' && c <= '9')) return(1); else return(0); } streq(s,t) char *s, *t; { int c; while ( (c= *s++) == *t++) if (c==0) return(1); return(0); } puts(s) char *s; { int c; if (pflag && !exflag) return; while (c= *s++) putc(c, obuf); } itoa(n) { char *sp; #ifndef LIST static char sb[20]; sp = sb+19; #endif LIST #ifdef LIST sp = itoabuf; while( sp<itoabuf+19 ) *sp++ = '0'; #endif LIST *sp=0; if (n<=0) *--sp = '0'; else while (n) { *--sp = '0'+ n%10; n=n/10; } return(sp); } blank(c) { return(c==' ' || c== '\t'); }