home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / e / elv17src.zip / SYSTEM.C < prev    next >
C/C++ Source or Header  |  1992-12-30  |  9KB  |  421 lines

  1. /* system.c  -- UNIX version */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains a new version of the system() function and related stuff.
  12.  *
  13.  * Entry points are:
  14.  *    system(cmd)        - run a single shell command
  15.  *    wildcard(names)        - expand wildcard characters in filanames
  16.  *    filter(m,n,cmd,back)    - run text lines through a filter program
  17.  *
  18.  * This is probably the single least portable file in the program.  The code
  19.  * shown here should work correctly if it links at all; it will work on UNIX
  20.  * and any O.S./Compiler combination which adheres to UNIX forking conventions.
  21.  */
  22.  
  23. #include "config.h"
  24. #include "vi.h"
  25. #ifndef XDOS
  26. extern char    **environ;
  27. #endif
  28.  
  29. #if ANY_UNIX
  30.  
  31. /* This is a new version of the system() function.  The only difference
  32.  * between this one and the library one is: this one uses the o_shell option.
  33.  */
  34. int system(cmd)
  35. #ifdef    __STDC__
  36.     const
  37. #endif
  38.     char    *cmd;    /* a command to run */
  39. {
  40.     int    pid;    /* process ID of child */
  41.     int    died;
  42.     int    status;    /* exit status of the command */
  43.  
  44.  
  45.     signal(SIGINT, SIG_IGN);
  46.     pid = fork();
  47.     switch (pid)
  48.     {
  49.       case -1:                        /* error */
  50.         msg("fork() failed");
  51.         status = -1;
  52.         break;
  53.  
  54.       case 0:                        /* child */
  55.         /* for the child, close all files except stdin/out/err */
  56.         for (status = 3; status < 60 && (close(status), errno != EINVAL); status++)
  57.         {
  58.         }
  59.  
  60.         signal(SIGINT, SIG_DFL);
  61.         if (cmd == o_shell)
  62.         {
  63.             execle(o_shell, o_shell, (char *)0, environ);
  64.         }
  65.         else
  66.         {
  67.             execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  68.         }
  69.         msg("execle(\"%s\", ...) failed", o_shell);
  70.         exit(1); /* if we get here, the exec failed */
  71.  
  72.       default:                        /* parent */
  73.         do
  74.         {
  75.             died = wait(&status);
  76.         } while (died >= 0 && died != pid);
  77.         if (died < 0)
  78.         {
  79.             status = -1;
  80.         }
  81.         signal(SIGINT, trapint);
  82.     }
  83.  
  84.     return status;
  85. }
  86.  
  87. /* This private function opens a pipe from a filter.  It is similar to the
  88.  * system() function above, and to popen(cmd, "r").
  89.  */
  90. int rpipe(cmd, in)
  91.     char    *cmd;    /* the filter command to use */
  92.     int    in;    /* the fd to use for stdin */
  93. {
  94.     int    r0w1[2];/* the pipe fd's */
  95.  
  96.     /* make the pipe */
  97.     if (pipe(r0w1) < 0)
  98.     {
  99.         return -1;    /* pipe failed */
  100.     }
  101.  
  102.     /* The parent process (elvis) ignores signals while the filter runs.
  103.      * The child (the filter program) will reset this, so that it can
  104.      * catch the signal.
  105.      */
  106.     signal(SIGINT, SIG_IGN);
  107.  
  108.     switch (fork())
  109.     {
  110.       case -1:                        /* error */
  111.         return -1;
  112.  
  113.       case 0:                        /* child */
  114.         /* close the "read" end of the pipe */
  115.         close(r0w1[0]);
  116.  
  117.         /* redirect stdout to go to the "write" end of the pipe */
  118.         close(1);
  119.         dup(r0w1[1]);
  120.         close(2);
  121.         dup(r0w1[1]);
  122.         close(r0w1[1]);
  123.  
  124.         /* redirect stdin */
  125.         if (in != 0)
  126.         {
  127.             close(0);
  128.             dup(in);
  129.             close(in);
  130.         }
  131.  
  132.         /* the filter should accept SIGINT signals */
  133.         signal(SIGINT, SIG_DFL);
  134.  
  135.         /* exec the shell to run the command */
  136.         execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  137.         exit(1); /* if we get here, exec failed */
  138.  
  139.       default:                        /* parent */
  140.         /* close the "write" end of the pipe */    
  141.         close(r0w1[1]);
  142.  
  143.         return r0w1[0];
  144.     }
  145. }
  146.  
  147. #endif /* non-DOS */
  148.  
  149. #if OSK
  150.  
  151. /* This private function opens a pipe from a filter.  It is similar to the
  152.  * system() function above, and to popen(cmd, "r").
  153.  */
  154. int rpipe(cmd, in)
  155.     char    *cmd;    /* the filter command to use */
  156.     int    in;    /* the fd to use for stdin */
  157. {
  158.     return osk_popen(cmd, "r", in, 0);
  159. }    
  160. #endif
  161.  
  162. #if ANY_UNIX || OSK
  163.  
  164. /* This function closes the pipe opened by rpipe(), and returns 0 for success */
  165. int rpclose(fd)
  166.     int    fd;
  167. {
  168.     int    status;
  169.  
  170.     close(fd);
  171.     wait(&status);
  172.     signal(SIGINT, trapint);
  173.     return status;
  174. }
  175.  
  176. #endif /* non-DOS */
  177.  
  178. /* This function expands wildcards in a filename or filenames.  It does this
  179.  * by running the "echo" command on the filenames via the shell; it is assumed
  180.  * that the shell will expand the names for you.  If for any reason it can't
  181.  * run echo, then it returns the names unmodified.
  182.  */
  183.  
  184. #if MSDOS || TOS
  185. #define    PROG    "wildcard "
  186. #define    PROGLEN    9
  187. #include <string.h>
  188. #else
  189. #define    PROG    "echo "
  190. #define    PROGLEN    5
  191. #endif
  192.  
  193. #if !AMIGA
  194. char *wildcard(names)
  195.     char    *names;
  196. {
  197.  
  198. # if VMS
  199. /* 
  200.    We could use expand() [vmswild.c], but what's the point on VMS? 
  201.    Anyway, echo is the wrong thing to do, it takes too long to build
  202.    a subprocess on VMS and any "echo" program would have to be supplied
  203.    by elvis.  More importantly, many VMS utilities expand names 
  204.    themselves (the shell doesn't do any expansion) so the concept is
  205.    non-native.  jdc
  206. */
  207.     return names;
  208. # else
  209.  
  210.     int    i, j, fd;
  211.     REG char *s, *d;
  212.  
  213.  
  214.     /* build the echo command */
  215.     if (names != tmpblk.c)
  216.     {
  217.         /* the names aren't in tmpblk.c, so we can do it the easy way */
  218.         strcpy(tmpblk.c, PROG);
  219.         strcat(tmpblk.c, names);
  220.     }
  221.     else
  222.     {
  223.         /* the names are already in tmpblk.c, so shift them to make
  224.          * room for the word "echo "
  225.          */
  226.         for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
  227.         {
  228.             *--d = *--s;
  229.         }
  230.         strncpy(names, PROG, PROGLEN);
  231.     }
  232.  
  233.     /* run the command & read the resulting names */
  234.     fd = rpipe(tmpblk.c, 0);
  235.     if (fd < 0) return names;
  236.     i = 0;
  237.     do
  238.     {
  239.         j = tread(fd, tmpblk.c + i, BLKSIZE - i);
  240.         i += j;
  241.     } while (j > 0);
  242.  
  243.     /* successful? */
  244.     if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
  245.     {
  246.         tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
  247.         return tmpblk.c;
  248.     }
  249.     else
  250.     {
  251.         return names;
  252.     }
  253. # endif
  254. }
  255. #endif
  256.  
  257. /* This function runs a range of lines through a filter program, and replaces
  258.  * the original text with the filtered version.  As a special case, if "to"
  259.  * is MARK_UNSET, then it runs the filter program with stdin coming from
  260.  * /dev/null, and inserts any output lines.
  261.  */
  262. int filter(from, to, cmd, back)
  263.     MARK    from, to;    /* the range of lines to filter */
  264.     char    *cmd;        /* the filter command */
  265.     int    back;        /* boolean: will we read lines back? */
  266. {
  267.     int    scratch;    /* fd of the scratch file */
  268.     int    fd;        /* fd of the pipe from the filter */
  269.     char    scrout[50];    /* name of the scratch out file */
  270.     MARK    new;        /* place where new text should go */
  271.     long    sent, rcvd;    /* number of lines sent/received */
  272.     int    i, j;
  273.  
  274.     /* write the lines (if specified) to a temp file */
  275.     if (to)
  276.     {
  277.         /* we have lines */
  278. #if MSDOS || TOS
  279.         strcpy(scrout, o_directory);
  280.         if ((i=strlen(scrout)) && !strchr("\\/:", scrout[i-1]))
  281.             scrout[i++]=SLASH;
  282.         strcpy(scrout+i, SCRATCHOUT+3);
  283. #else
  284.         sprintf(scrout, SCRATCHOUT, o_directory);
  285. #endif
  286.         mktemp(scrout);
  287.         cmd_write(from, to, CMD_BANG, FALSE, scrout);
  288.         sent = markline(to) - markline(from) + 1L;
  289.  
  290.         /* use those lines as stdin */
  291.         scratch = open(scrout, O_RDONLY);
  292.         if (scratch < 0)
  293.         {
  294.             unlink(scrout);
  295.             return -1;
  296.         }
  297.     }
  298.     else
  299.     {
  300.         scratch = 0;
  301.         sent = 0L;
  302.     }
  303.  
  304.     /* start the filter program */
  305. #if VMS
  306.     /* 
  307.        VMS doesn't know a thing about file descriptor 0.  The rpipe
  308.        concept is non-portable.  Hence we need a file name argument.
  309.     */
  310.     fd = rpipe(cmd, scratch, scrout);
  311. #else
  312.     fd = rpipe(cmd, scratch);
  313. #endif
  314.     if (fd < 0)
  315.     {
  316.         if (to)
  317.         {
  318.             close(scratch);
  319.             unlink(scrout);
  320.         }
  321.         return -1;
  322.     }
  323.  
  324.     if (back)
  325.     {
  326.         ChangeText
  327.         {
  328.             /* adjust MARKs for whole lines, and set "new" */
  329.             from &= ~(BLKSIZE - 1);
  330.             if (to)
  331.             {
  332.                 to &= ~(BLKSIZE - 1);
  333.                 to += BLKSIZE;
  334.                 new = to;
  335.             }
  336.             else
  337.             {
  338.                 new = from + BLKSIZE;
  339.             }
  340.  
  341. #if VMS
  342. /* Reading from a VMS mailbox (pipe) is record oriented... */
  343. # define tread vms_pread
  344. #endif
  345.  
  346.             /* repeatedly read in new text and add it */
  347.             rcvd = 0L;
  348.             while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
  349.             {
  350.                 tmpblk.c[i] = '\0';
  351.                 add(new, tmpblk.c);
  352. #if VMS
  353.                 /* What!  An advantage to record oriented reads? */
  354.                 new += (i - 1);
  355.                 new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
  356.                 rcvd++;
  357. #else
  358.                 for (i = 0; tmpblk.c[i]; i++)
  359.                 {
  360.                     if (tmpblk.c[i] == '\n')
  361.                     {
  362.                         new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
  363.                         rcvd++;
  364.                     }
  365.                     else
  366.                     {
  367.                         new++;
  368.                     }
  369.                 }
  370. #endif
  371.             }
  372.  
  373.             /* delete old text, if any */
  374.             if (to)
  375.             {
  376.                 cut(from, to);
  377.                 delete(from, to);
  378.             }
  379.         }
  380.     }
  381.     else
  382.     {
  383.         /* read the command's output, and copy it to the screen */
  384.         while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
  385.         {
  386.             for (j = 0; j < i; j++)
  387.             {
  388.                 addch(tmpblk.c[j]);
  389.             }
  390.         }
  391.         rcvd = 0;
  392.     }
  393.  
  394.     /* Reporting... */
  395.     if (sent >= *o_report || rcvd >= *o_report)
  396.     {
  397.         if (sent > 0L && rcvd > 0L)
  398.         {
  399.             msg("%ld lines out, %ld lines back", sent, rcvd);
  400.         }
  401.         else if (sent > 0)
  402.         {
  403.             msg("%ld lines written to filter", sent);
  404.         }
  405.         else
  406.         {
  407.             msg("%ld lines read from filter", rcvd);
  408.         }
  409.     }
  410.     rptlines = 0L;
  411.  
  412.     /* cleanup */
  413.     rpclose(fd);
  414.     if (to)
  415.     {
  416.         close(scratch);
  417.         unlink(scrout);
  418.     }
  419.     return 0;
  420. }
  421.