/* @(#)macro.c 1.2 */ /* 3.0 SID # 1.2 */ # /* * UNIX shell * * S. R. Bourne * Bell Telephone Laboratories * */ #include "defs.h" #include "sym.h" LOCAL CHAR quote; /* used locally */ LOCAL CHAR quoted; /* used locally */ LOCAL STRING copyto(endch) REG CHAR endch; { REG CHAR c; WHILE (c=getch(endch))!=endch ANDF c DO pushstak(c|quote) OD zerostak(); IF c!=endch THEN error(badsub) FI } LOCAL skipto(endch) REG CHAR endch; { /* skip chars up to } */ REG CHAR c; WHILE (c=readc()) ANDF c!=endch DO SWITCH c IN case SQUOTE: skipto(SQUOTE); break; case DQUOTE: skipto(DQUOTE); break; case DOLLAR: IF readc()==BRACE THEN skipto('}'); FI ENDSW OD IF c!=endch THEN error(badsub) FI } LOCAL getch(endch) CHAR endch; { REG CHAR d; retry: d=readc(); IF !subchar(d) THEN return(d); FI IF d==DOLLAR THEN REG INT c; IF (c=readc(), dolchar(c)) THEN NAMPTR n=(NAMPTR) NIL; INT dolg=0; BOOL bra; BOOL nulflg; REG STRING argp, v; CHAR idb[2]; STRING id=idb; IF bra=(c==BRACE) THEN c=readc() FI IF letter(c) THEN argp=(STRING) relstak(); WHILE alphanum(c) DO pushstak(c); c=readc() OD zerostak(); n=lookup(absstak(argp)); setstak(argp); v = n->namval; id = n->namid; peekc = c|MARK;; ELIF digchar(c) THEN *id=c; idb[1]=0; IF astchar(c) THEN dolg=1; c='1'; FI c -= '0'; v=((c==0) ? cmdadr : (c<=dolc) ? dolv[c] : (STRING)(dolg=0)); ELIF c=='$' THEN v=pidadr; ELIF c=='!' THEN v=pcsadr; ELIF c=='#' THEN v=dolladr; ELIF c=='?' THEN v=exitadr; ELIF c=='-' THEN v=flagadr; ELIF bra THEN error(badsub); ELSE goto retry; FI c = readc(); IF c==':' ANDF bra /* null and unset fix */ THEN nulflg=1; c=readc(); ELSE nulflg=0; FI IF !defchar(c) ANDF bra THEN error(badsub); FI argp=0; IF bra THEN IF c!='}' THEN argp=(STRING)relstak(); IF (v==0 ORF (nulflg ANDF *v==0)) NEQ (setchar(c)) THEN copyto('}'); ELSE skipto('}'); FI argp=absstak(argp); FI ELSE peekc = c|MARK; c = 0; FI IF v ANDF (!nulflg ORF *v) THEN IF c!='+' THEN LOOP WHILE c = *v++ DO pushstak(c|quote); OD IF dolg==0 ORF (++dolg>dolc) THEN break; ELSE v=dolv[dolg]; pushstak(SP|(*id=='*' ? quote : 0)); FI POOL FI ELIF argp THEN IF c=='?' THEN failed(id,*argp?argp:badparam); ELIF c=='=' THEN IF n THEN trim(argp); assign(n,argp); ELSE error(badsub); FI FI ELIF flags&setflg THEN failed(id,unset); FI goto retry; ELSE peekc=c|MARK; FI ELIF d==endch THEN return(d); ELIF d==SQUOTE THEN comsubst(); goto retry; ELIF d==DQUOTE THEN quoted++; quote^=QUOTE; goto retry; FI return(d); } STRING macro(as) STRING as; { /* Strip "" and do $ substitution * Leaves result on top of stack */ REG BOOL savqu =quoted; REG CHAR savq = quote; FILEHDR fb; push(&fb); estabf(as); usestak(); quote=0; quoted=0; copyto(0); pop(); IF quoted ANDF (stakbot == staktop) THEN pushstak(QUOTE) FI /* above is the fix for *'.c' bug */ quote=savq; quoted=savqu; return(fixstak()); } LOCAL comsubst() { /* command substn */ FILEBLK cb; REG CHAR d; REG STKPTR savptr = fixstak(); usestak(); WHILE (d=readc())!=SQUOTE ANDF d DO pushstak(d) OD BEGIN REG STRING argc; trim(argc=fixstak()); push(&cb); estabf(argc); END BEGIN REG TREPTR t = makefork(FPOU,cmd(EOFSYM,MTFLG|NLFLG)); INT pv[2]; /* this is done like this so that the pipe * is open only when needed */ chkpipe(pv); initf(pv[INPIPE]); execute(t, 0, flags & errflg, 0, pv); close(pv[OTPIPE]); END tdystak(savptr); staktop=movstr(savptr,stakbot); WHILE d=readc() DO pushstak(d|quote) OD await(0,0); WHILE stakbot!=staktop DO IF (*--staktop&STRIP)!=NL THEN ++staktop; break; FI OD pop(); } #define CPYSIZ 512 subst(in,ot) INT in, ot; { REG CHAR c; FILEBLK fb; REG INT count=CPYSIZ; push(&fb); initf(in); /* DQUOTE used to stop it from quoting */ WHILE c=(getch(DQUOTE)&STRIP) DO pushstak(c); IF --count == 0 THEN flush(ot); count=CPYSIZ; FI OD flush(ot); pop(); } LOCAL flush(ot) { write(ot,stakbot,staktop-stakbot); IF flags&execpr THEN write(output,stakbot,staktop-stakbot) FI staktop=stakbot; }