xref: /original-bsd/usr.bin/ex/ex_unix.c (revision bac5051c)
1 /* Copyright (c) 1979 Regents of the University of California */
2 static char *sccsid = "@(#)ex_unix.c	6.1 10/19/80";
3 #include "ex.h"
4 #include "ex_temp.h"
5 #include "ex_tty.h"
6 #include "ex_vis.h"
7 
8 /*
9  * Unix escapes, filtering
10  */
11 
12 /*
13  * First part of a shell escape,
14  * parse the line, expanding # and % and ! and printing if implied.
15  */
16 unix0(warn)
17 	bool warn;
18 {
19 	register char *up, *fp;
20 	register short c;
21 	char printub, puxb[UXBSIZE + sizeof (int)];
22 
23 	printub = 0;
24 	CP(puxb, uxb);
25 	c = getchar();
26 	if (c == '\n' || c == EOF)
27 		error("Incomplete shell escape command@- use 'shell' to get a shell");
28 	up = uxb;
29 	do {
30 		switch (c) {
31 
32 		case '\\':
33 			if (any(peekchar(), "%#!"))
34 				c = getchar();
35 		default:
36 			if (up >= &uxb[UXBSIZE]) {
37 tunix:
38 				uxb[0] = 0;
39 				error("Command too long");
40 			}
41 			*up++ = c;
42 			break;
43 
44 		case '!':
45 			fp = puxb;
46 			if (*fp == 0) {
47 				uxb[0] = 0;
48 				error("No previous command@to substitute for !");
49 			}
50 			printub++;
51 			while (*fp) {
52 				if (up >= &uxb[UXBSIZE])
53 					goto tunix;
54 				*up++ = *fp++;
55 			}
56 			break;
57 
58 		case '#':
59 			fp = altfile;
60 			if (*fp == 0) {
61 				uxb[0] = 0;
62 				error("No alternate filename@to substitute for #");
63 			}
64 			goto uexp;
65 
66 		case '%':
67 			fp = savedfile;
68 			if (*fp == 0) {
69 				uxb[0] = 0;
70 				error("No filename@to substitute for %%");
71 			}
72 uexp:
73 			printub++;
74 			while (*fp) {
75 				if (up >= &uxb[UXBSIZE])
76 					goto tunix;
77 				*up++ = *fp++ | QUOTE;
78 			}
79 			break;
80 		}
81 		c = getchar();
82 	} while (c == '"' || c == '|' || !endcmd(c));
83 	if (c == EOF)
84 		ungetchar(c);
85 	*up = 0;
86 	if (!inopen)
87 		resetflav();
88 	if (warn)
89 		ckaw();
90 	if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) {
91 		xchng = chng;
92 		vnfl();
93 		printf(mesg("[No write]|[No write since last change]"));
94 		noonl();
95 		flush();
96 	} else
97 		warn = 0;
98 	if (printub) {
99 		if (uxb[0] == 0)
100 			error("No previous command@to repeat");
101 		if (inopen) {
102 			splitw++;
103 			vclean();
104 			vgoto(WECHO, 0);
105 		}
106 		if (warn)
107 			vnfl();
108 		if (hush == 0)
109 			lprintf("!%s", uxb);
110 		if (inopen && Outchar != termchar) {
111 			vclreol();
112 			vgoto(WECHO, 0);
113 		} else
114 			putnl();
115 		flush();
116 	}
117 }
118 
119 /*
120  * Do the real work for execution of a shell escape.
121  * Mode is like the number passed to open system calls
122  * and indicates filtering.  If input is implied, newstdin
123  * must have been setup already.
124  */
125 ttymode
126 unixex(opt, up, newstdin, mode)
127 	char *opt, *up;
128 	int newstdin, mode;
129 {
130 	int pvec[2];
131 	ttymode f;
132 
133 	signal(SIGINT, SIG_IGN);
134 #ifdef SIGTSTP
135 	if (dosusp)
136 		signal(SIGTSTP, SIG_DFL);
137 #endif
138 	if (inopen)
139 		f = setty(normf);
140 	if ((mode & 1) && pipe(pvec) < 0) {
141 		/* Newstdin should be io so it will be closed */
142 		if (inopen)
143 			setty(f);
144 		error("Can't make pipe for filter");
145 	}
146 #ifndef VFORK
147 	pid = fork();
148 #else
149 	pid = vfork();
150 #endif
151 	if (pid < 0) {
152 		if (mode & 1) {
153 			close(pvec[0]);
154 			close(pvec[1]);
155 		}
156 		setrupt();
157 		error("No more processes");
158 	}
159 	if (pid == 0) {
160 		if (mode & 2) {
161 			close(0);
162 			dup(newstdin);
163 			close(newstdin);
164 		}
165 		if (mode & 1) {
166 			close(pvec[0]);
167 			close(1);
168 			dup(pvec[1]);
169 			if (inopen) {
170 				close(2);
171 				dup(1);
172 			}
173 			close(pvec[1]);
174 		}
175 		if (io)
176 			close(io);
177 		if (tfile)
178 			close(tfile);
179 #ifndef VMUNIX
180 		close(erfile);
181 #endif
182 		signal(SIGHUP, oldhup);
183 		signal(SIGQUIT, oldquit);
184 		if (ruptible)
185 			signal(SIGINT, SIG_DFL);
186 		execl(svalue(SHELL), "sh", opt, up, (char *) 0);
187 		printf("No %s!\n", svalue(SHELL));
188 		error(NOSTR);
189 	}
190 	if (mode & 1) {
191 		io = pvec[0];
192 		close(pvec[1]);
193 	}
194 	if (newstdin)
195 		close(newstdin);
196 	return (f);
197 }
198 
199 /*
200  * Wait for the command to complete.
201  * F is for restoration of tty mode if from open/visual.
202  * C flags suppression of printing.
203  */
204 unixwt(c, f)
205 	bool c;
206 	ttymode f;
207 {
208 
209 	waitfor();
210 #ifdef SIGTSTP
211 	if (dosusp)
212 		signal(SIGTSTP, onsusp);
213 #endif
214 	if (inopen)
215 		setty(f);
216 	setrupt();
217 	if (!inopen && c && hush == 0) {
218 		printf("!\n");
219 		flush();
220 		termreset();
221 		gettmode();
222 	}
223 }
224 
225 /*
226  * Setup a pipeline for the filtration implied by mode
227  * which is like a open number.  If input is required to
228  * the filter, then a child editor is created to write it.
229  * If output is catch it from io which is created by unixex.
230  */
231 filter(mode)
232 	register int mode;
233 {
234 	static int pvec[2];
235 	register ttymode f;
236 	register int lines = lineDOL();
237 
238 	mode++;
239 	if (mode & 2) {
240 		signal(SIGINT, SIG_IGN);
241 		if (pipe(pvec) < 0)
242 			error("Can't make pipe");
243 		pid = fork();
244 		io = pvec[0];
245 		if (pid < 0) {
246 			setrupt();
247 			close(pvec[1]);
248 			error("No more processes");
249 		}
250 		if (pid == 0) {
251 			setrupt();
252 			io = pvec[1];
253 			close(pvec[0]);
254 			putfile();
255 			exit(0);
256 		}
257 		close(pvec[1]);
258 		io = pvec[0];
259 		setrupt();
260 	}
261 	f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
262 	if (mode == 3) {
263 		delete(0);
264 		addr2 = addr1 - 1;
265 	}
266 	if (mode & 1) {
267 		if(FIXUNDO)
268 			undap1 = undap2 = addr2+1;
269 		ignore(append(getfile, addr2));
270 #ifdef TRACE
271 		if (trace)
272 			vudump("after append in filter");
273 #endif
274 	}
275 	close(io);
276 	io = -1;
277 	unixwt(!inopen, f);
278 	netchHAD(lines);
279 }
280 
281 /*
282  * Set up to do a recover, getting io to be a pipe from
283  * the recover process.
284  */
285 recover()
286 {
287 	static int pvec[2];
288 
289 	if (pipe(pvec) < 0)
290 		error(" Can't make pipe for recovery");
291 	pid = fork();
292 	io = pvec[0];
293 	if (pid < 0) {
294 		close(pvec[1]);
295 		error(" Can't fork to execute recovery");
296 	}
297 	if (pid == 0) {
298 		close(2);
299 		dup(1);
300 		close(1);
301 		dup(pvec[1]);
302 	        close(pvec[1]);
303 		execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0);
304 		close(1);
305 		dup(2);
306 		error(" No recovery routine");
307 	}
308 	close(pvec[1]);
309 }
310 
311 /*
312  * Wait for the process (pid an external) to complete.
313  */
314 waitfor()
315 {
316 
317 	do
318 		rpid = wait(&status);
319 	while (rpid != pid && rpid != -1);
320 	status = (status >> 8) & 0377;
321 }
322 
323 /*
324  * The end of a recover operation.  If the process
325  * exits non-zero, force not edited; otherwise force
326  * a write.
327  */
328 revocer()
329 {
330 
331 	waitfor();
332 	if (pid == rpid && status != 0)
333 		edited = 0;
334 	else
335 		change();
336 }
337