|
|
1.1 root 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 "ctype.h"
11: #include "disp.h"
12: #if defined(IPROCS)
13: # include "fp.h"
14: # include "iproc.h"
15: #endif
16:
17: #ifdef STDARGS
18: # include <stdargs.h>
19: #else
20: # include <varargs.h>
21: #endif
22:
23: #ifdef IPROCS
24:
25: private void
26: proc_rec proto ((Process *, char *)),
27: proc_close proto ((Process *)),
28: proc_kill proto((Process *, int)),
29: SendData proto ((int));
30:
31: private int
32: proc_child proto((int));
33:
34: #ifdef PIPEPROCS
35: # include "iproc-pipes.c"
36: #else
37: # include "iproc-ptys.c"
38: #endif
39:
40: char proc_prompt[128] = "% ";
41:
42: char *
43: pstate(p)
44: Process *p;
45: {
46: switch (proc_state(p)) {
47: case NEW:
48: return "New";
49:
50: case STOPPED:
51: return "Stopped";
52:
53: case RUNNING:
54: return "Running";
55:
56: case DEAD:
57: if (p->p_howdied == EXITED) {
58: if (p->p_reason == 0)
59: return "Done";
60: return sprint("Exit %d", p->p_reason);
61: }
62: return sprint("Killed %d", p->p_reason);
63:
64: default:
65: return "Unknown state";
66: }
67: }
68:
69: void
70: KillProcs()
71: {
72: register Process *p;
73: register int killem = -1; /* -1 means undetermined */
74: register char *yorn;
75:
76: for (p = procs; p != 0; p = p->p_next)
77: if (!isdead(p)) {
78: if (killem == -1) {
79: yorn = ask("y", "Should I kill your i-processes? ");
80: killem = (CharUpcase(*yorn) == 'Y');
81: }
82: if (killem)
83: proc_kill(p, SIGKILL);
84: }
85: }
86:
87: void
88: pbuftiedp(b)
89: register Buffer *b;
90: {
91: register Process *p = b->b_process;
92:
93: if (!isdead(p))
94: complain("Process %s, attached to %b, is %s.",
95: proc_cmd(p), b, pstate(p));
96: }
97:
98: char dbx_parse_fmt[128] = "line \\([0-9]*\\) in \\{file,\\} *\"\\([^\"]*\\)\"";
99:
100: void
101: DBXpoutput()
102: {
103: if (curbuf->b_process == 0)
104: complain("[Must be in a process buffer to enable dbx mode]");
105: curbuf->b_process->p_dbx_mode = !curbuf->b_process->p_dbx_mode;
106: UpdModLine = YES;
107: }
108:
109: private void
110: watch_input(m)
111: Mark *m;
112: {
113: Bufpos save;
114: char fname[FILESIZE],
115: lineno[FILESIZE];
116: int lnum;
117: Window *savew = curwind;
118: Buffer *buf;
119:
120: DOTsave(&save);
121: ToMark(m);
122: if (dosearch(dbx_parse_fmt, FORWARD, YES) != NULL) {
123: get_FL_info(fname, lineno);
124: buf = do_find((Window *) 0, fname, YES);
125: pop_wind(buf->b_name, NO, -1);
126: lnum = atoi(lineno);
127: SetLine(next_line(buf->b_first, lnum - 1));
128: SetWind(savew);
129: }
130: SetDot(&save);
131: }
132:
133: /* Process receive: receives the characters in buf, and appends them to
134: the buffer associated with p. */
135:
136: private void
137: proc_rec(p, buf)
138: register Process *p;
139: char *buf;
140: {
141: Buffer *saveb = curbuf;
142: register Window *w;
143: register Mark *savepoint;
144: int sameplace = NO,
145: do_disp = NO;
146:
147: if (curwind->w_bufp == p->p_buffer)
148: w = curwind;
149: else
150: w = windbp(p->p_buffer); /* Is this window visible? */
151: if (w != 0)
152: do_disp = (in_window(w, p->p_mark->m_line) != -1);
153: SetBuf(p->p_buffer);
154: savepoint = MakeMark(curline, curchar, M_FLOATER);
155: ToMark(p->p_mark); /* where output last stopped */
156: if (savepoint->m_line == curline && savepoint->m_char == curchar)
157: sameplace = YES;
158: ins_str(buf, YES);
159: if (do_disp == YES && p->p_dbx_mode == YES)
160: watch_input(p->p_mark);
161: MarkSet(p->p_mark, curline, curchar);
162: if (!sameplace)
163: ToMark(savepoint); /* back to where we were */
164: DelMark(savepoint);
165: /* redisplay now, instead of right after the ins_str, so that
166: we don't get a bouncing effect if point is not the same as
167: the process output position */
168: if (do_disp) {
169: w->w_line = curline;
170: w->w_char = curchar;
171: redisplay();
172: }
173: SetBuf(saveb);
174: }
175:
176: private void
177: proc_kill(p, sig)
178: register Process *p;
179: int sig;
180: {
181: if (isdead(p))
182: return;
183: if (killpg(p->p_pid, sig) == -1)
184: s_mess("Cannot kill %s!", proc_buf(p));
185: }
186:
187: /* Free process CHILD. Do all the necessary cleaning up (closing fd's,
188: etc.). */
189:
190: private void
191: free_proc(child)
192: Process *child;
193: {
194: register Process *p,
195: *prev = 0;
196:
197: if (!isdead(child))
198: return;
199: for (p = procs; p != child; prev = p, p = p->p_next)
200: ;
201: if (prev == 0)
202: procs = child->p_next;
203: else
204: prev->p_next = child->p_next;
205: proc_close(child); /* if not already closed */
206:
207: /* It's possible that the buffer has been given another process
208: between the time CHILD dies and CHILD's death is noticed (via
209: list-processes). So we only set it the buffer's process to
210: 0 if CHILD is still the controlling process. */
211: if (child->p_buffer->b_process == child) {
212: child->p_buffer->b_process = 0;
213: }
214: {
215: Buffer *old = curbuf;
216:
217: SetBuf(child->p_buffer);
218: DelMark(child->p_mark);
219: SetBuf(old);
220: }
221: free((char *) child->p_name);
222: free((char *) child);
223: }
224:
225: void
226: ProcList()
227: {
228: register Process *p,
229: *next;
230: char *fmt = "%-15s %-15s %-8s %s",
231: pidstr[16];
232:
233: if (procs == 0) {
234: message("[No subprocesses]");
235: return;
236: }
237: TOstart("Process list", TRUE);
238:
239: Typeout(fmt, "Buffer", "Status", "Pid ", "Command");
240: Typeout(fmt, "------", "------", "--- ", "-------");
241: for (p = procs; p != 0; p = next) {
242: next = p->p_next;
243: swritef(pidstr, "%d", p->p_pid);
244: Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name);
245: if (isdead(p)) {
246: free_proc(p);
247: UpdModLine = YES;
248: }
249: }
250: TOstop();
251: }
252:
253: private void
254: do_rtp(mp)
255: register Mark *mp;
256: {
257: register Process *p = curbuf->b_process;
258: Line *line1 = curline,
259: *line2 = mp->m_line;
260: int char1 = curchar,
261: char2 = mp->m_char;
262: char *gp;
263: size_t nbytes;
264:
265: if (isdead(p) || p->p_buffer != curbuf)
266: return;
267:
268: (void) fixorder(&line1, &char1, &line2, &char2);
269: while (line1 != line2->l_next) {
270: gp = ltobuf(line1, genbuf) + char1;
271: if (line1 == line2)
272: gp[char2] = '\0';
273: else
274: strcat(gp, "\n");
275: if ((nbytes = strlen(gp)) != 0)
276: proc_write(p, gp, nbytes);
277: line1 = line1->l_next;
278: char1 = 0;
279: }
280: }
281:
282: void
283: ProcNewline()
284: {
285: #ifdef ABBREV
286: MaybeAbbrevExpand();
287: #endif
288: SendData(YES);
289: }
290:
291: void
292: ProcSendData()
293: {
294: #ifdef ABBREV
295: MaybeAbbrevExpand();
296: #endif
297: SendData(NO);
298: }
299:
300: private void
301: SendData(newlinep)
302: int newlinep;
303: {
304: register Process *p = curbuf->b_process;
305: register char *lp,
306: *gp; /* JF fix for better prompt handling */
307:
308: if (isdead(p))
309: return;
310: /* If the process mark was involved in a big deletion, because
311: the user hit ^W or something, then let's do some magic with
312: the process mark. Problem is that if the user yanks back the
313: text he deleted, the mark stays at the beginning of the region,
314: and so the next time SendData() is called the entire region
315: will be sent. That's not good. So, to deal with that we reset
316: the mark to the last line, after skipping over the prompt, etc. */
317: if (p->p_mark->m_flags & M_BIG_DELETE) {
318: Bufpos bp;
319:
320: p->p_mark->m_flags &= ~M_BIG_DELETE;
321:
322: DOTsave(&bp);
323: ToLast();
324: Bol();
325: /* While we're looking at a prompt, and while we're
326: moving forward. This is for people who accidently
327: set their process-prompt to ">*" which will always
328: match! */
329: while ((LookingAt(proc_prompt, linebuf, curchar)) &&
330: (REeom > curchar))
331: curchar = REeom;
332: MarkSet(p->p_mark, curline, curchar);
333: SetDot(&bp);
334: }
335:
336: if (lastp(curline)) {
337: Eol();
338: if (newlinep)
339: LineInsert(1);
340: do_rtp(p->p_mark);
341: MarkSet(p->p_mark, curline, curchar);
342: } else {
343: /* Either we're looking at a prompt, or we're not, in
344: which case we want to strip off the beginning of the
345: line anything that looks like what the prompt at the
346: end of the file is. In other words, if "(dbx) stop in
347: ProcessNewline" is the line we're on, and the last
348: line in the buffer is "(dbx) ", then we strip off the
349: leading "(dbx) " from this line, because we know it's
350: part of the prompt. But this only happens if "(dbx) "
351: isn't one of the process prompts ... follow what I'm
352: saying? */
353: Bol();
354: if (LookingAt(proc_prompt, linebuf, curchar)) {
355: do
356: curchar = REeom;
357: while ((LookingAt(proc_prompt, linebuf, curchar)) &&
358: (REeom > curchar));
359: strcpy(genbuf, linebuf + curchar);
360: Eof();
361: ins_str(genbuf, NO);
362: } else {
363: strcpy(genbuf, linebuf + curchar);
364: Eof();
365: gp = genbuf;
366: lp = linebuf;
367: while (*lp == *gp && *lp != '\0') {
368: lp += 1;
369: gp += 1;
370: }
371: ins_str(gp, NO);
372: }
373: }
374: }
375:
376: void
377: ShellProc()
378: {
379: char *shbuf = "*shell*";
380: register Buffer *b;
381:
382: b = buf_exists(shbuf);
383: if (b == 0 || isdead(b->b_process))
384: proc_strt(shbuf, NO, Shell, "-i", (char *) 0);
385: pop_wind(shbuf, NO, -1);
386: }
387:
388: void
389: Iprocess()
390: {
391: register char *command;
392: char scratch[64],
393: *bnm;
394: int cnt = 1;
395: Buffer *bp;
396:
397: command = ask(ShcomBuf, ProcFmt);
398: null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1);
399: bnm = MakeName(command);
400: strcpy(scratch, bnm);
401: while ((bp = buf_exists(scratch)) != NIL && !isdead(bp->b_process))
402: swritef(scratch, "%s.%d", bnm, cnt++);
403: proc_strt(scratch, YES, Shell, ShFlags, command, (char *) 0);
404: }
405:
406: private SIGRESULT
407: proc_child(junk)
408: int junk; /* needed for signal handler; not used */
409: {
410: union wait w;
411: register int pid;
412:
413: for (;;) {
414: #ifndef WAIT3
415: pid = wait2(&w.w_status, (WNOHANG | WUNTRACED));
416: #else
417: pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *) 0);
418: #endif
419: if (pid <= 0)
420: break;
421: kill_off(pid, w);
422: }
423: SIGRETURN;
424: }
425:
426: void
427: kill_off(pid, w)
428: register int pid;
429: union wait w;
430: {
431: register Process *child;
432:
433: if ((child = proc_pid(pid)) == 0)
434: return;
435:
436: UpdModLine = YES; /* we're changing state ... */
437: if (WIFSTOPPED(w))
438: child->p_state = STOPPED;
439: else {
440: child->p_state = DEAD;
441: if (WIFEXITED(w))
442: child->p_howdied = EXITED;
443: else if (WIFSIGNALED(w)) {
444: child->p_reason = w_termsignum(w);
445: child->p_howdied = KILLED;
446: }
447: {
448: Buffer *save = curbuf;
449: char mesg[128];
450:
451: /* insert status message now */
452: swritef(mesg, "[Process %s: %s]\n",
453: proc_cmd(child),
454: pstate(child));
455: SetBuf(child->p_buffer);
456: ins_str(mesg, NO);
457: SetBuf(save);
458: redisplay();
459: }
460: }
461: }
462:
463: #endif /* IPROCS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.