xref: /original-bsd/old/sh/macro.c (revision 014fe330)
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