home *** CD-ROM | disk | FTP | other *** search
/ Mega CD-ROM 1 / megacd_rom_1.zip / megacd_rom_1 / GNUISH / SWALIB0.ZIP / SW_POPEN.C < prev    next >
C/C++ Source or Header  |  1990-09-10  |  7KB  |  313 lines

  1. /* sw_popen.c - popen () and pclose () with swapping.
  2.    Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  3.  
  4.    This file is part of SWAPLIB (the library), a library for efficient
  5.    execution of child processes under MS-DOS.
  6.  
  7.    The library is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 1, or (at your option)
  10.    any later version.
  11.  
  12.    The library is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with the library; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.    $Header: e:/gnu/swaplib/RCS/sw_popen.c'v 0.9 90/09/09 21:44:07 tho Stable $
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30.  
  31. #include <io.h>
  32. #include <fcntl.h>
  33.  
  34. #include "swaplib.h"
  35.  
  36. extern void *xmalloc (size_t size);
  37.  
  38.  
  39. /* We do not perform an extensive error check, but well-formed
  40.    MODE strings will be recognized properly.  */
  41.  
  42. #define BIN_MODE(p)        (strchr ((p).mode, 'b') != NULL)
  43. #define TXT_MODE(p)        (strchr ((p).mode, 't') != NULL)
  44. #define WR_MODE(p)        (strchr ((p).mode, 'w') != NULL)
  45. #define RD_MODE(p)        (strchr ((p).mode, 'r') != NULL)
  46. #define APP_MODE(p)        (strchr ((p).mode, 'a') != NULL)
  47. #define RDWR_MODE(p)        (strchr ((p).mode, '+') != NULL)
  48.  
  49. /* This is a very simple way to mark a pipe as closed or available
  50.    not open in any mode!  */
  51.  
  52. #define CLOSED(p)        ((p).mode == NULL)
  53. #define AVAIL(p)        ((p).mode == NULL)
  54.  
  55.  
  56. #define MAX_PIPES    (_NFILE - 3)
  57.  
  58. struct pipe
  59. {
  60.   /* The stream for this pipe (that's what the caller will use).  */
  61.   FILE *file;
  62.  
  63.   /* Are we reading or writing, or is it closed?  */
  64.   char *mode;
  65.  
  66.   /* The name of the temporary file for this pipe.  */
  67.   char *name;
  68.  
  69.   /* The command to pipe in to or out from.  */
  70.   char *cmd;
  71.  
  72.   /* The returncode of the above command. */
  73.   int rc;
  74. };
  75.  
  76. typedef struct pipe PIPE;
  77.  
  78.  
  79. static PIPE *pipes = NULL;
  80.  
  81. static FILE *popen_write (int ph);
  82. static FILE *popen_read (int ph);
  83. static int pclose_write (int ph);
  84. static int pclose_read (int ph);
  85. static int init_pipes (void);
  86. static void cleanup_pipes (void);
  87.  
  88.  
  89. /* Open a pipe to or from a shell COMMAND.  Returns a stdio stream.  */
  90.  
  91. FILE *
  92. swap_popen (char *command, char *mode)
  93. {
  94.   int i;
  95.  
  96.   /* Raw check of arguments.  */
  97.  
  98.   if (!command || !mode || strchr (mode, 'a') || strchr (mode, '+'))
  99.     {
  100.       errno = EINVAL;
  101.       return NULL;
  102.     }
  103.  
  104.   /* Have we had a pipe already?  If not, perform the necessary
  105.      initializations.  */
  106.  
  107.   if (!pipes)
  108.     if (init_pipes () != 0)
  109.       return NULL;
  110.  
  111.  
  112.   for (i = 0; i < MAX_PIPES; i++)
  113.     {
  114.       /* Scan the list of pipes for an available one.  */
  115.  
  116.       if (AVAIL (pipes[i]))
  117.     {
  118.       /* Initialize the data structure for this pipe.  */
  119.  
  120.       pipes[i].cmd = command;
  121.       pipes[i].mode = mode;
  122.       pipes[i].name = swap_mktmpname ("pi");
  123.       if (!pipes[i].name)
  124.         return NULL;
  125.  
  126.  
  127.       /* Actually open the pipe.  */
  128.  
  129.       if (WR_MODE (pipes[i]))
  130.         return popen_write (i);
  131.       else if (RD_MODE (pipes[i]))
  132.         return popen_read (i);
  133.       else
  134.         {
  135.           free (pipes[i].name);
  136.           return NULL;
  137.         }
  138.     }
  139.     }
  140.  
  141.   /* Failed.  */
  142.  
  143.   errno = EAGAIN;
  144.   return NULL;
  145. }
  146.  
  147.  
  148. /* Close a pipe to or from a shell command.  Returns the exit code
  149.    of the command.  */
  150.  
  151. int
  152. swap_pclose (FILE *pipe_file)
  153. {
  154.   int i;
  155.  
  156.   for (i = 0; i < MAX_PIPES; i++)
  157.     {
  158.       /* Scan the list of pipes for the stdio stream which uniquely
  159.      identifies the pipe.  */
  160.  
  161.       if (pipes[i].file == pipe_file)
  162.     {
  163.       /* Actually close the pipe.  */
  164.  
  165.       if (WR_MODE (pipes[i]))
  166.         return pclose_write (i);
  167.       else if (RD_MODE (pipes[i]))
  168.         return pclose_read (i);
  169.       else
  170.         {
  171.           errno = EBADF;
  172.           return -1;
  173.         }
  174.     }
  175.     }
  176.  
  177.   /* Failed.  */
  178.  
  179.   errno = EBADF;
  180.   return -1;
  181. }
  182.  
  183.  
  184. int
  185. init_pipes (void)
  186. {
  187.   int i;
  188.   pipes = (PIPE *) xmalloc (MAX_PIPES * sizeof (PIPE));
  189.  
  190.   for (i = 0; i < MAX_PIPES; i++)
  191.     {
  192.       pipes[i].mode = NULL;
  193.       pipes[i].file = NULL;
  194.     }
  195.  
  196.   /* Make sure that all pipes will be closed at exit ().
  197.      This is non trivial under MS-DOS, since we will have to
  198.      run the command that we wrote to at this time!  */
  199.  
  200.   return atexit (cleanup_pipes);
  201. }
  202.  
  203. void
  204. cleanup_pipes (void)
  205. {
  206.   int i;
  207.  
  208.   for (i = 0; i < MAX_PIPES; i++)
  209.     {
  210.       if (RD_MODE (pipes[i]))
  211.      pclose_read (i);
  212.       else if (WR_MODE (pipes[i]))
  213.      pclose_write (i);
  214.     }
  215. }
  216.  
  217.  
  218. FILE *
  219. popen_write (int ph)
  220. {
  221.   /* At the moment, all we need is a stdio stream to write to.  */
  222.  
  223.   return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
  224. }
  225.  
  226. FILE *
  227. popen_read (int ph)
  228. {
  229.   int save_stdout = dup (1);
  230.   FILE *pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "wb" : "w");
  231.  
  232.   dup2 (fileno (pf), 1);
  233.  
  234.   pipes[ph].rc = swap_system (pipes[ph].cmd);
  235.  
  236.   dup2 (save_stdout, 1);
  237.   close (save_stdout);
  238.   fclose (pf);
  239.  
  240.   return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
  241. }
  242.  
  243. int
  244. pclose_write (int ph)
  245. {
  246.   int rc;
  247.   int save_stdin;
  248.   FILE *pf;
  249.  
  250.   /* Close the stream (we're done writing...).  */
  251.  
  252.   fclose (pipes[ph].file);
  253.  
  254.  
  255.   /* Get a copy of our standard input (in order to reclaim it
  256.      after redirections.)  */
  257.  
  258.   save_stdin = dup (0);
  259.  
  260.  
  261.   /* Reopen the temporary file, but this time for reading.  And `dup'
  262.      it to standard input (descriptor 0).  */
  263.  
  264.   pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "rb" : "r");
  265.   dup2 (fileno (pf), 0);
  266.  
  267.  
  268.   /* Execute the command.  (With standard input redirected from our
  269.      pipe (i.e. temporary file).  */
  270.  
  271.   rc = swap_system (pipes[ph].cmd);
  272.  
  273.  
  274.   /* `dup` the old standard input back to file descriptor 0, close
  275.      the temporary file, and return the handle used to save the old
  276.      standard input to the system.  */
  277.  
  278.   dup2 (save_stdin, 0);
  279.   close (save_stdin);
  280.   fclose (pf);
  281.  
  282.  
  283.   /* Clean up and mark the pipe as available.  */
  284.  
  285.   pipes[ph].mode = NULL;
  286.   pipes[ph].file = NULL;
  287.   unlink (pipes[ph].name);
  288.   free (pipes[ph].name);
  289.  
  290.   return rc;
  291. }
  292.  
  293. int
  294. pclose_read (int ph)
  295. {
  296.   fclose (pipes[ph].file);
  297.  
  298.   pipes[ph].mode = NULL;
  299.   pipes[ph].file = NULL;
  300.   unlink (pipes[ph].name);
  301.   free (pipes[ph].name);
  302.  
  303.   return pipes[ph].rc;
  304. }
  305.  
  306. /* 
  307.  * Local Variables:
  308.  * mode:C
  309.  * ChangeLog:ChangeLog
  310.  * compile-command:make
  311.  * End:
  312.  */
  313.