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

  1. /*    npopen:  like popen, but grabs stderr, too
  2.  *        written by John Hutchinson, heavily modified by Paul Fox
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/npopen.c,v 1.64 1998/05/19 11:04:47 cmorgan Exp $
  5.  *
  6.  */
  7.  
  8. #include "estruct.h"
  9. #include "edef.h"
  10.  
  11. #if ! TEST_DOS_PIPES
  12.  
  13. #if SYS_UNIX || SYS_OS2
  14.  
  15. /*
  16.  * For OS/2 implementations of inout_popen(), npflush(), and npclose(),
  17.  * see "os2pipe.c".
  18.  */
  19.  
  20. #if SYS_OS2
  21. #include <process.h>
  22. #endif
  23.  
  24. #if OPT_EVAL
  25. #define    user_SHELL()    gtenv("shell")
  26. #else
  27. #define    user_SHELL()    getenv("SHELL")
  28. #endif
  29.  
  30. #if SYS_OS2_EMX
  31. #define SHELL_C "/c"
  32. #else
  33. #define SHELL_C "-c"
  34. #endif
  35.  
  36. #define R 0
  37. #define W 1
  38.  
  39. #if SYS_UNIX
  40. static int pipe_pid;
  41. #endif
  42.  
  43. static void exec_sh_c(char *cmd);
  44.  
  45. FILE *
  46. npopen (char *cmd, const char *type)
  47. {
  48.     FILE *ff;
  49.  
  50.     if (*type != 'r' && *type != 'w')
  51.         return NULL;
  52.  
  53.     if (*type == 'r') {
  54.           if (inout_popen(&ff, (FILE **)0, cmd) != TRUE)
  55.             return NULL;
  56.         return ff;
  57.     } else {
  58.         if (inout_popen((FILE **)0, &ff, cmd) != TRUE)
  59.             return NULL;
  60.         return ff;
  61.     }
  62. }
  63. #endif /* SYS_UNIX || SYS_OS2 */
  64.  
  65. #if SYS_UNIX
  66.  
  67. int
  68. inout_popen(FILE **fr, FILE **fw, char *cmd)
  69. {
  70.     int rp[2];
  71.     int wp[2];
  72.  
  73.     if (pipe(rp))
  74.         return FALSE;
  75.     if (pipe(wp))
  76.         return FALSE;
  77.  
  78.     pipe_pid = softfork();
  79.     if (pipe_pid < 0)
  80.         return FALSE;
  81.  
  82.     if (pipe_pid) { /* parent */
  83.  
  84.         if (fr) {
  85.             *fr = fdopen (rp[0], "r");
  86.             if (*fr == NULL) {
  87.                 (void)fprintf(stderr,"fdopen r failed\n");
  88.                 abort();
  89.             }
  90.         } else {
  91.             (void)close(rp[0]);
  92.         }
  93.         (void) close (rp[1]);
  94.  
  95.         if (fw) {
  96.             *fw = fdopen (wp[1], "w");
  97.             if (*fw == NULL) {
  98.                 (void)fprintf(stderr,"fdopen w failed\n");
  99.                 abort();
  100.             }
  101.         } else {
  102.             (void)close(wp[1]);
  103.         }
  104.         (void) close (wp[0]);
  105.         return TRUE;
  106.  
  107.     } else {            /* child */
  108.  
  109.         if (fw) {
  110.             (void)close (0);
  111.             if (dup (wp[0]) != 0) {
  112.                 (void)write(2,"dup 0 failed\r\n",15);
  113.                 exit(-1);
  114.             }
  115.         }
  116.         (void) close (wp[1]);
  117.         if (fr) {
  118.             (void)close (1);
  119.             if (dup (rp[1]) != 1) {
  120.                 (void)write(2,"dup 1 failed\r\n",15);
  121.                 exit(-1);
  122.             }
  123.             (void)close (2);
  124.             if (dup (rp[1]) != 2) {
  125.                 (void)write(1,"dup 2 failed\r\n",15);
  126.                 exit(-1);
  127.             }
  128.         } else {
  129.             (void) close (rp[1]);
  130.         }
  131.         (void) close (rp[0]);
  132.         exec_sh_c(cmd);
  133.  
  134.     }
  135.     return TRUE;
  136. }
  137.  
  138. void
  139. npclose (FILE *fp)
  140. {
  141.     int child;
  142.     (void)fflush(fp);
  143.     (void)fclose(fp);
  144.     while ((child = wait ((int *)0)) != pipe_pid) {
  145.         if (child < 0 && errno == EINTR) {
  146.             (void) kill (SIGKILL, pipe_pid);
  147.         }
  148.     }
  149. }
  150.  
  151. static void
  152. exec_sh_c(char *cmd)
  153. {
  154.     static char bin_sh[] = "/bin/sh";
  155.     char *sh, *shname;
  156.     int i;
  157.  
  158. #ifndef NOFILE
  159. # define NOFILE 20
  160. #endif
  161.     /* Make sure there are no upper inherited file descriptors */
  162.     for (i = 3; i < NOFILE; i++)
  163.         (void) close (i);
  164.  
  165.     if ((sh = user_SHELL()) == NULL || *sh == EOS) {
  166.         sh = bin_sh;
  167.         shname = pathleaf(sh);
  168.     } else {
  169.         shname = last_slash(sh);
  170.         if (shname == NULL) {
  171.             shname = sh;
  172.         } else {
  173.             shname++;
  174.             if (*shname == EOS)
  175.                 shname = sh;
  176.         }
  177.     }
  178.  
  179.     if (cmd)
  180.         (void) execlp (sh, shname, SHELL_C, cmd, 0);
  181.     else
  182.         (void) execlp (sh, shname, 0);
  183.     (void)write(2,"exec failed\r\n",14);
  184.     exit (-1);
  185. }
  186.  
  187.  
  188. #if LATER
  189.  
  190. int shellstatus;
  191.  
  192. static int
  193. process_exit_status(int status)
  194. {
  195.     if (WIFSIGNALED(status))
  196.     return (128 + WTERMSIG(status));
  197.     else if (!WIFSTOPPED(status))
  198.     return (WEXITSTATUS(status));
  199.     else
  200.     return (EXECUTION_SUCCESS);
  201. }
  202.  
  203. #endif /* LATER */
  204.  
  205.  
  206. int
  207. system_SHELL(char *cmd)
  208. {
  209.     int cpid;
  210.  
  211.     cpid = softfork();
  212.     if (cpid < 0) {
  213.         (void)write(2,"cannot fork\n",13);
  214.         return cpid;
  215.     }
  216.  
  217.     if (cpid) { /* parent */
  218.         int child;
  219.         int status;
  220.         beginDisplay();
  221.         while ((child = wait (&status)) != cpid) {
  222.             if (child < 0 && errno == EINTR) {
  223.                 (void) kill (SIGKILL, cpid);
  224.             }
  225.         }
  226.         endofDisplay();
  227. #if LATER
  228.         shellstatus = process_exit_status(status);
  229. #endif
  230.         return 0;
  231.     } else {
  232.         exec_sh_c(cmd);
  233.         (void)write(2,"cannot exec\n",13);
  234.         return -1;
  235.     }
  236.  
  237. }
  238.  
  239. int
  240. softfork(void)
  241. {
  242.     /* Try & fork 5 times, backing off 1, 2, 4 .. seconds each try */
  243.     int fpid;
  244.     int tries = 5;
  245.     unsigned slp = 1;
  246.  
  247.     while ((fpid = fork ()) < 0) {
  248.         if (--tries == 0)
  249.             return -1;
  250.         (void) sleep (slp);
  251.         slp <<= 1;
  252.     }
  253.     return fpid;
  254. }
  255.  
  256. #endif  /* SYS_UNIX */
  257. #endif     /* TEST_DOS_PIPES */
  258.  
  259. #if SYS_MSDOS || SYS_WIN31 || SYS_WINNT || TEST_DOS_PIPES
  260. #include <fcntl.h>        /* defines O_RDWR */
  261. #if ! TEST_DOS_PIPES
  262. #include <io.h>            /* defines 'dup2()', etc. */
  263. #endif
  264.  
  265. #if SYS_WIN31
  266. /* FIXME: is it possible to execute a DOS program from Windows? */
  267. int    system(const char *command) { return (-1); }
  268. #endif
  269.  
  270. static    void    deleteTemp (void);
  271.  
  272. static    FILE **    myPipe;        /* current pipe-file pointer */
  273. static    FILE **    myWrtr;        /* write-pipe pointer */
  274. static    char *    myName[2];    /* name of temporary file for pipe */
  275. static    char *    myCmds;        /* command to execute on read-pipe */
  276. static    int    myRval;        /* return-value of 'system()' */
  277.  
  278. static int
  279. createTemp (char *type)
  280. {
  281.     register int n = (*type == 'r');
  282.     register int fd;
  283.  
  284. #if CC_WATCOM || CC_TURBO
  285.     myName[n] = tmpnam((char *)0);
  286. #else
  287.     myName[n] = tempnam(TMPDIR, type);
  288. #endif
  289.     if (myName[n] == 0)
  290.         return -1;
  291.     (void)close(creat(myName[n], 0666));
  292.     if ((fd = open(myName[n], O_RDWR)) < 0) {
  293.         deleteTemp();
  294.         return -1;
  295.     }
  296.     return fd;
  297. }
  298.  
  299. static void
  300. deleteTemp (void)
  301. {
  302.     register int n;
  303.  
  304.     for (n = 0; n < 2; n++) {
  305.         if (myName[n] != 0) {
  306.             (void)unlink(myName[n]);
  307.             FreeAndNull(myName[n]);
  308.         }
  309.     }
  310. }
  311.  
  312. static void
  313. closePipe(FILE ***pp)
  314. {
  315.     if (*pp != 0) {
  316.         if (**pp != 0) {
  317.             (void)fclose(**pp);
  318.             **pp = 0;
  319.         }
  320.         *pp = 0;
  321.     }
  322. }
  323.  
  324. static FILE *
  325. readPipe(const char *cmd, int in, int out)
  326. {
  327.     int old0, old1, old2;
  328.  
  329.     TRACE(("readPipe(cmd='%s', in=%d, out=%d)\n", cmd, in, out))
  330.  
  331.     TTkclose();    /* close the keyboard in case of error */
  332.  
  333.     /* save and redirect stdin, stdout, and stderr */
  334.     old1 = dup(1);
  335.     old2 = dup(2);
  336.  
  337.     if (in >= 0)
  338.     {
  339.         old0 = dup(0);
  340.         dup2(in, 0);
  341.     }
  342.     dup2(out, 1);
  343.     dup2(out, 2);
  344.  
  345. #if SYS_WINNT
  346.     myRval = w32_system(cmd);
  347. #else
  348.     myRval = system(cmd);
  349. #endif
  350.  
  351.     /* restore old std... */
  352.     if (in >= 0)
  353.     {
  354.         dup2(old0, 0); close(old0);
  355.     }
  356.     dup2(old1, 1); close(old1);
  357.     dup2(old2, 2); close(old2);
  358.  
  359.     TTkopen();    /* reopen the keyboard */
  360.  
  361.     /* rewind command output */
  362.     lseek(out, 0L, 0);
  363.     return fdopen(out, "r");
  364. }
  365.  
  366. #if SYS_MSDOS
  367. static void
  368. writePipe(const char *cmd)
  369. {
  370.     int old0;
  371.  
  372.     TRACE(("writePipe(cmd='%s')\n", cmd))
  373.  
  374.     TTkclose();    /* close the keyboard in case of error */
  375.  
  376.     (void)fclose(*myWrtr);
  377.     *myWrtr = fopen(myName[0], "r");
  378.  
  379.     old0 = dup(0);
  380.     dup2(fileno(*myWrtr), 0);
  381.  
  382.     myRval = system(cmd);
  383.  
  384.     /* restore old std... */
  385.     dup2(old0, 0); close(old0);
  386.  
  387.     TTkopen();    /* reopen the keyboard */
  388. }
  389. #endif
  390.  
  391. FILE *
  392. npopen (char *cmd, const char *type)
  393. {
  394.     FILE *ff = 0;
  395.  
  396.     if (*type == 'r') {
  397.         (void)inout_popen(&ff, (FILE **)0, cmd);
  398.     } else if (*type == 'w') {
  399.         (void)inout_popen((FILE **)0, &ff, cmd);
  400.     }
  401.     return ff;
  402. }
  403.  
  404. /*
  405.  * Create pipe with either write- _or_ read-semantics.  Fortunately for us,
  406.  * on SYS_MSDOS, we don't need both at the same instant.
  407.  */
  408. int
  409. inout_popen(FILE **fr, FILE **fw, char *cmd)
  410. {
  411.     char        *type = (fw != 0) ? "w" : "r";
  412.     static FILE    *pp = 0;
  413.     int        fd;
  414.  
  415.     TRACE(("inout_popen(fr=%p, fw=%p, cmd='%s')\n", fr, fw, cmd))
  416. #ifdef GMDW32PIPES
  417.     if (global_g_val(GMDW32PIPES))
  418.         return (w32_inout_popen(fr, fw, cmd));
  419. #endif
  420.  
  421.     /* Create the file that will hold the pipe's content */
  422.     if ((fd = createTemp(type)) >= 0) {
  423.         if (fw == 0) {
  424.             *fr = pp = readPipe(cmd, -1, fd);
  425.             myWrtr = 0;
  426.             myPipe = &pp;  /* Can't assign "fr", may be stack-based. */
  427.             myCmds = 0;
  428.         } else {
  429.             *fw = pp = fdopen(fd, type);
  430.             myPipe = fr;
  431.             myWrtr = &pp;  /* Can't assign "fw", may be stack-based. */
  432.             myCmds = strmalloc(cmd);
  433.         }
  434.     }
  435.     return (pp != 0);
  436. }
  437.  
  438. /*
  439.  * If we were writing to a pipe, invoke the read-process with stdin set to the
  440.  * temporary-file.  This is used in the filter-buffer code, which needs both
  441.  * read- and write-pipes.
  442.  */
  443. void
  444. npflush (void)
  445. {
  446. #ifdef GMDW32PIPES
  447.     if (global_g_val(GMDW32PIPES))
  448.         return;
  449. #endif
  450.     if (myCmds != 0) {
  451.         if (myWrtr != 0) {
  452.             (void)fflush(*myWrtr);
  453. #if UNUSED
  454.             (void)fclose(*myWrtr);
  455.             *myWrtr = fopen(myName[0], "r");
  456. #endif
  457.             rewind(*myWrtr);
  458.             *myPipe = readPipe(myCmds, fileno(*myWrtr), createTemp("r"));
  459.         }
  460.         FreeAndNull(myCmds);
  461.     }
  462. }
  463.  
  464. void
  465. npclose (FILE *fp)
  466. {
  467. #ifdef GMDW32PIPES
  468.     if (global_g_val(GMDW32PIPES))
  469.     {
  470.         w32_npclose(fp);
  471.         return;
  472.     }
  473. #endif
  474. #if SYS_MSDOS
  475.     if (myWrtr != 0 && myPipe == 0)
  476.         writePipe(myCmds);
  477. #endif
  478.     closePipe(&myWrtr);
  479.     closePipe(&myPipe);
  480.     deleteTemp();
  481. }
  482.  
  483. int
  484. softfork(void)    /* dummy function to make filter-region work */
  485. {
  486.     return 0;
  487. }
  488.  
  489. #if TEST_DOS_PIPES
  490. int
  491. system_SHELL(char *cmd)    /* dummy function */
  492. {
  493.     return 0;
  494. }
  495. #endif /* TEST_DOS_PIPES */
  496. #endif /* SYS_MSDOS */
  497.