home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / spawn.c < prev    next >
C/C++ Source or Header  |  1998-09-22  |  18KB  |  784 lines

  1. /*    Spawn:    various DOS access commands
  2.  *        for MicroEMACS
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/spawn.c,v 1.132 1998/09/23 00:14:07 tom Exp $
  5.  *
  6.  */
  7.  
  8. #ifdef _WIN32
  9. # include    <process.h>
  10. #endif
  11.  
  12. #include    "estruct.h"
  13. #include    "edef.h"
  14. #include    "nefunc.h"
  15.  
  16. #if SYS_UNIX && defined(SIGTSTP) && !DISP_X11
  17. #define USE_UNIX_JOB_CTL 1
  18. #else
  19. #define USE_UNIX_JOB_CTL 0
  20. #endif
  21.  
  22. #if SYS_VMS
  23. #include <starlet.h>
  24. #include <lib$routines.h>
  25. extern    int    vms_system(char *);    /*FIXME: not the same as 'system()'?*/
  26. #endif
  27.  
  28. static    int spawn1(int rerun, int pressret);
  29.  
  30.  
  31.  
  32. #if    SYS_VMS
  33. #define EFN    0                /* Event flag.        */
  34.  
  35. #include    <ssdef.h>            /* Random headers.    */
  36. #include    <stsdef.h>
  37. #include    <descrip.h>
  38. #include    <iodef.h>
  39.  
  40. extern  int    oldmode[3];            /* In "termio.c"    */
  41. extern  int    newmode[3];            /* In "termio.c"    */
  42. extern  short    iochan;                /* In "termio.c"    */
  43. #endif
  44.  
  45. #if CC_NEWDOSCC && !CC_DJGPP            /* Typo, was NEWSDOSCC    */
  46. #include    <process.h>
  47. #endif
  48.  
  49. /*
  50.  * Check all modification-times after executing a shell command
  51.  */
  52. #ifdef    MDCHK_MODTIME
  53. #define    AfterShell()    check_visible_modtimes()
  54. #else
  55. #define    AfterShell()    TRUE
  56. #endif
  57.  
  58. #if DISP_X11
  59. static void x_window_SHELL(const char *cmd)
  60. {
  61.     TBUFF *tmp = 0;
  62.  
  63.     /*
  64.      * We would use the -display option of xterm, but that would get in the
  65.      * way of the user's ability to customize $xshell.
  66.      */
  67. #if HAVE_PUTENV
  68.     static char *display_env;
  69.     char *env = gtenv("xdisplay");
  70.     if (display_env != 0)
  71.         free(display_env);
  72.     display_env = typeallocn(char,20+strlen(env));
  73.     lsprintf(display_env, "DISPLAY=%s", env);
  74.     putenv(display_env);
  75. #endif
  76.  
  77.     tmp = tb_scopy(&tmp, gtenv("xshell"));
  78.     if (cmd != 0) {
  79.         tb_unput(tmp);
  80.         tmp = tb_sappend(&tmp, " -e ");
  81.         tmp = tb_sappend(&tmp, cmd);
  82.         tmp = tb_append(&tmp, EOS);
  83.     }
  84.     TRACE(("executing '%s'\n", tb_values(tmp)));
  85.     (void)system(tb_values(tmp));
  86.     tb_free(&tmp);
  87. }
  88. #endif
  89.  
  90. /*
  91.  * Create a subjob with a copy of the command interpreter in it. When the
  92.  * command interpreter exits, mark the screen as garbage so that you do a full
  93.  * repaint. The message at the start in VMS puts out a newline.
  94.  * Under some (unknown) condition, you don't get one free when DCL starts up.
  95.  */
  96. /* ARGSUSED */
  97. int
  98. spawncli(int f GCC_UNUSED, int n GCC_UNUSED)
  99. {
  100. #undef OK_SPAWN
  101.  
  102. #if    SYS_UNIX
  103. #define    OK_SPAWN
  104.     ttclean(TRUE);
  105.     kbd_openup();
  106. #if    DISP_X11
  107.     (void)x_window_SHELL((char *)0);
  108. #else
  109.     (void)system_SHELL((char *)0);
  110. #endif
  111.     kbd_openup();
  112.     ttunclean();
  113.     sgarbf = TRUE;
  114.     return AfterShell();
  115. #endif /* SYS_UNIX */
  116.  
  117.  
  118. #if    SYS_VMS
  119. #define    OK_SPAWN
  120.     mlforce("[Starting DCL]\r\n");
  121.     kbd_flush();                /* Ignore "ttcol".    */
  122.     sgarbf = TRUE;
  123.     return vms_system(NULL);        /* NULL => DCL.        */
  124. #endif
  125.  
  126.  
  127. #if    SYS_MSDOS || SYS_OS2 || SYS_WINNT
  128. #define    OK_SPAWN
  129.     bottomleft();
  130.     kbd_flush();
  131.     TTkclose();
  132.     {
  133.         char *shell = gtenv("shell");
  134. #if SYS_OS2
  135. /*
  136.  *    spawn it if we know it.  Some 3rd party command processors fail
  137.  *    if they system themselves (eg 4OS2).  CCM 24-MAR-94
  138.  */
  139.         spawnl( P_WAIT, shell, shell, NULL);
  140. #else
  141. #if SYS_WINNT
  142.         w32_system(shell);
  143. #else
  144.         system(shell);
  145. #endif
  146. #endif
  147.     }
  148.     TTkopen();
  149.     sgarbf = TRUE;
  150.     return AfterShell();
  151. #endif
  152.  
  153.  
  154. #ifndef    OK_SPAWN
  155.     mlforce("[This version of vile cannot spawn an interactive shell]");
  156.     return FALSE;
  157. #endif
  158. }
  159.  
  160.  
  161. /* ARGSUSED */
  162. int
  163. bktoshell(int f, int n)        /* suspend and wait to wake up */
  164. {
  165. #if USE_UNIX_JOB_CTL
  166.     int forced = (f && n == SPECIAL_BANG_ARG); /* then it was :stop! */
  167.  
  168.     /* take care of autowrite */
  169.     if (!forced && writeall(f,n,FALSE,TRUE,TRUE) != TRUE)
  170.         return FALSE;
  171.  
  172.     beginDisplay();
  173.     ttclean(TRUE);
  174.  
  175. /* #define simulate_job_control_for_debug */
  176. # ifdef simulate_job_control_for_debug
  177.     rtfrmshell(SIGCONT);
  178.     return TRUE;
  179. # else
  180.     (void)signal_pg(SIGTSTP);
  181.  
  182.     /*
  183.      * Next four lines duplicate spawncli() actions following return
  184.      * from shell.    Adding lines 1-3 ensure that vile properly redraws
  185.      * its screen when TERM type is vt220 or vt320 and host is linux.
  186.      */
  187.     kbd_openup();
  188.     ttunclean();
  189.     sgarbf = TRUE;
  190.     return AfterShell();
  191. # endif
  192. #else
  193.     mlforce("[Job control unavailable]");
  194.     return FALSE;
  195. #endif /* SIGTSTP */
  196. }
  197.  
  198. /*ARGSUSED*/
  199. SIGT
  200. rtfrmshell(int ACTUAL_SIG_ARGS GCC_UNUSED)
  201. {
  202. #if USE_UNIX_JOB_CTL
  203.     endofDisplay();
  204.     ttunclean();
  205.     sgarbf = TRUE;
  206. #  if SYS_APOLLO
  207.     (void)TTgetc();        /* have to skip a character */
  208.     ttunclean();        /* ...so that I can finally suppress echo */
  209. #  endif
  210.     TTkopen();
  211.     setup_handler(SIGCONT,rtfrmshell); /* suspend & restart */
  212.     (void)update(TRUE);
  213. #endif
  214. #ifdef    MDCHK_MODTIME
  215.     (void)check_visible_modtimes();
  216. #endif
  217.     SIGRET;
  218. }
  219.  
  220. void
  221. pressreturn(void)
  222. {
  223.     int c;
  224.     int odiscmd;
  225.  
  226.     odiscmd = discmd;
  227.     discmd = TRUE;
  228.     mlprompt("[Press return to continue]");
  229.     discmd = odiscmd;
  230.     /* loop for a CR, a space, or a : to do another named command */
  231.     while ((c = keystroke()) != '\r' &&
  232.             c != '\n' &&
  233.             c != ' ' &&
  234.             !ABORTED(c)) {
  235.         if (kcod2fnc(c) == &f_namedcmd) {
  236.             unkeystroke(c);
  237.             break;
  238.         }
  239.     }
  240.     kbd_erase_to_end(0);
  241. }
  242.  
  243. /* ARGSUSED */
  244. int
  245. respawn(int f, int n GCC_UNUSED)
  246. {
  247.     return spawn1(TRUE, !f);
  248. }
  249.  
  250. /* ARGSUSED */
  251. int
  252. spawn(int f, int n GCC_UNUSED)
  253. {
  254.     return spawn1(FALSE, !f);
  255. }
  256.  
  257. #define COMMON_SH_PROMPT (SYS_UNIX || SYS_VMS || SYS_MSDOS || SYS_OS2 || SYS_WINNT)
  258.  
  259. #if COMMON_SH_PROMPT
  260. /*
  261.  * Common function for prompting for shell/pipe command, and for recording the
  262.  * last shell/pipe command so that we can support "!!" convention.
  263.  *
  264.  * Note that for 'pipecmd()', we must retain a leading "!".
  265.  */
  266. static int
  267. ShellPrompt(
  268. TBUFF    **holds,
  269. char    *result,
  270. int    rerun)        /* TRUE/FALSE: spawn, -TRUE: pipecmd */
  271. {
  272.     register int    s;
  273.     register SIZE_T    len;
  274.     static    const char bang[] = SHPIPE_LEFT;
  275.     BUFFER *bp;
  276.     int    cb    = any_changed_buf(&bp),
  277.         fix    = (rerun != -TRUE);
  278.     char    save[NLINE],
  279.         temp[NLINE],
  280.         line[NLINE+1];
  281.  
  282.     if ((len = tb_length(*holds)) != 0) {
  283.         (void)strncpy(save, tb_values(*holds), len);
  284.     }
  285.     save[len] = EOS;
  286.  
  287.     /* if it doesn't start with '!', or if that's all it is */
  288.     if (!isShellOrPipe(save) || save[1] == EOS)
  289.         (void)strcpy(save, bang);
  290.  
  291.     (void)strcpy(line, save);
  292.     if (rerun != TRUE) {
  293.         if (cb != 0) {
  294.             if (cb > 1) {
  295.             (void)lsprintf(temp,
  296.                 "Warning: %d modified buffers: %s",
  297.                 cb, bang);
  298.             } else {
  299.             (void)lsprintf(temp,
  300.                 "Warning: buffer \"%s\" is modified: %s",
  301.                 bp->b_bname, bang);
  302.             }
  303.         } else {
  304.             (void)lsprintf(temp, "%s%s",
  305.                 rerun == -TRUE ? "" : ": ", bang);
  306.         }
  307.  
  308.         if ((s = mlreply_no_bs(temp, line+1, NLINE)) != TRUE)
  309.             return s;
  310.     }
  311.     if (line[1] == EOS)
  312.         return FALSE;
  313.  
  314.     *holds = tb_scopy(holds, line);
  315.     (void)strcpy(result, line+fix);
  316.     return TRUE;
  317. }
  318. #endif
  319.  
  320. /*
  321.  * Run a one-liner in a subjob. When the command returns, wait for a single
  322.  * character to be typed, then mark the screen as garbage so a full repaint is
  323.  * done.
  324.  */
  325. /* the #ifdefs have been totally separated, for readability */
  326. static int
  327. spawn1(int rerun, int pressret)
  328. {
  329. #if DISP_IBMPC
  330.     int    closed;
  331. #endif
  332. #if COMMON_SH_PROMPT
  333.     register int    s;
  334.     char    line[NLINE];    /* command line send to shell */
  335.  
  336.     if ((s = ShellPrompt(&save_shell[0], line, rerun)) != TRUE)
  337.         return s;
  338. #endif    /* COMMON_SH_PROMPT */
  339.  
  340.     /* take care of autowrite */
  341.     if (writeall(FALSE,1,FALSE,TRUE,TRUE) != TRUE)
  342.         return FALSE;
  343.  
  344. #if SYS_UNIX
  345. #if DISP_X11
  346.     /*FIXME (void)x_window_SHELL(line); */
  347.     (void)system_SHELL(line);
  348. #else
  349.     ttclean(TRUE);
  350.     (void)system_SHELL(line);
  351.     TTflush();
  352.     ttunclean();
  353.     if (pressret)
  354.         pressreturn();
  355.     TTopen();
  356.     TTkopen();
  357.     TTflush();
  358.     sgarbf = TRUE;
  359. #endif /* DISP_X11 */
  360.     return AfterShell();
  361. #endif /* SYS_UNIX */
  362.  
  363. #if    SYS_VMS
  364.     kbd_flush();
  365.     s = vms_system(line);        /* Run the command.    */
  366.     if (pressret) {
  367.         TTputc('\r');
  368.         TTputc('\n');
  369.         TTflush();
  370.         pressreturn();
  371.     }
  372.     sgarbf = TRUE;
  373.     return (s);
  374. #endif
  375. #if    SYS_WIN31
  376.     mlforce("[Not in Windows 3.1]");
  377.     return FALSE;
  378. #endif
  379. #if    SYS_MSDOS || SYS_OS2 || SYS_WINNT
  380.     kbd_erase_to_end(0);
  381.     kbd_flush();
  382.     TTkclose();
  383. #if    DISP_IBMPC
  384.     /* If we don't reset to 80x25, parts of the shell-output will go
  385.      * astray.
  386.      */
  387.     closed = term.t_ncol != 80 || term.t_nrow != 25;
  388.     if (closed)
  389.         TTclose();
  390. #endif
  391. #if SYS_WINNT
  392. # if DISP_NTWIN
  393.     w32_system_winvile(line);
  394. # else
  395.     w32_system(line);
  396. # endif
  397.     w32_keybrd_reopen(pressret);
  398. #else
  399.     system(line);
  400.     TTkopen();
  401.     /* if we are interactive, pause here */
  402.     if (pressret) {
  403.         pressreturn();
  404.     }
  405. #endif
  406. #if    DISP_IBMPC
  407.     /* Reopen the display _after_ the prompt, to keep the shell-output
  408.      * in the same type of screen as the prompt.
  409.      */
  410.     if (closed)
  411.         TTopen();
  412. #endif
  413. #if DISP_NTCONS
  414.     ntcons_reopen();
  415. #endif
  416.     sgarbf = TRUE;
  417.     return AfterShell();
  418. #endif
  419. }
  420.  
  421. #if SYS_UNIX || SYS_MSDOS || SYS_VMS || SYS_OS2 || SYS_WINNT
  422. /*
  423.  * Pipe a one line command into a window
  424.  */
  425. /* ARGSUSED */
  426. int
  427. pipecmd(int f, int n)
  428. {
  429.     register BUFFER *bp;    /* pointer to buffer to zot */
  430.     register int    s;
  431.     char line[NLINE];    /* command line send to shell */
  432.  
  433.     /* get the command to pipe in */
  434.     hst_init('!');
  435.     s = ShellPrompt(&save_shell[!global_g_val(GMDSAMEBANGS)], line, -TRUE);
  436.     hst_flush();
  437.  
  438.     /* prompt ok? */
  439.     if (s != TRUE)
  440.         return s;
  441.  
  442.     /* take care of autowrite */
  443.     if (writeall(f,n,FALSE,FALSE,TRUE) != TRUE)
  444.         return FALSE;
  445.  
  446.  
  447. #if BEFORE
  448.     if (((s = ((bp = bfind(OUTPUT_BufName, 0)) != NULL)) == TRUE)
  449.      && ((s = popupbuff(bp)) == TRUE)
  450.      && ((s = swbuffer(bp)) == TRUE)
  451.      && ((s = readin(line, FALSE, bp, TRUE)) == TRUE))
  452.         set_rdonly(bp, line, MDVIEW);
  453.  
  454. #else
  455.     if ((s = ((bp = bfind(OUTPUT_BufName, 0)) != NULL)) != TRUE)
  456.         return s;
  457.     if ((s = popupbuff(bp)) != TRUE)
  458.         return s;
  459.     ch_fname(bp,line);
  460.     bp->b_active = FALSE; /* force a re-read */
  461.     if ((s = swbuffer_lfl(bp,FALSE)) != TRUE)
  462.         return s;
  463.     set_rdonly(bp, line, MDVIEW);
  464. #endif
  465.  
  466.     return (s);
  467. }
  468.  
  469. #else /* ! SYS_UNIX */
  470.  
  471. /*
  472.  * Pipe a one line command into a window
  473.  */
  474. int
  475. pipecmd(int f, int n)
  476. {
  477.     register int    s;    /* return status from CLI */
  478.     register WINDOW *wp;    /* pointer to new window */
  479.     register BUFFER *bp;    /* pointer to buffer to zot */
  480.     static char oline[NLINE];    /* command line send to shell */
  481.     char    line[NLINE];    /* command line send to shell */
  482.     WINDOW *ocurwp;        /* save the current window during delete */
  483.  
  484.     static char filnam[NSTRING] = "command";
  485.  
  486.     /* get the command to pipe in */
  487.     if ((s=mlreply("cmd: <", oline, NLINE)) != TRUE)
  488.         return(s);
  489.  
  490.     (void)strcpy(line,oline);
  491.  
  492.     /* get rid of the command output buffer if it exists */
  493.     if ((bp=find_b_name(OUTPUT_BufName)) != NULL) {
  494.         /* try to make sure we are off screen */
  495.         ocurwp = NULL;
  496.         for_each_window(wp) {
  497.             if (wp->w_bufp == bp) {
  498.                 if (curwp != wp) {
  499.                     ocurwp = curwp;
  500.                     curwp = wp;
  501.                 }
  502.                 delwind(FALSE, 1);
  503.                 if (ocurwp != NULL)
  504.                     curwp = ocurwp;
  505.                 break;
  506.             }
  507.         }
  508.         if (zotbuf(bp) != TRUE)
  509.             return(FALSE);
  510.     }
  511.  
  512.     if (s != TRUE)
  513.         return(s);
  514.  
  515.     /* split the current window to make room for the command output */
  516.     if (splitwind(FALSE, 1) == FALSE)
  517.         return(FALSE);
  518.  
  519.     /* and read the stuff in */
  520.     if (getfile(filnam, FALSE) == FALSE)
  521.         return(FALSE);
  522.  
  523.     /* overwrite its buffer name for consistency */
  524.     set_bname(curbp, OUTPUT_BufName);
  525.  
  526.     /* make this window in VIEW mode, update buffer's mode lines */
  527.     make_local_b_val(curwp->w_bufp,MDVIEW);
  528.     set_b_val(curwp->w_bufp,MDVIEW,TRUE);
  529.     curwp->w_flag |= WFMODE;
  530.  
  531. #if OPT_FINDERR
  532.     set_febuff(OUTPUT_BufName);
  533. #endif
  534.  
  535.     /* and get rid of the temporary file */
  536.     unlink(filnam);
  537.     return AfterShell();
  538. }
  539. #endif /* SYS_UNIX */
  540.  
  541. #if SYS_UNIX || SYS_MSDOS || (SYS_OS2 && CC_CSETPP) || SYS_WINNT
  542. /*
  543.  * write_data_to_pipe() exists to facilitate execution of a Win32 thread.
  544.  * All other host operating systems are simply victims.
  545.  */
  546. static void
  547. write_data_to_pipe(void *writefp)
  548. {
  549.     FILE *fw;
  550.     KILL *kp;       /* pointer into kill register */
  551.  
  552.     fw = (FILE *)writefp;
  553.     kregcirculate(FALSE);
  554.     kp = kbs[ukb].kbufh;
  555.     while (kp != NULL)
  556.     {
  557.         fwrite((char *)kp->d_chunk, 1, (SIZE_T)KbSize(ukb,kp), fw);
  558.         kp = kp->d_next;
  559.     }
  560.     ukb = 0;   /* was modified by kregciruclate() */
  561. #if SYS_UNIX && ! TEST_DOS_PIPES
  562.     (void)fflush(fw);
  563.     (void)fclose(fw);
  564.     ExitProgram (GOODEXIT);
  565.     /* NOTREACHED */
  566. #else
  567.     npflush();  /* fake multi-processing */
  568. #endif
  569. #if SYS_WINNT
  570.     /*
  571.      * If this function is invoked by a thread, then that thread (not
  572.      * the parent process) must close write pipe.  We generalize this
  573.      * function so that all Win32 execution environments (threaded or
  574.      * not) use the same code.
  575.      */
  576.     (void)fflush(fw);
  577.     (void)fclose(fw);
  578. #endif
  579. }
  580. #endif
  581.  
  582. /* run a region through an external filter, replace it with its output */
  583. int
  584. filterregion(void)
  585. {
  586. /* FIXX work on this for OS2, need inout_popen support, or named pipe? */
  587. #if SYS_UNIX || SYS_MSDOS || (SYS_OS2 && CC_CSETPP) || SYS_WINNT
  588.     static char oline[NLINE];   /* command line send to shell */
  589.     char    line[NLINE];    /* command line send to shell */
  590.     FILE *fr, *fw;
  591.     int s;
  592.  
  593.     /* get the filter name and its args */
  594.     if ((s=mlreply_no_bs("!", oline, NLINE)) != TRUE)
  595.         return(s);
  596.     (void)strcpy(line,oline);
  597.     if ((s = inout_popen(&fr, &fw, line)) != TRUE) {
  598.         mlforce("[Couldn't open pipe or command]");
  599.         return s;
  600.     }
  601.  
  602.     killregion();
  603.     if (!softfork())
  604.     {
  605. #if !(SYS_WINNT && defined(GMDW32PIPES))
  606.         write_data_to_pipe(fw);
  607. #else
  608.         /* This is a Win32 environment with compiled Win32 pipe support. */
  609.         if (global_g_val(GMDW32PIPES))
  610.         {
  611.             /*
  612.              * w32pipes mode enabled -- create child thread to blast
  613.              * region to write pipe.
  614.              */
  615.  
  616.             if (_beginthread(write_data_to_pipe, 0, fw) == -1)
  617.             {
  618.                 mlforce("[Can't create Win32 write pipe]");
  619.                 (void) fclose(fw);
  620.                 (void) npclose(fr);
  621.                 return (FALSE);
  622.             }
  623.         }
  624.         else
  625.         {
  626.             /*
  627.              * Single-threaded parent process writes region to pseudo
  628.              * write pipe (temp file).
  629.              */
  630.  
  631.             write_data_to_pipe(fw);
  632.         }
  633. #endif
  634.     }
  635. #if ! ((SYS_OS2 && CC_CSETPP) || SYS_WINNT)
  636.     (void)fclose(fw);
  637. #endif
  638.     DOT.l = lback(DOT.l);
  639.     s = ifile((char *)0,TRUE,fr);
  640.     npclose(fr);
  641.     (void)firstnonwhite(FALSE,1);
  642.     (void)setmark();
  643.     return s;
  644. #else
  645.     mlforce("[Region filtering not available -- try buffer filtering]");
  646.     return FALSE;
  647. #endif
  648. }
  649.  
  650. /*
  651.  * filter a buffer through an external DOS program
  652.  * this is obsolete, the filterregion code is better.
  653.  */
  654. /* ARGSUSED */
  655. int
  656. vile_filter(int f GCC_UNUSED, int n GCC_UNUSED)
  657. {
  658. #if !(SYS_UNIX||SYS_MSDOS || (SYS_OS2 && CC_CSETPP)) /* filterregion up above is better */
  659.     register int    s;    /* return status from CLI */
  660.     register BUFFER *bp;    /* pointer to buffer to zot */
  661.     static char oline[NLINE];    /* command line send to shell */
  662.     char    line[NLINE];    /* command line send to shell */
  663.     char tnam[NFILEN];    /* place to store real file name */
  664.     static char bname1[] = "fltinp";
  665. #if    SYS_UNIX
  666.     char    *t;
  667. #endif
  668.  
  669.     static char filnam1[] = "fltinp";
  670.     static char filnam2[] = "fltout";
  671.  
  672. #if    SYS_VMS
  673.     mlforce("[Not available under VMS]");
  674.     return(FALSE);
  675. #endif
  676.     /* get the filter name and its args */
  677.     if ((s=mlreply("cmd: |", oline, NLINE)) != TRUE)
  678.         return(s);
  679.     (void)strcpy(line,oline);
  680.  
  681.     /* setup the proper file names */
  682.     bp = curbp;
  683.     (void)strcpy(tnam, bp->b_fname);/* save the original name */
  684.     ch_fname(bp, bname1);        /* set it to our new one */
  685.  
  686.     /* write it out, checking for errors */
  687.     if (writeout(filnam1,curbp,TRUE,TRUE) != TRUE) {
  688.         mlforce("[Cannot write filter file]");
  689.         ch_fname(bp, tnam);
  690.         return(FALSE);
  691.     }
  692.  
  693. #if    SYS_MSDOS || SYS_OS2 || SYS_WINNT
  694.     (void)strcat(line," <fltinp >fltout");
  695.     bottomleft();
  696.     TTkclose();
  697.     system(line);
  698.     TTkopen();
  699.     sgarbf = TRUE;
  700.     s = TRUE;
  701. #endif
  702. #if    SYS_UNIX
  703.     bottomleft();
  704.     ttclean(TRUE);
  705.     if ((t = strchr(line, '|')) != 0) {
  706.         char    temp[NLINE];
  707.         (void)strcpy(temp, t);
  708.         (void)strcat(strcpy(t, " <fltinp"), temp);
  709.     } else {
  710.         (void)strcat(line, " <fltinp");
  711.     }
  712.     (void)strcat(line," >fltout");
  713.     system(line);
  714.     ttunclean();
  715.     TTflush();
  716.     sgarbf = TRUE;
  717.     s = TRUE;
  718. #endif
  719.  
  720.     /* on failure, escape gracefully */
  721.     if (s != TRUE || (readin(filnam2,FALSE,curbp,TRUE) == FALSE)) {
  722.         mlforce("[Execution failed]");
  723.         ch_fname(bp, tnam);
  724.         unlink(filnam1);
  725.         unlink(filnam2);
  726.         return(s);
  727.     }
  728.  
  729.     ch_fname(bp, tnam); /* restore name */
  730.  
  731.     b_set_changed(bp);    /* flag it as changed */
  732.     nounmodifiable(bp);    /* and it can never be "un-changed" */
  733.  
  734.     /* and get rid of the temporary file */
  735.     unlink(filnam1);
  736.     unlink(filnam2);
  737.     return AfterShell();
  738. #else
  739.     mlforce("[Buffer filtering not available -- use filter operator]");
  740.     return FALSE;
  741. #endif
  742. }
  743.  
  744. #if    SYS_VMS
  745. /*
  746.  * Run a command. The "cmd" is a pointer to a command string, or NULL if you
  747.  * want to run a copy of DCL in the subjob (this is how the standard routine
  748.  * lib$spawn works. You have to do wierd stuff with the terminal on the way in
  749.  * and the way out, because DCL does not want the channel to be in raw mode.
  750.  */
  751. int
  752. vms_system(register char *cmd)
  753. {
  754.     struct  dsc$descriptor  cdsc;
  755.     struct  dsc$descriptor  *cdscp;
  756.     long    status;
  757.     long    substatus;
  758.     long    iosb[2];
  759.  
  760.     status = sys$qiow(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  761.               oldmode, sizeof(oldmode), 0, 0, 0, 0);
  762.     if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  763.         return (FALSE);
  764.     cdscp = NULL;                /* Assume DCL.        */
  765.     if (cmd != NULL) {            /* Build descriptor.    */
  766.         cdsc.dsc$a_pointer = cmd;
  767.         cdsc.dsc$w_length  = strlen(cmd);
  768.         cdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  769.         cdsc.dsc$b_class   = DSC$K_CLASS_S;
  770.         cdscp = &cdsc;
  771.     }
  772.     status = lib$spawn(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
  773.     if (status != SS$_NORMAL)
  774.         substatus = status;
  775.     status = sys$qiow(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  776.               newmode, sizeof(newmode), 0, 0, 0, 0);
  777.     if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  778.         return (FALSE);
  779.     if ((substatus&STS$M_SUCCESS) == 0)    /* Command failed.    */
  780.         return (FALSE);
  781.     return AfterShell();
  782. }
  783. #endif
  784.