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