Commit | Line | Data |
---|---|---|
6ca833f5 C |
1 | /*************************************************************************** |
2 | * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * | |
3 | * is provided to you without charge, and with no warranty. You may give * | |
4 | * away copies of JOVE, including sources, provided that this notice is * | |
5 | * included in all the files. * | |
6 | ***************************************************************************/ | |
7 | ||
8 | #include "jove.h" | |
9 | #include "re.h" | |
10 | #include <varargs.h> | |
11 | ||
12 | #ifdef IPROCS | |
13 | ||
14 | int proc_child(); | |
15 | ||
16 | #ifdef PIPEPROCS | |
17 | # include "iproc-pipes.c" | |
18 | #else | |
19 | # include "iproc-ptys.c" | |
20 | #endif | |
21 | ||
22 | char proc_prompt[128] = "% "; | |
23 | ||
24 | KillProcs() | |
25 | { | |
26 | register Process *p; | |
27 | register int killem = -1; /* -1 means undetermined */ | |
28 | register char *yorn; | |
29 | ||
30 | for (p = procs; p != 0; p = p->p_next) | |
31 | if (!isdead(p)) { | |
32 | if (killem == -1) { | |
33 | yorn = ask("y", "Should I kill your i-processes? "); | |
34 | killem = (CharUpcase(*yorn) == 'Y'); | |
35 | } | |
36 | if (killem) | |
37 | proc_kill(p, SIGKILL); | |
38 | } | |
39 | } | |
40 | ||
41 | pbuftiedp(b) | |
42 | register Buffer *b; | |
43 | { | |
44 | register Process *p = b->b_process; | |
45 | ||
46 | if (!isdead(p)) | |
47 | complain("Process %s, attached to %b, is %s.", | |
48 | proc_cmd(p), b, pstate(p)); | |
49 | } | |
50 | ||
51 | /* Process receive: receives the characters in buf, and appends them to | |
52 | the buffer associated with p. */ | |
53 | ||
54 | private | |
55 | proc_rec(p, buf) | |
56 | register Process *p; | |
57 | char *buf; | |
58 | { | |
59 | Buffer *saveb = curbuf; | |
60 | register Window *w; | |
61 | register Mark *savepoint; | |
62 | int sameplace = NO, | |
63 | do_disp = NO; | |
64 | ||
65 | if (curwind->w_bufp == p->p_buffer) | |
66 | w = curwind; | |
67 | else | |
68 | w = windbp(p->p_buffer); /* Is this window visible? */ | |
69 | if (w != 0) | |
70 | do_disp = (in_window(w, p->p_mark->m_line) != -1); | |
71 | SetBuf(p->p_buffer); | |
72 | savepoint = MakeMark(curline, curchar, M_FLOATER); | |
73 | ToMark(p->p_mark); /* where output last stopped */ | |
74 | if (savepoint->m_line == curline && savepoint->m_char == curchar) | |
75 | sameplace = YES; | |
76 | ||
77 | ins_str(buf, YES); | |
78 | MarkSet(p->p_mark, curline, curchar); | |
79 | if (!sameplace) | |
80 | ToMark(savepoint); /* back to where we were */ | |
81 | DelMark(savepoint); | |
82 | /* redisplay now, instead of right after the ins_str, so that | |
83 | we don't get a bouncing effect if point is not the same as | |
84 | the process output position */ | |
85 | if (do_disp) { | |
86 | w->w_line = curline; | |
87 | w->w_char = curchar; | |
88 | redisplay(); | |
89 | } | |
90 | SetBuf(saveb); | |
91 | } | |
92 | ||
93 | proc_kill(p, sig) | |
94 | register Process *p; | |
95 | { | |
96 | if (isdead(p)) | |
97 | return; | |
98 | if (killpg(p->p_pid, sig) == -1) | |
99 | s_mess("Cannot kill %s!", proc_buf(p)); | |
100 | } | |
101 | ||
102 | /* Free process CHILD. Do all the necessary cleaning up (closing fd's, | |
103 | etc.). */ | |
104 | ||
105 | free_proc(child) | |
106 | Process *child; | |
107 | { | |
108 | register Process *p, | |
109 | *prev = 0; | |
110 | ||
111 | if (!isdead(child)) | |
112 | return; | |
113 | for (p = procs; p != child; prev = p, p = p->p_next) | |
114 | ; | |
115 | if (prev == 0) | |
116 | procs = child->p_next; | |
117 | else | |
118 | prev->p_next = child->p_next; | |
119 | proc_close(child); /* if not already closed */ | |
120 | ||
121 | /* It's possible that the buffer has been given another process | |
122 | between the time CHILD dies and CHILD's death is noticed (via | |
123 | list-processes). So we only set it the buffer's process to | |
124 | 0 if CHILD is still the controlling process. */ | |
125 | if (child->p_buffer->b_process == child) { | |
126 | child->p_buffer->b_process = 0; | |
127 | if (curbuf == child->p_buffer) | |
128 | PopPBs(); | |
129 | } | |
130 | { | |
131 | Buffer *old = curbuf; | |
132 | ||
133 | SetBuf(child->p_buffer); | |
134 | DelMark(child->p_mark); | |
135 | SetBuf(old); | |
136 | } | |
137 | free((char *) child->p_name); | |
138 | free((char *) child); | |
139 | } | |
140 | ||
141 | ProcList() | |
142 | { | |
143 | register Process *p, | |
144 | *next; | |
145 | char *fmt = "%-15s %-15s %-8s %s", | |
146 | pidstr[16]; | |
147 | ||
148 | if (procs == 0) { | |
149 | message("[No subprocesses]"); | |
150 | return; | |
151 | } | |
152 | TOstart("Process list", TRUE); | |
153 | ||
154 | Typeout(fmt, "Buffer", "Status", "Pid ", "Command"); | |
155 | Typeout(fmt, "------", "------", "--- ", "-------"); | |
156 | for (p = procs; p != 0; p = next) { | |
157 | next = p->p_next; | |
158 | sprintf(pidstr, "%d", p->p_pid); | |
159 | Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name); | |
160 | if (isdead(p)) { | |
161 | free_proc(p); | |
162 | UpdModLine = YES; | |
163 | } | |
164 | } | |
165 | TOstop(); | |
166 | } | |
167 | ||
168 | ProcNewline() | |
169 | { | |
170 | #ifdef ABBREV | |
171 | MaybeAbbrevExpand(); | |
172 | #endif | |
173 | SendData(YES); | |
174 | } | |
175 | ||
176 | ProcSendData() | |
177 | { | |
178 | #ifdef ABBREV | |
179 | MaybeAbbrevExpand(); | |
180 | #endif | |
181 | SendData(NO); | |
182 | } | |
183 | ||
184 | private | |
185 | SendData(newlinep) | |
186 | { | |
187 | register Process *p = curbuf->b_process; | |
188 | register char *lp, | |
189 | *gp; /* JF fix for better prompt handling */ | |
190 | ||
191 | if (isdead(p)) | |
192 | return; | |
193 | /* If the process mark was involved in a big deletion, because | |
194 | the user hit ^W or something, then let's do some magic with | |
195 | the process mark. Problem is that if the user yanks back the | |
196 | text he deleted, the mark stays at the beginning of the region, | |
197 | and so the next time SendData() is called the entire region | |
198 | will be sent. That's not good. So, to deal with that we reset | |
199 | the mark to the last line, after skipping over the prompt, etc. */ | |
200 | if (p->p_mark->m_flags & M_BIG_DELETE) { | |
201 | Bufpos bp; | |
202 | ||
203 | p->p_mark->m_flags &= ~M_BIG_DELETE; | |
204 | ||
205 | DOTsave(&bp); | |
206 | ToLast(); | |
207 | Bol(); | |
208 | /* While we're looking at a prompt, and while we're | |
209 | moving forward. This is for people who accidently | |
210 | set their process-prompt to ">*" which will always | |
211 | match! */ | |
212 | while ((LookingAt(proc_prompt, linebuf, curchar)) && | |
213 | (REeom > curchar)) | |
214 | curchar = REeom; | |
215 | MarkSet(p->p_mark, curline, curchar); | |
216 | SetDot(&bp); | |
217 | } | |
218 | ||
219 | if (lastp(curline)) { | |
220 | Eol(); | |
221 | if (newlinep) | |
222 | LineInsert(1); | |
223 | do_rtp(p->p_mark); | |
224 | MarkSet(p->p_mark, curline, curchar); | |
225 | } else { | |
226 | /* Either we're looking at a prompt, or we're not, in | |
227 | which case we want to strip off the beginning of the | |
228 | line anything that looks like what the prompt at the | |
229 | end of the file is. In other words, if "(dbx) stop in | |
230 | ProcessNewline" is the line we're on, and the last | |
231 | line in the buffer is "(dbx) ", then we strip off the | |
232 | leading "(dbx) " from this line, because we know it's | |
233 | part of the prompt. But this only happens if "(dbx) " | |
234 | isn't one of the process prompts ... follow what I'm | |
235 | saying? */ | |
236 | Bol(); | |
237 | if (LookingAt(proc_prompt, linebuf, curchar)) { | |
238 | do | |
239 | curchar = REeom; | |
240 | while ((LookingAt(proc_prompt, linebuf, curchar)) && | |
241 | (REeom > curchar)); | |
242 | strcpy(genbuf, linebuf + curchar); | |
243 | Eof(); | |
244 | ins_str(genbuf, NO); | |
245 | } else { | |
246 | strcpy(genbuf, linebuf + curchar); | |
247 | Eof(); | |
248 | gp = genbuf; | |
249 | lp = linebuf; | |
250 | while (*lp == *gp && *lp != '\0') { | |
251 | lp += 1; | |
252 | gp += 1; | |
253 | } | |
254 | ins_str(gp, NO); | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | ShellProc() | |
260 | { | |
261 | char *shbuf = "*shell*"; | |
262 | register Buffer *b; | |
263 | ||
264 | b = buf_exists(shbuf); | |
265 | if (b == 0 || isdead(b->b_process)) | |
266 | proc_strt(shbuf, NO, Shell, "-i", (char *) 0); | |
267 | pop_wind(shbuf, NO, -1); | |
268 | } | |
269 | ||
270 | Iprocess() | |
271 | { | |
272 | extern char ShcomBuf[100], | |
273 | *MakeName(); | |
274 | register char *command; | |
275 | char scratch[64], | |
276 | *bufname; | |
277 | int cnt = 1; | |
278 | Buffer *bp; | |
279 | ||
280 | command = ask(ShcomBuf, ProcFmt); | |
281 | null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1); | |
282 | bufname = MakeName(command); | |
283 | strcpy(scratch, bufname); | |
284 | while ((bp = buf_exists(scratch)) && !isdead(bp->b_process)) | |
285 | sprintf(scratch, "%s.%d", bufname, cnt++); | |
286 | proc_strt(scratch, YES, Shell, ShFlags, command, (char *) 0); | |
287 | } | |
288 | ||
289 | proc_child() | |
290 | { | |
291 | union wait w; | |
292 | register int pid; | |
293 | ||
294 | for (;;) { | |
295 | #ifndef BSD4_2 | |
296 | pid = wait2(&w.w_status, (WNOHANG | WUNTRACED)); | |
297 | #else | |
298 | pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *) 0); | |
299 | #endif | |
300 | if (pid <= 0) | |
301 | break; | |
302 | kill_off(pid, w); | |
303 | } | |
304 | } | |
305 | ||
306 | kill_off(pid, w) | |
307 | register int pid; | |
308 | union wait w; | |
309 | { | |
310 | register Process *child; | |
311 | ||
312 | if ((child = proc_pid(pid)) == 0) | |
313 | return; | |
314 | ||
315 | UpdModLine = YES; /* we're changing state ... */ | |
316 | if (WIFSTOPPED(w)) | |
317 | child->p_state = STOPPED; | |
318 | else { | |
319 | child->p_state = DEAD; | |
320 | if (WIFEXITED(w)) | |
321 | child->p_howdied = EXITED; | |
322 | else if (WIFSIGNALED(w)) { | |
323 | child->p_reason = w.w_termsig; | |
324 | child->p_howdied = KILLED; | |
325 | } | |
326 | { | |
327 | Buffer *save = curbuf; | |
328 | char mesg[128]; | |
329 | ||
330 | /* insert status message now */ | |
331 | sprintf(mesg, "[Process %s: %s]\n", | |
332 | proc_cmd(child), | |
333 | pstate(child)); | |
334 | SetBuf(child->p_buffer); | |
335 | ins_str(mesg, NO); | |
336 | SetBuf(save); | |
337 | redisplay(); | |
338 | } | |
339 | } | |
340 | } | |
341 | ||
342 | /* Push/pod process bindings. I openly acknowledge that this is a | |
343 | kludge, but I can't be bothered making it right. */ | |
344 | ||
345 | struct proc_bind { | |
346 | int pb_key; | |
347 | data_obj **pb_map; | |
348 | data_obj *pb_push; | |
349 | data_obj *pb_cmd; | |
350 | struct proc_bind *pb_next; | |
351 | }; | |
352 | ||
353 | struct proc_bind *PBinds = 0; | |
354 | ||
355 | PopPBs() | |
356 | { | |
357 | register struct proc_bind *p; | |
358 | ||
359 | for (p = PBinds; p != 0; p = p->pb_next) | |
360 | p->pb_map[p->pb_key] = p->pb_push; | |
361 | } | |
362 | ||
363 | PushPBs() | |
364 | { | |
365 | register struct proc_bind *p; | |
366 | ||
367 | for (p = PBinds; p != 0; p = p->pb_next) { | |
368 | p->pb_push = p->pb_map[p->pb_key]; | |
369 | p->pb_map[p->pb_key] = p->pb_cmd; | |
370 | } | |
371 | } | |
372 | /* VARARGS0 */ | |
373 | ||
374 | ProcBind() | |
375 | { | |
376 | register data_obj *d; | |
377 | ||
378 | if ((d = findcom(ProcFmt)) == 0) | |
379 | return; | |
380 | s_mess(": %f %s ", d->Name); | |
381 | ProcB2(mainmap, EOF, d); | |
382 | } | |
383 | ||
384 | ProcB2(map, lastkey, cmd) | |
385 | data_obj **map, | |
386 | *cmd; | |
387 | { | |
388 | register struct proc_bind *p; | |
389 | register data_obj **nextmap; | |
390 | int c; | |
391 | ||
392 | c = addgetc(); | |
393 | if (c == EOF) { | |
394 | if (lastkey == EOF) | |
395 | complain("[Empty key sequence]"); | |
396 | complain("[Unexpected end-of-line]"); | |
397 | } else { | |
398 | if (nextmap = IsPrefix(map[c])) | |
399 | ProcB2(nextmap, c, cmd); | |
400 | else { | |
401 | if (curbuf->b_process) | |
402 | PopPBs(); | |
403 | ||
404 | for (p = PBinds; p != 0; p = p->pb_next) | |
405 | if (p->pb_key == c && p->pb_map == map) | |
406 | break; | |
407 | if (p == 0) { | |
408 | p = (struct proc_bind *) emalloc(sizeof *p); | |
409 | p->pb_next = PBinds; | |
410 | PBinds = p; | |
411 | } | |
412 | p->pb_map = map; | |
413 | p->pb_key = c; | |
414 | p->pb_cmd = cmd; | |
415 | ||
416 | if (curbuf->b_process) | |
417 | PushPBs(); | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | #endif /* IPROCS */ | |
423 |