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 */