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