home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / Editors / mjovesrc.zoo / proc.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  20KB  |  911 lines

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