Commit | Line | Data |
---|---|---|
9cf6814f | 1 | /* Copyright (c) 1979 Regents of the University of California */ |
299f2784 | 2 | static char *sccsid = "@(#)ex_unix.c 6.1 10/18/80"; |
9cf6814f MH |
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); | |
bdbbb330 | 134 | #ifdef SIGTSTP |
9cf6814f MH |
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(); | |
bdbbb330 | 210 | #ifdef SIGTSTP |
9cf6814f MH |
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]; | |
299f2784 | 235 | ttymode f; /* mjm: was register */ |
9cf6814f MH |
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]); | |
299f2784 | 254 | putfile(1); |
9cf6814f MH |
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)); | |
04379bab MH |
270 | #ifdef TRACE |
271 | if (trace) | |
272 | vudump("after append in filter"); | |
273 | #endif | |
9cf6814f MH |
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 | } |