1 #ifndef lint 2 static char sccsid[] = "@(#)macro.c 4.3 08/11/83"; 3 #endif 4 5 # 6 /* 7 * UNIX shell 8 * 9 * S. R. Bourne 10 * Bell Telephone Laboratories 11 * 12 */ 13 14 #include "defs.h" 15 #include "sym.h" 16 17 LOCAL CHAR quote; /* used locally */ 18 LOCAL CHAR quoted; /* used locally */ 19 20 21 22 LOCAL STRING copyto(endch) 23 REG CHAR endch; 24 { 25 REG CHAR c; 26 27 WHILE (c=getch(endch))!=endch ANDF c 28 DO pushstak(c|quote) OD 29 zerostak(); 30 IF c!=endch THEN error(badsub) FI 31 } 32 33 LOCAL skipto(endch) 34 REG CHAR endch; 35 { 36 /* skip chars up to } */ 37 REG CHAR c; 38 WHILE (c=readc()) ANDF c!=endch 39 DO SWITCH c IN 40 41 case SQUOTE: skipto(SQUOTE); break; 42 43 case DQUOTE: skipto(DQUOTE); break; 44 45 case DOLLAR: IF readc()==BRACE 46 THEN skipto('}'); 47 FI 48 ENDSW 49 OD 50 IF c!=endch THEN error(badsub) FI 51 } 52 53 LOCAL getch(endch) 54 CHAR endch; 55 { 56 REG CHAR d; 57 58 retry: 59 d=readc(); 60 IF !subchar(d) 61 THEN return(d); 62 FI 63 IF d==DOLLAR 64 THEN REG INT c; 65 IF (c=readc(), dolchar(c)) 66 THEN NAMPTR n=NIL; 67 INT dolg=0; 68 BOOL bra; 69 REG STRING argp, v; 70 CHAR idb[2]; 71 STRING id=idb; 72 73 IF bra=(c==BRACE) THEN c=readc() FI 74 IF letter(c) 75 THEN argp=relstak(); 76 WHILE alphanum(c) DO pushstak(c); c=readc() OD 77 zerostak(); 78 n=lookup(absstak(argp)); setstak(argp); 79 v = n->namval; id = n->namid; 80 peekc = c|MARK;; 81 ELIF digchar(c) 82 THEN *id=c; idb[1]=0; 83 IF astchar(c) 84 THEN dolg=1; c='1'; 85 FI 86 c -= '0'; 87 v=((c==0) ? cmdadr : (c<=dolc) ? dolv[c] : (dolg=0)); 88 ELIF c=='$' 89 THEN v=pidadr; 90 ELIF c=='!' 91 THEN v=pcsadr; 92 ELIF c=='#' 93 THEN v=dolladr; 94 ELIF c=='?' 95 THEN v=exitadr; 96 ELIF c=='-' 97 THEN v=flagadr; 98 ELIF bra THEN error(badsub); 99 ELSE goto retry; 100 FI 101 c = readc(); 102 IF !defchar(c) ANDF bra 103 THEN error(badsub); 104 FI 105 argp=0; 106 IF bra 107 THEN IF c!='}' 108 THEN argp=relstak(); 109 IF (v==0)NEQ(setchar(c)) 110 THEN copyto('}'); 111 ELSE skipto('}'); 112 FI 113 argp=absstak(argp); 114 FI 115 ELSE peekc = c|MARK; c = 0; 116 FI 117 IF v 118 THEN IF c!='+' 119 THEN LOOP WHILE c = *v++ 120 DO pushstak(c|quote); OD 121 IF dolg==0 ORF (++dolg>dolc) 122 THEN break; 123 ELSE v=dolv[dolg]; pushstak(SP|(*id=='*' ? quote : 0)); 124 FI 125 POOL 126 FI 127 ELIF argp 128 THEN IF c=='?' 129 THEN failed(id,*argp?argp:badparam); 130 ELIF c=='=' 131 THEN IF n 132 THEN assign(n,argp); 133 ELSE error(badsub); 134 FI 135 FI 136 ELIF flags&setflg 137 THEN failed(id,badparam); 138 FI 139 goto retry; 140 ELSE peekc=c|MARK; 141 FI 142 ELIF d==endch 143 THEN return(d); 144 ELIF d==SQUOTE 145 THEN comsubst(); goto retry; 146 ELIF d==DQUOTE 147 THEN quoted++; quote^=QUOTE; goto retry; 148 FI 149 return(d); 150 } 151 152 STRING macro(as) 153 STRING as; 154 { 155 /* Strip "" and do $ substitution 156 * Leaves result on top of stack 157 */ 158 REG BOOL savqu =quoted; 159 REG CHAR savq = quote; 160 FILEHDR fb; 161 162 push(&fb); estabf(as); 163 usestak(); 164 quote=0; quoted=0; 165 copyto(0); 166 pop(); 167 IF quoted ANDF (stakbot==staktop) THEN pushstak(QUOTE) FI 168 quote=savq; quoted=savqu; 169 return(fixstak()); 170 } 171 172 LOCAL comsubst() 173 { 174 /* command substn */ 175 FILEBLK cb; 176 REG CHAR d; 177 REG STKPTR savptr = fixstak(); 178 179 usestak(); 180 WHILE (d=readc())!=SQUOTE ANDF d 181 DO pushstak(d) OD 182 183 BEGIN 184 REG STRING argc; 185 trim(argc=fixstak()); 186 push(&cb); estabf(argc); 187 END 188 BEGIN 189 REG TREPTR t = makefork(FPOU,cmd(EOFSYM,MTFLG|NLFLG)); 190 INT pv[2]; 191 192 /* this is done like this so that the pipe 193 * is open only when needed 194 */ 195 chkpipe(pv); 196 initf(pv[INPIPE]); 197 execute(t, 0, 0, pv); 198 close(pv[OTPIPE]); 199 END 200 tdystak(savptr); staktop=movstr(savptr,stakbot); 201 WHILE d=readc() DO locstak(); pushstak(d|quote) OD 202 await(0); 203 WHILE stakbot!=staktop 204 DO IF (*--staktop&STRIP)!=NL 205 THEN ++staktop; break; 206 FI 207 OD 208 pop(); 209 } 210 211 #define CPYSIZ 512 212 213 subst(in,ot) 214 INT in, ot; 215 { 216 REG CHAR c; 217 FILEBLK fb; 218 REG INT count=CPYSIZ; 219 220 push(&fb); initf(in); 221 /* DQUOTE used to stop it from quoting */ 222 WHILE c=(getch(DQUOTE)&STRIP) 223 DO pushstak(c); 224 IF --count == 0 225 THEN flush(ot); count=CPYSIZ; 226 FI 227 OD 228 flush(ot); 229 pop(); 230 } 231 232 LOCAL flush(ot) 233 { 234 write(ot,stakbot,staktop-stakbot); 235 IF flags&execpr THEN write(output,stakbot,staktop-stakbot) FI 236 staktop=stakbot; 237 } 238