home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1709 / system.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  5.8 KB  |  286 lines

  1. /* system.c  -- UNIX version */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  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)    - 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. #include <signal.h>
  26. extern char    **environ;
  27.  
  28. #if    ANY_UNIX
  29.  
  30. /* This is a new version of the system() function.  The only difference
  31.  * between this one and the library one is: this one uses the o_shell option.
  32.  */
  33. int system(cmd)
  34.     char    *cmd;    /* a command to run */
  35. {
  36.     int    status;    /* exit status of the command */
  37.  
  38.     /* warn the user if the file hasn't been saved yet */
  39.     if (*o_warn && tstflag(file, MODIFIED))
  40.     {
  41.         msg("Warning: \"%s\" has been modified but not yet saved", origname);
  42.     }
  43.  
  44.     switch (fork())
  45.     {
  46.       case -1:                        /* error */
  47.         status = -1;
  48.         break;
  49.  
  50.       case 0:                        /* child */
  51.         execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  52.         exit(1); /* if we get here, the exec failed */
  53.  
  54.       default:                        /* parent */
  55.         signal(SIGINT, SIG_IGN);
  56.         wait(&status);
  57.         signal(SIGINT, trapint);
  58.     }
  59.  
  60.     return status;
  61. }
  62.  
  63. /* This private function opens a pipe from a filter.  It is similar to the
  64.  * system() function above, and to popen(cmd, "r").
  65.  */
  66. static int rpipe(cmd, in)
  67.     char    *cmd;    /* the filter command to use */
  68.     int    in;    /* the fd to use for stdin */
  69. {
  70.     int    r0w1[2];/* the pipe fd's */
  71.  
  72.     /* make the pipe */
  73.     if (pipe(r0w1) < 0)
  74.     {
  75.         return -1;    /* pipe failed */
  76.     }
  77.  
  78.     switch (fork())
  79.     {
  80.       case -1:                        /* error */
  81.         return -1;
  82.  
  83.       case 0:                        /* child */
  84.         /* close the "read" end of the pipe */
  85.         close(r0w1[0]);
  86.  
  87.         /* redirect stdout to go to the "write" end of the pipe */
  88.         close(1);
  89.         dup(r0w1[1]);
  90.         close(2);
  91.         dup(r0w1[1]);
  92.         close(r0w1[1]);
  93.  
  94.         /* redirect stdin */
  95.         if (in != 0)
  96.         {
  97.             close(0);
  98.             dup(in);
  99.             close(in);
  100.         }
  101.  
  102.         /* exec the shell to run the command */
  103.         execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  104.         exit(1); /* if we get here, exec failed */
  105.  
  106.       default:                        /* parent */
  107.         signal(SIGINT, SIG_IGN);    /* <- reset after the wait() */
  108.  
  109.         /* close the "write" end of the pipe */    
  110.         close(r0w1[1]);
  111.  
  112.         return r0w1[0];
  113.     }
  114. }
  115.  
  116. /* This function closes the pipe opened by rpipe(), and returns 0 for success */
  117. static int rpclose(fd)
  118.     int    fd;
  119. {
  120.     int    status;
  121.  
  122.     close(fd);
  123.     wait(&status);
  124.     signal(SIGINT, trapint);
  125.     return status;
  126. }
  127.  
  128. #endif /* non-DOS */
  129.  
  130. /* This function expands wildcards in a filename or filenames.  It does this
  131.  * by running the "echo" command on the filenames via the shell; it is assumed
  132.  * that the shell will expand the names for you.  If for any reason it can't
  133.  * run echo, then it returns the names unmodified.
  134.  */
  135.  
  136. #if    MSDOS || TOS
  137. #define    PROG    "wildcard "
  138. #define    PROGLEN    9
  139. #include <string.h>
  140. #else
  141. #define    PROG    "echo "
  142. #define    PROGLEN    5
  143. #endif
  144.  
  145. char *wildcard(names)
  146.     char    *names;
  147. {
  148.     int    i, j, fd;
  149.  
  150.     /* build the echo command */
  151.     if (names != tmpblk.c)
  152.     {
  153.         /* the names aren't in tmpblk.c, so we can do it the easy way */
  154.         strcpy(tmpblk.c, PROG);
  155.         strcat(tmpblk.c, names);
  156.     }
  157.     else
  158.     {
  159.         register char *s, *d;
  160.  
  161.         /* the names are already in tmpblk.c, so shift them to make
  162.          * room for the word "echo "
  163.          */
  164.         for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
  165.         {
  166.             *--d = *--s;
  167.         }
  168.         strncpy(names, PROG, PROGLEN);
  169.     }
  170.  
  171.     /* run the command & read the resulting names */
  172.     fd = rpipe(tmpblk.c, 0);
  173.     if (fd < 0) return names;
  174.     i = 0;
  175.     do
  176.     {
  177.         j = tread(fd, tmpblk.c + i, BLKSIZE - i);
  178.         i += j;
  179.     } while (j > 0);
  180.  
  181.     /* successful? */
  182.     if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
  183.     {
  184.         tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
  185.         return tmpblk.c;
  186.     }
  187.     else
  188.     {
  189.         return names;
  190.     }
  191. }
  192.  
  193. /* This function runs a range of lines through a filter program, and replaces
  194.  * the original text with the filtered version.  As a special case, if "to"
  195.  * is MARK_UNSET, then it runs the filter program with stdin coming from
  196.  * /dev/null, and inserts any output lines.
  197.  */
  198. int filter(from, to, cmd)
  199.     MARK    from, to;    /* the range of lines to filter */
  200.     char    *cmd;        /* the filter command */
  201. {
  202.     int    scratch;    /* fd of the scratch file */
  203.     int    fd;        /* fd of the pipe from the filter */
  204.     char    scrout[50];    /* name of the scratch out file */
  205.     int    i;
  206.  
  207.     /* write the lines (if specified) to a temp file */
  208.     if (to)
  209.     {
  210.         /* we have lines */
  211. #if    MSDOS || TOS
  212.         strcpy(scrout, o_directory);
  213.         if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1]))
  214.             scrout[i++]=SLASH;
  215.         strcpy(scrout+i, SCRATCHOUT+3);
  216. #else
  217.         sprintf(scrout, SCRATCHOUT, o_directory);
  218. #endif        
  219.         mktemp(scrout);
  220.         cmd_write(from, to, CMD_BANG, 0, scrout);
  221.  
  222.         /* use those lines as stdin */
  223.         scratch = open(scrout, O_RDONLY);
  224.         if (scratch < 0)
  225.         {
  226.             unlink(scrout);
  227.             return -1;
  228.         }
  229.     }
  230.     else
  231.     {
  232.         scratch = 0;
  233.     }
  234.  
  235.     /* start the filter program */
  236.     fd = rpipe(cmd, scratch);
  237.     if (fd < 0)
  238.     {
  239.         if (to)
  240.         {
  241.             close(scratch);
  242.             unlink(scrout);
  243.         }
  244.         return -1;
  245.     }
  246.  
  247.     ChangeText
  248.     {
  249.         /* delete the original lines, if any.  Lines!  */
  250.         if (to)
  251.         {
  252.             from &= ~(BLKSIZE - 1);
  253.             to &= ~(BLKSIZE - 1);
  254.             to += BLKSIZE;
  255.             delete(from, to);
  256.         }
  257.  
  258.         /* repeatedly read in new text and add it */
  259.         while ((i = tread(fd, tmpblk.c, BLKSIZE)) > 0)
  260.         {
  261.             tmpblk.c[i] = '\0';
  262.             add(from, tmpblk.c);
  263.             for (i = 0; tmpblk.c[i]; i++)
  264.             {
  265.                 if (tmpblk.c[i] == '\n')
  266.                 {
  267.                     from = (from & ~(BLKSIZE - 1)) + BLKSIZE;
  268.                 }
  269.                 else
  270.                 {
  271.                     from++;
  272.                 }
  273.             }
  274.         }
  275.     }
  276.  
  277.     /* cleanup */
  278.     rpclose(fd);
  279.     if (to)
  280.     {
  281.         close(scratch);
  282.         unlink(scrout);
  283.     }
  284.     return 0;
  285. }
  286.