home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / less_332.lzh / less_332 / lsystem.c < prev    next >
Text File  |  1998-03-03  |  11KB  |  512 lines

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