Commit | Line | Data |
---|---|---|
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 | 8 | static 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 | */ | |
24 | unix0(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]) { | |
45 | tunix: | |
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 | } | |
80 | uexp: | |
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 | */ | |
133 | ttymode | |
134 | unixex(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 | */ | |
212 | unixwt(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 | */ | |
239 | filter(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 | */ | |
301 | recover() | |
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 | */ | |
330 | waitfor() | |
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 | */ | |
347 | revocer() | |
348 | { | |
349 | ||
350 | waitfor(); | |
351 | if (pid == rpid && status != 0) | |
352 | edited = 0; | |
353 | else | |
354 | change(); | |
355 | } |