home *** CD-ROM | disk | FTP | other *** search
- /* sw_popen.c - popen () and pclose () with swapping.
- Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
-
- This file is part of SWAPLIB (the library), a library for efficient
- execution of child processes under MS-DOS.
-
- The library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- The library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with the library; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- $Header: e:/gnu/swaplib/RCS/sw_popen.c'v 0.9 90/09/09 21:44:07 tho Stable $
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include <io.h>
- #include <fcntl.h>
-
- #include "swaplib.h"
-
- extern void *xmalloc (size_t size);
-
-
- /* We do not perform an extensive error check, but well-formed
- MODE strings will be recognized properly. */
-
- #define BIN_MODE(p) (strchr ((p).mode, 'b') != NULL)
- #define TXT_MODE(p) (strchr ((p).mode, 't') != NULL)
- #define WR_MODE(p) (strchr ((p).mode, 'w') != NULL)
- #define RD_MODE(p) (strchr ((p).mode, 'r') != NULL)
- #define APP_MODE(p) (strchr ((p).mode, 'a') != NULL)
- #define RDWR_MODE(p) (strchr ((p).mode, '+') != NULL)
-
- /* This is a very simple way to mark a pipe as closed or available
- not open in any mode! */
-
- #define CLOSED(p) ((p).mode == NULL)
- #define AVAIL(p) ((p).mode == NULL)
-
-
- #define MAX_PIPES (_NFILE - 3)
-
- struct pipe
- {
- /* The stream for this pipe (that's what the caller will use). */
- FILE *file;
-
- /* Are we reading or writing, or is it closed? */
- char *mode;
-
- /* The name of the temporary file for this pipe. */
- char *name;
-
- /* The command to pipe in to or out from. */
- char *cmd;
-
- /* The returncode of the above command. */
- int rc;
- };
-
- typedef struct pipe PIPE;
-
-
- static PIPE *pipes = NULL;
-
- static FILE *popen_write (int ph);
- static FILE *popen_read (int ph);
- static int pclose_write (int ph);
- static int pclose_read (int ph);
- static int init_pipes (void);
- static void cleanup_pipes (void);
-
-
- /* Open a pipe to or from a shell COMMAND. Returns a stdio stream. */
-
- FILE *
- swap_popen (char *command, char *mode)
- {
- int i;
-
- /* Raw check of arguments. */
-
- if (!command || !mode || strchr (mode, 'a') || strchr (mode, '+'))
- {
- errno = EINVAL;
- return NULL;
- }
-
- /* Have we had a pipe already? If not, perform the necessary
- initializations. */
-
- if (!pipes)
- if (init_pipes () != 0)
- return NULL;
-
-
- for (i = 0; i < MAX_PIPES; i++)
- {
- /* Scan the list of pipes for an available one. */
-
- if (AVAIL (pipes[i]))
- {
- /* Initialize the data structure for this pipe. */
-
- pipes[i].cmd = command;
- pipes[i].mode = mode;
- pipes[i].name = swap_mktmpname ("pi");
- if (!pipes[i].name)
- return NULL;
-
-
- /* Actually open the pipe. */
-
- if (WR_MODE (pipes[i]))
- return popen_write (i);
- else if (RD_MODE (pipes[i]))
- return popen_read (i);
- else
- {
- free (pipes[i].name);
- return NULL;
- }
- }
- }
-
- /* Failed. */
-
- errno = EAGAIN;
- return NULL;
- }
-
-
- /* Close a pipe to or from a shell command. Returns the exit code
- of the command. */
-
- int
- swap_pclose (FILE *pipe_file)
- {
- int i;
-
- for (i = 0; i < MAX_PIPES; i++)
- {
- /* Scan the list of pipes for the stdio stream which uniquely
- identifies the pipe. */
-
- if (pipes[i].file == pipe_file)
- {
- /* Actually close the pipe. */
-
- if (WR_MODE (pipes[i]))
- return pclose_write (i);
- else if (RD_MODE (pipes[i]))
- return pclose_read (i);
- else
- {
- errno = EBADF;
- return -1;
- }
- }
- }
-
- /* Failed. */
-
- errno = EBADF;
- return -1;
- }
-
-
- int
- init_pipes (void)
- {
- int i;
- pipes = (PIPE *) xmalloc (MAX_PIPES * sizeof (PIPE));
-
- for (i = 0; i < MAX_PIPES; i++)
- {
- pipes[i].mode = NULL;
- pipes[i].file = NULL;
- }
-
- /* Make sure that all pipes will be closed at exit ().
- This is non trivial under MS-DOS, since we will have to
- run the command that we wrote to at this time! */
-
- return atexit (cleanup_pipes);
- }
-
- void
- cleanup_pipes (void)
- {
- int i;
-
- for (i = 0; i < MAX_PIPES; i++)
- {
- if (RD_MODE (pipes[i]))
- pclose_read (i);
- else if (WR_MODE (pipes[i]))
- pclose_write (i);
- }
- }
-
-
- FILE *
- popen_write (int ph)
- {
- /* At the moment, all we need is a stdio stream to write to. */
-
- return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
- }
-
- FILE *
- popen_read (int ph)
- {
- int save_stdout = dup (1);
- FILE *pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "wb" : "w");
-
- dup2 (fileno (pf), 1);
-
- pipes[ph].rc = swap_system (pipes[ph].cmd);
-
- dup2 (save_stdout, 1);
- close (save_stdout);
- fclose (pf);
-
- return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
- }
-
- int
- pclose_write (int ph)
- {
- int rc;
- int save_stdin;
- FILE *pf;
-
- /* Close the stream (we're done writing...). */
-
- fclose (pipes[ph].file);
-
-
- /* Get a copy of our standard input (in order to reclaim it
- after redirections.) */
-
- save_stdin = dup (0);
-
-
- /* Reopen the temporary file, but this time for reading. And `dup'
- it to standard input (descriptor 0). */
-
- pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "rb" : "r");
- dup2 (fileno (pf), 0);
-
-
- /* Execute the command. (With standard input redirected from our
- pipe (i.e. temporary file). */
-
- rc = swap_system (pipes[ph].cmd);
-
-
- /* `dup` the old standard input back to file descriptor 0, close
- the temporary file, and return the handle used to save the old
- standard input to the system. */
-
- dup2 (save_stdin, 0);
- close (save_stdin);
- fclose (pf);
-
-
- /* Clean up and mark the pipe as available. */
-
- pipes[ph].mode = NULL;
- pipes[ph].file = NULL;
- unlink (pipes[ph].name);
- free (pipes[ph].name);
-
- return rc;
- }
-
- int
- pclose_read (int ph)
- {
- fclose (pipes[ph].file);
-
- pipes[ph].mode = NULL;
- pipes[ph].file = NULL;
- unlink (pipes[ph].name);
- free (pipes[ph].name);
-
- return pipes[ph].rc;
- }
-
- /*
- * Local Variables:
- * mode:C
- * ChangeLog:ChangeLog
- * compile-command:make
- * End:
- */
-