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 "io.h" 10: #include "termcap.h" 11: 12: #include <signal.h> 13: #include <varargs.h> 14: 15: #ifdef MSDOS 16: # include <io.h> 17: # include <process.h> 18: #endif 19: 20: 21: #ifdef LINT_ARGS 22: private void 23: DoShell(char *, char *), 24: com_finish(int, char *), 25: toerror(int, int), 26: closepipe(void); 27: 28: private int 29: okay_error(void), 30: openforpipe(void), 31: reopenforpipe(void); 32: 33: private struct error 34: * AddError(struct error *, Line *, Buffer *, Line *, int); 35: #else 36: private void 37: DoShell(), 38: com_finish(), 39: toerror(), 40: closepipe(); 41: 42: private int 43: openforpipe(), 44: okay_error(), 45: reopenforpipe(); 46: 47: private struct error 48: * AddError(); 49: #endif 50: 51: long SigMask = 0; 52: 53: /* This disgusting RE search string parses output from the GREP 54: family, from the pdp11 compiler, pcc, and lint. Jay (HACK) 55: Fenlasen changed this to work for the lint errors. */ 56: char ErrFmtStr[256] = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]\ 57: \\|:: *\\([^(]*\\)(\\([0-9]*\\))$\ 58: \\|( \\([^(]*\\)(\\([0-9]*\\)) ),"; 59: 60: struct error { 61: Buffer *er_buf; /* Buffer error is in */ 62: Line *er_mess, /* Actual error message */ 63: *er_text; /* Actual error */ 64: int er_char; /* char pos of error */ 65: struct error *er_prev, /* List of errors */ 66: *er_next; 67: }; 68: 69: struct error *cur_error = 0, 70: *errorlist = 0; 71: Buffer *perr_buf = 0; /* Buffer with error messages */ 72: 73: int WtOnMk = 1; /* Write the modified files when we make */ 74: 75: /* Add an error to the end of the list of errors. This is used for 76: parse-{C,LINT}-errors and for the spell-buffer command */ 77: 78: private struct error * 79: AddError(laste, errline, buf, line, charpos) 80: struct error *laste; 81: Line *errline, 82: *line; 83: Buffer *buf; 84: { 85: struct error *new = (struct error *) emalloc(sizeof *new); 86: 87: new->er_prev = laste; 88: if (laste) 89: laste->er_next = new; 90: else { 91: if (errorlist) /* Free up old errors */ 92: ErrFree(); 93: cur_error = errorlist = new; 94: } 95: laste = new; 96: new->er_next = 0; 97: new->er_buf = buf; 98: new->er_text = line; 99: new->er_char = charpos; 100: new->er_mess = errline; 101: 102: return new; 103: } 104: 105: /* Parse errors of the form specified in ErrFmtStr in the current 106: buffer. Do a show error of the first error. This is neat because this 107: will work for any kind of output that prints a file name and a line 108: number on the same line. */ 109: 110: void 111: ErrParse() 112: { 113: Bufpos *bp; 114: char fname[FILESIZE], 115: lineno[10], 116: REbuf[256], 117: *REalts[10]; 118: int lnum, 119: last_lnum = -1; 120: struct error *ep = 0; 121: Buffer *buf, 122: *lastb = 0; 123: Line *err_line; 124: 125: ErrFree(); /* This is important! */ 126: ToFirst(); 127: perr_buf = curbuf; 128: REcompile(ErrFmtStr, 1, REbuf, REalts); 129: /* Find a line with a number on it. */ 130: while (bp = docompiled(FORWARD, REbuf, REalts)) { 131: SetDot(bp); 132: putmatch(1, fname, sizeof fname); 133: putmatch(2, lineno, sizeof lineno); 134: buf = do_find((Window *) 0, fname, 1); 135: if (buf != lastb) { 136: lastb = buf; 137: last_lnum = -1; /* signals new file */ 138: err_line = buf->b_first; 139: } 140: (void) chr_to_int(lineno, 10, NO, &lnum); 141: if (lnum == last_lnum) /* one error per line is nicer */ 142: continue; 143: if (last_lnum == -1) 144: last_lnum = 1; /* that's where we really are */ 145: err_line = next_line(err_line, lnum - last_lnum); 146: ep = AddError(ep, curline, buf, err_line, 0); 147: last_lnum = lnum; 148: } 149: if (cur_error != 0) 150: ShowErr(); 151: } 152: 153: /* Free up all the errors */ 154: 155: void 156: ErrFree() 157: { 158: register struct error *ep; 159: 160: for (ep = errorlist; ep != 0; ep = ep->er_next) 161: free((char *) ep); 162: errorlist = cur_error = 0; 163: } 164: 165: /* Internal next error sets cur_error to the next error, taking the 166: argument count, supplied by the user, into consideration. */ 167: 168: private char errbounds[] = "You're at the %s error.", 169: noerrs[] = "No errors!"; 170: 171: private void 172: toerror(forward, num) 173: { 174: register struct error *e = cur_error; 175: 176: if (e == 0) 177: complain(noerrs); 178: if ((forward && (e->er_next == 0)) || 179: (!forward && (e->er_prev == 0))) 180: complain(errbounds, forward ? "last" : "first"); 181: 182: while (--num >= 0) { 183: if ((e = forward ? e->er_next : e->er_prev) == 0) 184: break; 185: cur_error = e; 186: } 187: } 188: 189: void 190: NextError() 191: { 192: ToError(1); 193: } 194: 195: void 196: PrevError() 197: { 198: ToError(0); 199: } 200: 201: private int 202: okay_error() 203: { 204: return ((inlist(perr_buf->b_first, cur_error->er_mess)) && 205: (inlist(cur_error->er_buf->b_first, cur_error->er_text))); 206: } 207: 208: /* Go the the next error, if there is one. Put the error buffer in 209: one window and the buffer with the error in another window. 210: It checks to make sure that the error actually exists. */ 211: 212: void 213: ToError(forward) 214: { 215: do { 216: toerror(forward, arg_value()); 217: } while (!okay_error()); 218: ShowErr(); 219: } 220: 221: int EWSize = 20; /* percentage of screen the error window 222: should be */ 223: 224: void 225: set_wsize(wsize) 226: int wsize; 227: { 228: wsize = (LI * wsize) / 100; 229: if (wsize >= 1 && !one_windp()) 230: WindSize(curwind, wsize - (curwind->w_height - 1)); 231: } 232: 233: /* Show the current error, i.e. put the line containing the error message 234: in one window, and the buffer containing the actual error in another 235: window. */ 236: 237: void 238: ShowErr() 239: { 240: Window *err_wind, 241: *buf_wind; 242: 243: if (cur_error == 0) 244: complain(noerrs); 245: if (!okay_error()) { 246: rbell(); 247: return; 248: } 249: err_wind = windbp(perr_buf); 250: buf_wind = windbp(cur_error->er_buf); 251: 252: if (err_wind && !buf_wind) { 253: SetWind(err_wind); 254: pop_wind(cur_error->er_buf->b_name, NO, -1); 255: buf_wind = curwind; 256: } else if (!err_wind && buf_wind) { 257: SetWind(buf_wind); 258: pop_wind(perr_buf->b_name, NO, -1); 259: err_wind = curwind; 260: } else if (!err_wind && !buf_wind) { 261: pop_wind(perr_buf->b_name, NO, -1); 262: err_wind = curwind; 263: pop_wind(cur_error->er_buf->b_name, NO, -1); 264: buf_wind = curwind; 265: } 266: 267: /* Put the current error message at the top of its Window */ 268: SetWind(err_wind); 269: SetLine(cur_error->er_mess); 270: SetTop(curwind, (curwind->w_line = cur_error->er_mess)); 271: set_wsize(EWSize); 272: 273: /* now go to the the line with the error in the other window */ 274: SetWind(buf_wind); 275: DotTo(cur_error->er_text, cur_error->er_char); 276: } 277: 278: char ShcomBuf[128] = {0}; 279: 280: /* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c" 281: will return the buffer name "fgrep". */ 282: 283: char * 284: MakeName(command) 285: char *command; 286: { 287: static char bufname[50]; 288: register char *cp = bufname, 289: c; 290: 291: while ((c = *command++) && (c == ' ' || c == '\t')) 292: ; 293: do 294: *cp++ = c; 295: while ((c = *command++) && (c != ' ' && c != '\t')); 296: *cp = 0; 297: strcpy(bufname, basename(bufname)); 298: 299: return bufname; 300: } 301: 302: /* Run make, first writing all the modified buffers (if the WtOnMk flag is 303: non-zero), parse the errors, and go the first error. */ 304: 305: char make_cmd[128] = "make"; 306: 307: void 308: MakeErrors() 309: { 310: Window *old = curwind; 311: int status, 312: compilation; 313: 314: if (WtOnMk) 315: put_bufs(0); 316: /* When we're not doing make or cc (i.e., the last command 317: was probably a grep or something) and the user just types 318: C-X C-E, he probably (possibly, hopefully, usually (in my 319: case)) doesn't want to do the grep again but rather wants 320: to do a make again; so we ring the bell and insert the 321: default command and let the person decide. */ 322: 323: compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd)); 324: if (is_an_arg() || !compilation) { 325: if (!compilation) { 326: rbell(); 327: Inputp = make_cmd; /* insert the default for the user */ 328: } 329: null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "), 330: sizeof (make_cmd) - 1); 331: } 332: status = UnixToBuf(MakeName(make_cmd), YES, EWSize, YES, Shell, ShFlags, make_cmd, (char *) 0); 333: com_finish(status, make_cmd); 334: 335: ErrParse(); 336: 337: if (!cur_error) 338: SetWind(old); 339: } 340: 341: #ifdef SPELL 342: 343: void 344: SpelBuffer() 345: { 346: char *Spell = "Spell", 347: com[100]; 348: Window *savewp = curwind; 349: 350: put_bufs(0); 351: sprintf(com, "spell %s", curbuf->b_fname); 352: (void) UnixToBuf(Spell, YES, EWSize, YES, Shell, ShFlags, com, (char *) 0); 353: message("[Delete the irrelevant words and then type C-X C-C]"); 354: ToFirst(); 355: Recur(); 356: SetWind(savewp); 357: SpelParse(Spell); 358: } 359: 360: void 361: SpelWords() 362: { 363: char *buftospel; 364: Buffer *wordsb = curbuf; 365: 366: if ((buftospel = ask_buf((Buffer *) 0)) == 0) 367: return; 368: SetBuf(do_select(curwind, buftospel)); 369: SpelParse(wordsb->b_name); 370: } 371: 372: void 373: SpelParse(bname) 374: char *bname; 375: { 376: Buffer *buftospel, 377: *wordsb; 378: char wordspel[100]; 379: Bufpos *bp; 380: struct error *ep = 0; 381: 382: ErrFree(); /* This is important! */ 383: 384: buftospel = curbuf; 385: wordsb = buf_exists(bname); 386: perr_buf = wordsb; /* This is important (buffer containing 387: error messages) */ 388: SetBuf(wordsb); 389: ToFirst(); 390: f_mess("Finding misspelled words ... "); 391: while (!lastp(curline)) { 392: sprintf(wordspel, "\\<%s\\>", linebuf); 393: SetBuf(buftospel); 394: ToFirst(); 395: while (bp = dosearch(wordspel, 1, 1)) { 396: SetDot(bp); 397: ep = AddError(ep, wordsb->b_dot, buftospel, 398: curline, curchar); 399: } 400: SetBuf(wordsb); 401: line_move(FORWARD, 1, NO); 402: } 403: add_mess("Done."); 404: SetBuf(buftospel); 405: ShowErr(); 406: } 407: 408: #endif /* SPELL */ 409: 410: void 411: ShToBuf() 412: { 413: char bufname[128], 414: cmd[128]; 415: 416: strcpy(bufname, ask((char *) 0, "Buffer: ")); 417: strcpy(cmd, ask(ShcomBuf, "Command: ")); 418: DoShell(bufname, cmd); 419: } 420: 421: void 422: ShellCom() 423: { 424: null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1); 425: DoShell(MakeName(ShcomBuf), ShcomBuf); 426: } 427: 428: ShNoBuf() 429: { 430: int status; 431: 432: null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1); 433: status = UnixToBuf((char *) 0, NO, 0, NO, Shell, ShFlags, ShcomBuf, (char *) 0); 434: com_finish(status, ShcomBuf); 435: } 436: 437: Shtypeout() 438: { 439: int status; 440: 441: null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1); 442: status = UnixToBuf((char *) 0, YES, 0, NO, Shell, ShFlags, ShcomBuf, (char *) 0); 443: if (status == 0) 444: Typeout("[%s: completed successfully]", ShcomBuf); 445: else 446: Typeout("[%s: exited (%d)]", ShcomBuf, status); 447: TOstop(); 448: } 449: 450: /* Run the shell command into `bufname'. Empty the buffer except when we 451: give a numeric argument, in which case it inserts the output at the 452: current position in the buffer. */ 453: 454: private void 455: DoShell(bufname, command) 456: char *bufname, 457: *command; 458: { 459: Window *savewp = curwind; 460: int status; 461: 462: status = UnixToBuf(bufname, YES, 0, !is_an_arg(), Shell, 463: ShFlags, command, (char *) 0); 464: com_finish(status, command); 465: SetWind(savewp); 466: } 467: 468: private void 469: com_finish(status, cmd) 470: int status; 471: char *cmd; 472: { 473: s_mess("[%s: ", cmd); 474: if (status == 0) 475: add_mess("completed successfully"); 476: else 477: add_mess("exited (%d)", status); 478: add_mess("]"); 479: } 480: 481: #ifndef MSDOS 482: void 483: dowait(pid, status) 484: int pid, 485: *status; 486: { 487: # ifndef IPROCS 488: 489: int rpid; 490: 491: while ((rpid = wait(status)) != pid) 492: ; 493: # else 494: 495: # ifdef BSD4_2 496: # include <sys/wait.h> 497: # else 498: # include <wait.h> 499: # endif 500: 501: union wait w; 502: int rpid; 503: 504: for (;;) { 505: # ifndef BSD4_2 506: rpid = wait2(&w.w_status, 0); 507: # else 508: rpid = wait3(&w, 0, (struct rusage *) 0); 509: # endif 510: if (rpid == pid) { 511: if (status) 512: *status = w.w_status; 513: break; 514: } else 515: kill_off(rpid, w); 516: } 517: # endif /* IPROCS */ 518: } 519: #endif /* MSDOS */ 520: 521: /* Run the command to bufname, erase the buffer if clobber is non-zero, 522: and redisplay if disp is non-zero. Leaves current buffer in `bufname' 523: and leaves any windows it creates lying around. It's up to the caller 524: to fix everything up after we're done. (Usually there's nothing to 525: fix up.) */ 526: 527: /* VARARGS5 */ 528: 529: int 530: UnixToBuf(bufname, disp, wsize, clobber, va_alist) 531: char *bufname; 532: va_dcl 533: { 534: #ifndef MSDOS 535: int p[2], 536: pid, 537: status, 538: #else /* MSDOS */ 539: int p0, 540: oldo, 541: olde, 542: retcode, 543: #endif /* MSDOS */ 544: eof; 545: va_list ap; 546: char *argv[32], 547: *mess; 548: File *fp; 549: int (*old_int)(); 550: 551: va_start(ap); 552: make_argv(argv, ap); 553: va_end(ap); 554: if (bufname != 0 && clobber == YES) 555: isprocbuf(bufname); 556: if (disp) { 557: if (bufname != 0) 558: message("Starting up..."); 559: else { 560: TOstart(argv[0], TRUE); 561: Typeout("Starting up..."); 562: } 563: if (bufname != 0) { 564: pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE); 565: set_wsize(wsize); 566: redisplay(); 567: } 568: } 569: /* Now I will attempt to describe how I deal with signals during 570: the execution of the shell command. My desire was to be able 571: to interrupt the shell command AS SOON AS the window pops up. 572: So, if we have JOB_CONTROL (i.e., the new signal mechanism) I 573: hold SIGINT, meaning if we interrupt now, we will eventually 574: see the interrupt, but not before we are ready for it. We 575: fork, the child releases the interrupt, it then sees the 576: interrupt, and so exits. Meanwhile the parent ignores the 577: signal, so if there was a pending one, it's now lost. 578: 579: With no JOB_CONTROL, the best behavior you can expect is, when 580: you type ^] too very quickly after the window pops up, it may 581: be ignored. The behavior BEFORE was that it would interrupt 582: JOVE and then you would have to continue JOVE and wait a 583: little while longer before trying again. Now that is fixed, 584: in that you just have to type it twice. */ 585: 586: #ifndef MSDOS 587: # ifdef IPROCS 588: sighold(SIGCHLD); 589: # endif 590: # ifdef JOB_CONTROL 591: sighold(SIGINT); 592: # else 593: old_int = signal(SIGINT, SIG_IGN), 594: # endif 595: dopipe(p); 596: pid = vfork(); 597: if (pid == -1) { 598: pclose(p); 599: complain("[Fork failed]"); 600: } 601: if (pid == 0) { 602: # ifdef BSD4_2 603: /* 604: * We want to release SIGCHLD and SIGINT in the child, but 605: * we can't use sigrelse because that would change Jove's 606: * copy of the SigMask variable (because we're in a 607: * vfork). So we simply set set the mask directly. There 608: * are several other forks in Jove, but this is the only 609: * one we execute often enough to make it worth using a 610: * vfork. 611: */ 612: (void) signal(SIGINT, SIG_DFL); 613: (void) sigsetmask(SigMask & ~(sigmask(SIGCHLD)|sigmask(SIGINT))); 614: # else /* BSD4_2 */ 615: # ifdef IPROCS 616: sigrelse(SIGCHLD); /* don't know if this matters */ 617: # endif /* IPROCS */ 618: (void) signal(SIGINT, SIG_DFL); 619: # ifdef JOB_CONTROL 620: sigrelse(SIGINT); 621: # endif 622: # endif /* BSD4_2 */ 623: (void) close(0); 624: (void) open("/dev/null", 0); 625: (void) close(1); 626: (void) close(2); 627: (void) dup(p[1]); 628: (void) dup(p[1]); 629: pclose(p); 630: execv(argv[0], &argv[1]); 631: (void) write(1, "Execl failed.\n", 14); 632: _exit(1); 633: } 634: # ifdef JOB_CONTROL 635: old_int = signal(SIGINT, SIG_IGN); 636: # endif 637: (void) close(p[1]); 638: fp = fd_open(argv[1], F_READ, p[0], iobuff, LBSIZE); 639: #else /* MSDOS */ 640: if ((p0 = openforpipe()) < 0) 641: complain("cannot make pipe for filter"); 642: 643: oldo = dup(1); 644: olde = dup(2); 645: close(1); 646: close(2); 647: dup(p0); 648: dup(1); 649: close(p0); 650: retcode = spawnv(0, argv[0], &argv[1]); 651: p0 = reopenforpipe(); 652: close(1); 653: close(2); 654: dup(oldo); 655: dup(olde); 656: close(oldo); 657: close(olde); 658: 659: if (retcode < 0) 660: complain("[Spawn failed]"); 661: 662: fp = fd_open(argv[1], F_READ, p0, iobuff, LBSIZE); 663: #endif /* MSDOS */ 664: do { 665: #ifndef MSDOS 666: inIOread = 1; 667: #endif 668: eof = f_gets(fp, genbuf, LBSIZE); 669: #ifndef MSDOS 670: inIOread = 0; 671: #endif 672: if (bufname != 0) { 673: ins_str(genbuf, YES); 674: if (!eof) 675: LineInsert(1); 676: } else if (disp == YES) 677: Typeout("%s", genbuf); 678: if (bufname != 0 && disp != 0 && fp->f_cnt <= 0) { 679: #ifdef LOAD_AV 680: { 681: double theavg; 682: 683: get_la(&theavg); 684: if (theavg < 2.0) 685: mess = "Screaming along..."; 686: else if (theavg < 5.0) 687: mess = "Chugging along..."; 688: else 689: mess = "Crawling along..."; 690: } 691: #else 692: mess = "Chugging along..."; 693: #endif /* LOAD_AV */ 694: if (bufname != 0) { 695: message(mess); 696: redisplay(); 697: } 698: } 699: } while (!eof); 700: if (disp) 701: DrawMesg(NO); 702: close_file(fp); 703: #ifndef MSDOS 704: dowait(pid, &status); 705: # ifdef JOB_CONTROL 706: (void) sigrelse(SIGINT); 707: # endif 708: #else /* MSDOS */ 709: closepipe(); 710: #endif /* MSDOS */ 711: (void) signal(SIGINT, old_int); 712: #ifndef MSDOS 713: # ifdef IPROCS 714: sigrelse(SIGCHLD); 715: # endif 716: return status; 717: #else /* MSDOS */ 718: # ifdef CHDIR 719: getCWD(); 720: # endif 721: return retcode; 722: #endif /* MSDOS */ 723: } 724: 725: void 726: FilterRegion() 727: { 728: char *cmd = ask((char *) 0, ": %f (through command) ", ProcFmt); 729: 730: RegToUnix(curbuf, cmd); 731: } 732: 733: /* Send the current region to CMD and insert the output from the 734: command into OUT_BUF. */ 735: 736: void 737: RegToUnix(outbuf, cmd) 738: Buffer *outbuf; 739: char *cmd; 740: { 741: Mark *m = CurMark(); 742: #ifndef MSDOS 743: char *tname = mktemp("/tmp/jfilterXXXXXX"), 744: combuf[128]; 745: #endif /* MSDOS */ 746: Window *save_wind = curwind; 747: int status, 748: error = NO; 749: #ifdef MSDOS 750: int p0, oldi; 751: #endif /* MSDOS */ 752: File *fp; 753: 754: #ifndef MSDOS 755: fp = open_file(tname, iobuff, F_WRITE, COMPLAIN, QUIET); 756: #else /* MSDOS */ 757: p0 = openforpipe(); 758: #endif /* MSDOS */ 759: CATCH 760: #ifdef MSDOS 761: fp = fd_open(cmd, F_WRITE, p0, iobuff, LBSIZE); 762: #endif /* MSDOS */ 763: putreg(fp, m->m_line, m->m_char, curline, curchar, YES); 764: DelReg(); 765: #ifndef MSDOS 766: sprintf(combuf, "%s < %s", cmd, tname); 767: #else /* MSDOS */ 768: f_close(fp); 769: p0 = reopenforpipe(); 770: oldi = dup(0); 771: close(0); 772: dup(p0); 773: close(p0); 774: #endif /* MSDOS */ 775: status = UnixToBuf(outbuf->b_name, NO, 0, outbuf->b_type == B_SCRATCH, 776: #ifndef MSDOS 777: Shell, ShFlags, combuf, (char *) 0); 778: #else /* MSDOS */ 779: Shell, ShFlags, cmd, (char *) 0); 780: #endif /* MSDOS */ 781: ONERROR 782: error = YES; 783: ENDCATCH 784: #ifndef MSDOS 785: f_close(fp); 786: (void) unlink(tname); 787: #else /* MSDOS */ 788: close(0); 789: open("con", 0); /* dup(oldi); */ 790: close(oldi); 791: closepipe(); 792: #endif /* MSDOS */ 793: SetWind(save_wind); 794: if (error == NO) 795: #ifndef MSDOS 796: com_finish(status, combuf); 797: #else 798: com_finish(status, cmd); 799: #endif 800: } 801: 802: void 803: isprocbuf(bufname) 804: char *bufname; 805: { 806: Buffer *bp; 807: 808: if ((bp = buf_exists(bufname)) != 0 && bp->b_type != B_PROCESS) 809: confirm("Over-write buffer %s?", bufname); 810: } 811: 812: #ifdef MSDOS 813: /* msdos specific hacks to allow for pipes */ 814: 815: #include <dos.h> 816: #include <fcntl.h> 817: #include <sys/types.h> 818: #include <sys/stat.h> 819: 820: static char pipeiname[64]; 821: static char pipeoname[64]; 822: static int pipehandle; 823: 824: extern char TmpFilePath[]; 825: 826: private int 827: openforpipe() 828: { 829: sprintf(pipeiname, "%s/%s", TmpFilePath, "Jove-I"); 830: sprintf(pipeoname, "%s/%s", TmpFilePath, "Jove-O"); 831: 832: return(pipehandle = creat(pipeoname, S_IWRITE|S_IREAD)); 833: } 834: 835: private int 836: reopenforpipe() 837: { 838: close(pipehandle); 839: unlink(pipeiname); 840: rename(pipeoname, pipeiname); 841: if ((pipehandle = open(pipeiname, 0)) >= 0) 842: return(pipehandle); 843: closepipe(); 844: return(-1); 845: } 846: 847: private void 848: closepipe() 849: { 850: unlink(pipeoname); 851: unlink(pipeiname); 852: } 853: 854: char 855: switchar() 856: { 857: union REGS regs; 858: 859: regs.h.ah = 0x37; 860: regs.h.al = 0; 861: intdos(®s, ®s); 862: return(regs.h.dl); 863: } 864: #endif /* MSDOS */