BSD 4_3_Tahoe development
[unix-history] / usr / src / new / jove / iproc.c
CommitLineData
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
14int proc_child();
15
16#ifdef PIPEPROCS
17# include "iproc-pipes.c"
18#else
19# include "iproc-ptys.c"
20#endif
21
22char proc_prompt[128] = "% ";
23
24KillProcs()
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
41pbuftiedp(b)
42register 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
54private
55proc_rec(p, buf)
56register Process *p;
57char *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
93proc_kill(p, sig)
94register 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
105free_proc(child)
106Process *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
141ProcList()
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
168ProcNewline()
169{
170#ifdef ABBREV
171 MaybeAbbrevExpand();
172#endif
173 SendData(YES);
174}
175
176ProcSendData()
177{
178#ifdef ABBREV
179 MaybeAbbrevExpand();
180#endif
181 SendData(NO);
182}
183
184private
185SendData(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
259ShellProc()
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
270Iprocess()
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
289proc_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
306kill_off(pid, w)
307register int pid;
308union 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
345struct 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
353struct proc_bind *PBinds = 0;
354
355PopPBs()
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
363PushPBs()
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
374ProcBind()
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
384ProcB2(map, lastkey, cmd)
385data_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