xref: /original-bsd/old/sh/macro.c (revision c577960b)
1 #ifndef lint
2 static char sccsid[] = "@(#)macro.c	4.4 04/24/88";
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] : (STRING)(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