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