home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / less373.zip / lsystem.c < prev    next >
C/C++ Source or Header  |  2002-01-14  |  11KB  |  510 lines

  1. /*
  2.  * Copyright (C) 1984-2000  Mark Nudelman
  3.  *
  4.  * You may distribute under the terms of either the GNU General Public
  5.  * License or the Less License, as specified in the README file.
  6.  *
  7.  * For more information about less, or for information on how to 
  8.  * contact the author, see the README file.
  9.  */
  10.  
  11.  
  12. /*
  13.  * Routines to execute other programs.
  14.  * Necessarily very OS dependent.
  15.  */
  16.  
  17. #include "less.h"
  18. #include <signal.h>
  19. #include "position.h"
  20.  
  21. #if MSDOS_COMPILER
  22. #include <dos.h>
  23. #ifdef _MSC_VER
  24. #include <direct.h>
  25. #define setdisk(n) _chdrive((n)+1)
  26. #else
  27. #include <dir.h>
  28. #endif
  29. #endif
  30.  
  31. extern int screen_trashed;
  32. extern IFILE curr_ifile;
  33.  
  34.  
  35. #if HAVE_SYSTEM
  36.  
  37. /*
  38.  * Pass the specified command to a shell to be executed.
  39.  * Like plain "system()", but handles resetting terminal modes, etc.
  40.  */
  41.     public void
  42. lsystem(cmd, donemsg)
  43.     char *cmd;
  44.     char *donemsg;
  45. {
  46.     register int inp;
  47. #if HAVE_SHELL
  48.     register char *shell;
  49.     register char *p;
  50. #endif
  51.     IFILE save_ifile;
  52. #if MSDOS_COMPILER
  53.     char cwd[FILENAME_MAX+1];
  54. #endif
  55.  
  56.     /*
  57.      * Print the command which is to be executed,
  58.      * unless the command starts with a "-".
  59.      */
  60.     if (cmd[0] == '-')
  61.         cmd++;
  62.     else
  63.     {
  64.         clear_bot();
  65.         putstr("!");
  66.         putstr(cmd);
  67.         putstr("\n");
  68.     }
  69.  
  70. #if MSDOS_COMPILER
  71.     /*
  72.      * Working directory is global on MSDOS.
  73.      * The child might change the working directory, so we
  74.      * must save and restore CWD across calls to "system",
  75.      * or else we won't find our file when we return and
  76.      * try to "reedit_ifile" it.
  77.      */
  78.     getcwd(cwd, FILENAME_MAX);
  79. #endif
  80.  
  81.     /*
  82.      * Close the current input file.
  83.      */
  84.     save_ifile = save_curr_ifile();
  85.     (void) edit_ifile(NULL_IFILE);
  86.  
  87.     /*
  88.      * De-initialize the terminal and take out of raw mode.
  89.      */
  90.     deinit();
  91.     flush();    /* Make sure the deinit chars get out */
  92.     raw_mode(0);
  93. #if MSDOS_COMPILER==WIN32C
  94.     close_getchr();
  95. #endif
  96.  
  97.     /*
  98.      * Restore signals to their defaults.
  99.      */
  100.     init_signals(0);
  101.  
  102. #if HAVE_DUP
  103.     /*
  104.      * Force standard input to be the user's terminal
  105.      * (the normal standard input), even if less's standard input 
  106.      * is coming from a pipe.
  107.      */
  108.     inp = dup(0);
  109.     close(0);
  110. #if OS2
  111.     /* The __open() system call translates "/dev/tty" to "con". */
  112.     if (__open("/dev/tty", OPEN_READ) < 0)
  113. #else
  114.     if (open("/dev/tty", OPEN_READ) < 0)
  115. #endif
  116.         dup(inp);
  117. #endif
  118.  
  119.     /*
  120.      * Pass the command to the system to be executed.
  121.      * If we have a SHELL environment variable, use
  122.      * <$SHELL -c "command"> instead of just <command>.
  123.      * If the command is empty, just invoke a shell.
  124.      */
  125. #if HAVE_SHELL
  126.     p = NULL;
  127.     if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
  128.     {
  129.         if (*cmd == '\0')
  130.             p = save(shell);
  131.         else
  132.         {
  133.             char *esccmd = shell_quote(cmd);
  134.             if (esccmd != NULL)
  135.             {
  136.                 p = (char *) ecalloc(strlen(shell) +
  137.                     strlen(esccmd) + 5, sizeof(char));
  138.                 sprintf(p, "%s %s %s", shell, shell_coption(), esccmd);
  139.                 free(esccmd);
  140.             }
  141.         }
  142.     }
  143.     if (p == NULL)
  144.     {
  145.         if (*cmd == '\0')
  146.             p = save("sh");
  147.         else
  148.             p = save(cmd);
  149.     }
  150.     system(p);
  151.     free(p);
  152. #else
  153. #if MSDOS_COMPILER==DJGPPC
  154.     /*
  155.      * Make stdin of the child be in cooked mode.
  156.      */
  157.     setmode(0, O_TEXT);
  158.     /*
  159.      * We don't need to catch signals of the child (it
  160.      * also makes trouble with some DPMI servers).
  161.      */
  162.     __djgpp_exception_toggle();
  163.       system(cmd);
  164.     __djgpp_exception_toggle();
  165. #else
  166.     system(cmd);
  167. #endif
  168. #endif
  169.  
  170. #if HAVE_DUP
  171.     /*
  172.      * Restore standard input, reset signals, raw mode, etc.
  173.      */
  174.     close(0);
  175.     dup(inp);
  176.     close(inp);
  177. #endif
  178.  
  179. #if MSDOS_COMPILER==WIN32C
  180.     open_getchr();
  181. #endif
  182.     init_signals(1);
  183.     raw_mode(1);
  184.     if (donemsg != NULL)
  185.     {
  186.         putstr(donemsg);
  187.         putstr("  (press RETURN)");
  188.         get_return();
  189.         putchr('\n');
  190.         flush();
  191.     }
  192.     init();
  193.     screen_trashed = 1;
  194.  
  195. #if MSDOS_COMPILER
  196.     /*
  197.      * Restore the previous directory (possibly
  198.      * changed by the child program we just ran).
  199.      */
  200.     chdir(cwd);
  201. #if MSDOS_COMPILER != DJGPPC
  202.     /*
  203.      * Some versions of chdir() don't change to the drive
  204.      * which is part of CWD.  (DJGPP does this in chdir.)
  205.      */
  206.     if (cwd[1] == ':')
  207.     {
  208.         if (cwd[0] >= 'a' && cwd[0] <= 'z')
  209.             setdisk(cwd[0] - 'a');
  210.         else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
  211.             setdisk(cwd[0] - 'A');
  212.     }
  213. #endif
  214. #endif
  215.  
  216.     /*
  217.      * Reopen the current input file.
  218.      */
  219.     reedit_ifile(save_ifile);
  220.  
  221. #if defined(SIGWINCH) || defined(SIGWIND)
  222.     /*
  223.      * Since we were ignoring window change signals while we executed
  224.      * the system command, we must assume the window changed.
  225.      * Warning: this leaves a signal pending (in "sigs"),
  226.      * so psignals() should be called soon after lsystem().
  227.      */
  228.     winch(0);
  229. #endif
  230. }
  231.  
  232. #endif
  233.  
  234. #if PIPEC
  235.  
  236. /*
  237.  * Pipe a section of the input file into the given shell command.
  238.  * The section to be piped is the section "between" the current
  239.  * position and the position marked by the given letter.
  240.  *
  241.  * If the mark is after the current screen, the section between
  242.  * the top line displayed and the mark is piped.
  243.  * If the mark is before the current screen, the section between
  244.  * the mark and the bottom line displayed is piped.
  245.  * If the mark is on the current screen, or if the mark is ".",
  246.  * the whole current screen is piped.
  247.  */
  248.     public int
  249. pipe_mark(c, cmd)
  250.     int c;
  251.     char *cmd;
  252. {
  253.     POSITION mpos, tpos, bpos;
  254.  
  255.     /*
  256.      * mpos = the marked position.
  257.      * tpos = top of screen.
  258.      * bpos = bottom of screen.
  259.      */
  260.     mpos = markpos(c);
  261.     if (mpos == NULL_POSITION)
  262.         return (-1);
  263.     tpos = position(TOP);
  264.     if (tpos == NULL_POSITION)
  265.         tpos = ch_zero();
  266.     bpos = position(BOTTOM);
  267.  
  268.      if (c == '.') 
  269.          return (pipe_data(cmd, tpos, bpos));
  270.      else if (mpos <= tpos)
  271.          return (pipe_data(cmd, mpos, bpos));
  272.      else if (bpos == NULL_POSITION)
  273.          return (pipe_data(cmd, tpos, bpos));
  274.      else
  275.          return (pipe_data(cmd, tpos, mpos));
  276. }
  277.  
  278. /*
  279.  * Create a pipe to the given shell command.
  280.  * Feed it the file contents between the positions spos and epos.
  281.  */
  282.     public int
  283. pipe_data(cmd, spos, epos)
  284.     char *cmd;
  285.     POSITION spos;
  286.     POSITION epos;
  287. {
  288.     register FILE *f;
  289.     register int c;
  290.     extern FILE *popen();
  291.  
  292.     /*
  293.      * This is structured much like lsystem().
  294.      * Since we're running a shell program, we must be careful
  295.      * to perform the necessary deinitialization before running
  296.      * the command, and reinitialization after it.
  297.      */
  298.     if (ch_seek(spos) != 0)
  299.     {
  300.         error("Cannot seek to start position", NULL_PARG);
  301.         return (-1);
  302.     }
  303.  
  304.     if ((f = popen(cmd, "w")) == NULL)
  305.     {
  306.         error("Cannot create pipe", NULL_PARG);
  307.         return (-1);
  308.     }
  309.     clear_bot();
  310.     putstr("!");
  311.     putstr(cmd);
  312.     putstr("\n");
  313.  
  314.     deinit();
  315.     flush();
  316.     raw_mode(0);
  317.     init_signals(0);
  318. #if MSDOS_COMPILER==WIN32C
  319.     close_getchr();
  320. #endif
  321. #ifdef SIGPIPE
  322.     LSIGNAL(SIGPIPE, SIG_IGN);
  323. #endif
  324.  
  325.     c = EOI;
  326.     while (epos == NULL_POSITION || spos++ <= epos)
  327.     {
  328.         /*
  329.          * Read a character from the file and give it to the pipe.
  330.          */
  331.         c = ch_forw_get();
  332.         if (c == EOI)
  333.             break;
  334.         if (putc(c, f) == EOF)
  335.             break;
  336.     }
  337.  
  338.     /*
  339.      * Finish up the last line.
  340.      */
  341.      while (c != '\n' && c != EOI ) 
  342.      {
  343.          c = ch_forw_get();
  344.          if (c == EOI)
  345.              break;
  346.          if (putc(c, f) == EOF)
  347.              break;
  348.      }
  349.  
  350.     pclose(f);
  351.  
  352. #ifdef SIGPIPE
  353.     LSIGNAL(SIGPIPE, SIG_DFL);
  354. #endif
  355. #if MSDOS_COMPILER==WIN32C
  356.     open_getchr();
  357. #endif
  358.     init_signals(1);
  359.     raw_mode(1);
  360.     init();
  361.     screen_trashed = 1;
  362. #if defined(SIGWINCH) || defined(SIGWIND)
  363.     /* {{ Probably don't need this here. }} */
  364.     winch(0);
  365. #endif
  366.     return (0);
  367. }
  368.  
  369. #endif
  370.  
  371. #ifdef _OSK
  372. /*
  373.  *    Popen, and Pclose, for OS-9.
  374.  *
  375.  *    Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim,
  376.  *                                        Ulli Dessauer, Germering and
  377.  *                                        Reimer Mellin, Muenchen
  378.  *                                        (W-Germany)
  379.  *
  380.  *    These functions can be copied and distributed freely for any
  381.  *    non-commercial purposes.  It can only be incorporated into
  382.  *    commercial software with the written permission of the authors.
  383.  *
  384.  *    TOP-specific code stripped out and adapted for less by M.Gregorie, 1996
  385.  *
  386.  *    address:    Wolfgang Ocker
  387.  *                Lochhauserstrasse 35a
  388.  *                D-8039 Puchheim
  389.  *                West Germany
  390.  *
  391.  *    e-mail:     weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP
  392.  *                pyramid!tmpmbx!recco!weo
  393.  *                pyramid!tmpmbx!nitmar!ud
  394.  *                pyramid!tmpmbx!ramsys!ram
  395.  *
  396.  *                Martin Gregorie
  397.  *                10 Sadlers Mead
  398.  *                Harlow
  399.  *                Essex, CM18 6HG
  400.  *                U.K.
  401.  *
  402.  *                gregorie@logica.com
  403.  */
  404. #include <strings.h>
  405. #include <errno.h>
  406. extern char **environ;
  407. extern char *getenv();
  408. extern int  os9forkc();
  409. static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0,
  410.                             0, 0, 0, 0, 0, 0, 0, 0,
  411.                             0, 0, 0, 0, 0, 0, 0, 0,
  412.                             0, 0, 0, 0, 0, 0, 0, 0 };
  413. /* 
  414.  * p o p e n
  415.  */
  416. FILE *popen(name, mode)
  417.     char *name;
  418.     char *mode;
  419. {
  420.     int          fd, fd2, fdsav, pid;
  421.     static char  *argv[] = {NULL, NULL, NULL };
  422.     static char  cmd[200];
  423.     static char  cmd_path[200];
  424.     char         *cp;
  425.     char         *shell;
  426.     FILE         *r;
  427.     if ((shell = getenv("SHELL")) == NULL)
  428.         return(NULL);
  429.     cp = name;
  430.     while (*cp == ' ')
  431.         cp++;
  432.     strcpy(cmd_path, cp);
  433.     if (cp = index(cmd_path, ' '))
  434.         *cp++ = '\0';
  435.     strcpy(cmd, "ex ");
  436.     strcat(cmd, cmd_path);
  437.     if (cp)
  438.     {
  439.         strcat(cmd, " ");
  440.         strcat(cmd, cp);
  441.     }
  442.     argv[0] = shell;
  443.     argv[1] = cmd;
  444.     /*
  445.          mode is "r" (stdout) or "w" (stdin)
  446.     */
  447.     switch(mode[0])
  448.     {
  449.         case 'w':   fd = 0;
  450.                     break;
  451.         case 'r':   fd = 1;
  452.                     break;
  453.         default:    return(NULL);
  454.     }
  455.     if (fd == 1)
  456.         fflush(stdout);
  457.     fdsav = dup(fd);
  458.     close(fd);
  459.  
  460.     creat("/pipe", S_IWRITE+S_IREAD);
  461.     pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3);
  462.     fd2 = dup(fd);
  463.     close(fd);
  464.     dup(fdsav);
  465.     close(fdsav);
  466.     if (pid > 0)
  467.     {
  468.         pids[fd2] = pid;
  469.         r = fdopen(fd2, mode);
  470.     }
  471.     else
  472.     {
  473.         close(fd2);
  474.         r = NULL;
  475.     }
  476.     return(r);
  477. }
  478.  
  479. /*
  480.  * p c l o s e
  481.  */
  482. int pclose(fp)
  483.     FILE *fp;
  484. {
  485.     unsigned int    status;
  486.     int             pid;
  487.     int             fd,
  488.                     i;
  489.     fd = fileno(fp);
  490.     if (pids[fd] == 0)
  491.         return(-1);
  492.     fflush(fp);
  493.     fclose(fp);
  494.     while ((pid = wait(&status)) != -1)
  495.         if (pid == pids[fd])
  496.             break;
  497.         else
  498.             for (i = 0; i < _NFILE; i++)
  499.                 if (pids[i] == pid)
  500.                 {
  501.                     pids[i] = 0;
  502.                     break;
  503.                 }
  504.     if (pid == -1)
  505.         status = -1;
  506.     pids[fd] = 0;
  507.     return(status);
  508. }
  509. #endif /* _OSK */
  510.