home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / less-321-src.tgz / tar.out / fsf / less / lsystem.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  397 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. #endif
  40.  
  41. extern int screen_trashed;
  42. extern IFILE curr_ifile;
  43.  
  44.  
  45. #if HAVE_SYSTEM
  46.  
  47. /*
  48.  * Pass the specified command to a shell to be executed.
  49.  * Like plain "system()", but handles resetting terminal modes, etc.
  50.  */
  51.     public void
  52. lsystem(cmd, donemsg)
  53.     char *cmd;
  54.     char *donemsg;
  55. {
  56.     register int inp;
  57.     register char *shell;
  58.     register char *p;
  59.     IFILE save_ifile;
  60.  
  61.     /*
  62.      * Print the command which is to be executed,
  63.      * unless the command starts with a "-".
  64.      */
  65.     if (cmd[0] == '-')
  66.         cmd++;
  67.     else
  68.     {
  69.         clear_bot();
  70.         putstr("!");
  71.         putstr(cmd);
  72.         putstr("\n");
  73.     }
  74.  
  75.     /*
  76.      * Close the current input file.
  77.      */
  78.     save_ifile = curr_ifile;
  79.     (void) edit_ifile(NULL_IFILE);
  80.  
  81.     /*
  82.      * De-initialize the terminal and take out of raw mode.
  83.      */
  84.     deinit();
  85.     flush();    /* Make sure the deinit chars get out */
  86.     raw_mode(0);
  87.  
  88.     /*
  89.      * Restore signals to their defaults.
  90.      */
  91.     init_signals(0);
  92.  
  93. #if HAVE_DUP
  94.     /*
  95.      * Force standard input to be the user's terminal
  96.      * (the normal standard input), even if less's standard input 
  97.      * is coming from a pipe.
  98.      */
  99.     inp = dup(0);
  100.     close(0);
  101.     if (OPEN_TTYIN() < 0)
  102.         dup(inp);
  103. #endif
  104.  
  105.     /*
  106.      * Pass the command to the system to be executed.
  107.      * If we have a SHELL environment variable, use
  108.      * <$SHELL -c "command"> instead of just <command>.
  109.      * If the command is empty, just invoke a shell.
  110.      */
  111. #if HAVE_SHELL
  112.     p = NULL;
  113.     if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
  114.     {
  115.         if (*cmd == '\0')
  116.             p = save(shell);
  117.         else
  118.         {
  119.             p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, 
  120.                     sizeof(char));
  121.             sprintf(p, "%s -c \"%s\"", shell, cmd);
  122.         }
  123.     }
  124.     if (p == NULL)
  125.     {
  126.         if (*cmd == '\0')
  127.             p = save("sh");
  128.         else
  129.             p = save(cmd);
  130.     }
  131.  
  132.     system(p);
  133.     free(p);
  134. #else
  135.     system(cmd);
  136. #endif
  137.  
  138. #if HAVE_DUP
  139.     /*
  140.      * Restore standard input, reset signals, raw mode, etc.
  141.      */
  142.     close(0);
  143.     dup(inp);
  144.     close(inp);
  145. #endif
  146.  
  147.     init_signals(1);
  148.     raw_mode(1);
  149.     if (donemsg != NULL)
  150.     {
  151.         putstr(donemsg);
  152.         putstr("  (press RETURN)");
  153.         get_return();
  154.     }
  155.     init();
  156.     screen_trashed = 1;
  157.  
  158.     /*
  159.      * Reopen the current input file.
  160.      */
  161.     reedit_ifile(save_ifile);
  162.  
  163. #if defined(SIGWINCH) || defined(SIGWIND)
  164.     /*
  165.      * Since we were ignoring window change signals while we executed
  166.      * the system command, we must assume the window changed.
  167.      * Warning: this leaves a signal pending (in "sigs"),
  168.      * so psignals() should be called soon after lsystem().
  169.      */
  170.     winch(0);
  171. #endif
  172. }
  173.  
  174. #endif
  175.  
  176. #if PIPEC
  177.  
  178. /*
  179.  * Pipe a section of the input file into the given shell command.
  180.  * The section to be piped is the section "between" the current
  181.  * position and the position marked by the given letter.
  182.  *
  183.  * If the mark is after the current screen, the section between
  184.  * the top line displayed and the mark is piped.
  185.  * If the mark is before the current screen, the section between
  186.  * the mark and the bottom line displayed is piped.
  187.  * If the mark is on the current screen, or if the mark is ".",
  188.  * the whole current screen is piped.
  189.  */
  190.     public int
  191. pipe_mark(c, cmd)
  192.     int c;
  193.     char *cmd;
  194. {
  195.     POSITION mpos, tpos, bpos;
  196.  
  197.     /*
  198.      * mpos = the marked position.
  199.      * tpos = top of screen.
  200.      * bpos = bottom of screen.
  201.      */
  202.     mpos = markpos(c);
  203.     if (mpos == NULL_POSITION)
  204.         return (-1);
  205.     tpos = position(TOP);
  206.     if (tpos == NULL_POSITION)
  207.         tpos = ch_zero();
  208.     bpos = position(BOTTOM);
  209.  
  210.      if (c == '.') 
  211.          return (pipe_data(cmd, tpos, bpos));
  212.      else if (mpos <= tpos)
  213.          return (pipe_data(cmd, mpos, bpos));
  214.      else if (bpos == NULL_POSITION)
  215.          return (pipe_data(cmd, tpos, bpos));
  216.      else
  217.          return (pipe_data(cmd, tpos, mpos));
  218. }
  219.  
  220. /*
  221.  * Create a pipe to the given shell command.
  222.  * Feed it the file contents between the positions spos and epos.
  223.  */
  224.     public int
  225. pipe_data(cmd, spos, epos)
  226.     char *cmd;
  227.     POSITION spos;
  228.     POSITION epos;
  229. {
  230.     register FILE *f;
  231.     register int c;
  232.     extern FILE *popen();
  233.  
  234.     /*
  235.      * This is structured much like lsystem().
  236.      * Since we're running a shell program, we must be careful
  237.      * to perform the necessary deinitialization before running
  238.      * the command, and reinitialization after it.
  239.      */
  240.     if (ch_seek(spos) != 0)
  241.     {
  242.         error("Cannot seek to start position", NULL_PARG);
  243.         return (-1);
  244.     }
  245.  
  246.     if ((f = popen(cmd, "w")) == NULL)
  247.     {
  248.         error("Cannot create pipe", NULL_PARG);
  249.         return (-1);
  250.     }
  251.     clear_bot();
  252.     putstr("!");
  253.     putstr(cmd);
  254.     putstr("\n");
  255.  
  256.     deinit();
  257.     flush();
  258.     raw_mode(0);
  259.     init_signals(0);
  260. #ifdef SIGPIPE
  261.     LSIGNAL(SIGPIPE, SIG_IGN);
  262. #endif
  263.  
  264.     c = EOI;
  265.     while (epos == NULL_POSITION || spos++ <= epos)
  266.     {
  267.         /*
  268.          * Read a character from the file and give it to the pipe.
  269.          */
  270.         c = ch_forw_get();
  271.         if (c == EOI)
  272.             break;
  273.         if (putc(c, f) == EOF)
  274.             break;
  275.     }
  276.  
  277.     /*
  278.      * Finish up the last line.
  279.      */
  280.      while (c != '\n' && c != EOI ) 
  281.      {
  282.          c = ch_forw_get();
  283.          if (c == EOI)
  284.              break;
  285.          if (putc(c, f) == EOF)
  286.              break;
  287.      }
  288.  
  289.     pclose(f);
  290.  
  291. #ifdef SIGPIPE
  292.     LSIGNAL(SIGPIPE, SIG_DFL);
  293. #endif
  294.     init_signals(1);
  295.     raw_mode(1);
  296.     init();
  297.     screen_trashed = 1;
  298. #if defined(SIGWINCH) || defined(SIGWIND)
  299.     /* {{ Probably don't need this here. }} */
  300.     winch(0);
  301. #endif
  302.     return (0);
  303. }
  304.  
  305. #endif
  306.  
  307. #ifdef _OSK
  308. /*
  309.  * Popen, and Pclose, for OS-9.
  310.  */
  311.  
  312. #define ERR      (-1)
  313. #define PIPEMAX  _NFILE
  314. #define READ     1 /* For OS-9 */
  315. #define WRITE    2 /* For OS-9 */
  316. #define STDIN    0 /* For OS-9 */
  317. #define STDOUT   1 /* For OS-9 */
  318.  
  319. #define RESTORE  free(parameter); close(path); dup(save); close(save);
  320.  
  321. static int   _pid[PIPEMAX];
  322.  
  323. FILE *popen(command, type)
  324.     char *command, *type;
  325. {
  326.     register char *p = command;
  327.     char *parameter;
  328.     FILE *_pfp;
  329.     int l, path, pipe, pcnt, save;
  330.  
  331.     path = (*type == 'w') ? STDIN : STDOUT;
  332.  
  333.     if ((pipe = open("/pipe", READ+WRITE)) == ERR)
  334.         return (NULL);
  335.     pcnt = pipe;
  336.  
  337.     if ((save = dup(path)) == ERR) 
  338.     {
  339.         close(pipe);
  340.         return (NULL);
  341.     }
  342.     close(path);
  343.  
  344.     if (dup(pipe) == ERR) 
  345.     {
  346.         dup(save);
  347.         close(save);
  348.         close(pipe);
  349.         return (NULL);
  350.     }
  351.  
  352.     while (*p != ' ' && *p)
  353.         p++;
  354.     if (*p == ' ')
  355.         p++;
  356.     l = strlen(p);
  357.     parameter = (char *) malloc(l+2);
  358.     strcpy(parameter,p);
  359.     strcat(parameter,"\n");
  360.  
  361.     if ((_pid[pcnt] = os9fork(command,l+1,parameter,1,1,0)) == ERR) 
  362.     {
  363.         { RESTORE }
  364.         close(pipe);
  365.         _pid[pcnt] = 0;
  366.         return (NULL);
  367.     }
  368.  
  369.     { RESTORE }
  370.  
  371.     if ((_pfp = fdopen(pipe,type)) == NULL)
  372.     {
  373.         close(pipe);
  374.         while (((l=wait(0)) != _pid[pcnt]) && l != ERR)
  375.             ;
  376.         _pid[pcnt] = 0;
  377.         return (NULL);
  378.     }
  379.  
  380.     return (_pfp);
  381. }
  382.  
  383. int pclose(stream)
  384.     FILE *stream;
  385. {
  386.     register int i;
  387.     int f, status;
  388.  
  389.     f = fileno(stream);
  390.     fclose(stream);
  391.     while ((i = wait(&status)) != _pid[f] && i != ERR)
  392.         ;
  393.     _pid[f] = 0;
  394.     return ((i == ERR) ? ERR : status);
  395. }
  396. #endif /* _OSK */
  397.