home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / ntcode / gd25s / ms / popen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  4.7 KB  |  226 lines

  1. /*
  2.  *  popen.c - imitate UNIX pipes
  3.  *
  4.  *  $Header: c:/src/RCS/popen.c 1.2 1993/05/17 17:51:07 few Exp $
  5.  *
  6.  *  Author: Frank Whaley (few@autodesk.com)
  7.  *
  8.  *  Copyright (c) 1993 Frank Whaley.  All rights reserved.
  9.  *
  10.  *  Permission to use, copy, modify, distribute, and sell this software
  11.  *  and its documentation for any purpose is hereby granted without fee,
  12.  *  provided that the above copyright notice appears in all copies.  The
  13.  *  name of the author may not be used to endorse or promote products
  14.  *  derived from this software without specific prior written permission.
  15.  *
  16.  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <process.h>
  25. #include <io.h>
  26. #include <errno.h>
  27.  
  28. #define NPIPES    10    /*  max number of pipes  */
  29.  
  30. typedef struct
  31. {
  32.     char *command;    /*  program name  */
  33.     FILE *fp;    /*  pipe tempfile  */
  34.     char *file;    /*  pipe filename  */
  35.     char *mode;    /*  pipe mode  */
  36.     int status;    /*  status to return  */
  37. } PIPE;
  38.  
  39. static PIPE pipes[NPIPES];
  40. static int init = 0;
  41.  
  42.     /*  forward declarations  */
  43. static PIPE *findPipe(FILE *fp);
  44. static int killPipe(PIPE *pp, int mode);
  45. static PIPE *newPipe(char *command, char *mode);
  46.  
  47.  
  48. /*
  49. -*    popen - open a (pseudo) pipe
  50.  */
  51.     FILE *
  52. popen(char *command, char *type)
  53.     int old_stdout;
  54.     PIPE *pp;
  55.  
  56.     /*  init PIPE table  */
  57.     if ( !init )
  58.     {
  59.         for ( pp = pipes; pp < &pipes[NPIPES]; pp++ )
  60.             pp->fp = (FILE *)NULL;
  61.         init++;
  62.     }
  63.  
  64.     /*  which flavor pipe ??  */
  65.     switch ( *type )
  66.     {
  67.     case 'w':
  68.         /*  pclose() execs command for write pipes  */
  69.         if ( (pp = newPipe(command, type)) == (PIPE *)NULL )
  70.             return ( (FILE *)NULL );
  71.         return ( pp->fp );
  72.  
  73.     case 'r':
  74.         /*  exec command now for read pipes  */
  75.         if ( (pp = newPipe(command, type)) == (PIPE *)NULL )
  76.             return ( (FILE *)NULL );
  77.  
  78.         if ( ((old_stdout = dup(fileno(stdout))) < 0) ||
  79.              (dup2(fileno(pp->fp), fileno(stdout)) < 0) ||
  80.              ((pp->status = system(command)) < 0) ||
  81.              (fclose(pp->fp) < 0) ||
  82.              (dup2(old_stdout, fileno(stdout)) < 0) ||
  83.              ((pp->fp = fopen(pp->file, pp->mode)) == (FILE *)NULL) )
  84.         {
  85.             killPipe(pp, 1);
  86.             return ( (FILE *)NULL );
  87.         }
  88.  
  89.         return ( pp->fp );
  90.  
  91.     default:
  92.         errno = EINVAL;
  93.         return ( (FILE *)NULL );
  94.     }
  95. }
  96.  
  97. /*
  98. -*    pclose - close a (pseudo) pipe
  99.  */
  100.     int
  101. pclose(FILE *fp)
  102. {
  103.     PIPE *pp;
  104.     int old_stdin;
  105.  
  106.     if ( (pp = findPipe(fp)) == (PIPE *)NULL )
  107.     {
  108.         errno = EBADF;
  109.         return ( -1 );
  110.     }
  111.  
  112.     if ( fclose(pp->fp) < 0 )
  113.         return ( killPipe(pp, 1) );
  114.  
  115.     if ( (*pp->mode == 'w') &&
  116.          (((pp->fp = fopen(pp->file, "r")) == (FILE *)NULL) ||
  117.           ((old_stdin = dup(fileno(stdin))) < 0) ||
  118.           (dup2(fileno(pp->fp), fileno(stdin)) < 0) ||
  119.           ((pp->status = system(pp->command)) < 0) ||
  120.           (fclose(pp->fp) < 0) ||
  121.           (dup2(old_stdin, fileno(stdin)) < 0)) )
  122.     {
  123.         return ( killPipe(pp, 1) );
  124.     }
  125.  
  126.     return ( killPipe(pp, 0) );
  127. }
  128.  
  129. /*
  130.  *    find a PIPE entry
  131.  */
  132.     static PIPE *
  133. findPipe(FILE *fp)
  134. {
  135.     PIPE *pp;
  136.  
  137.     for ( pp = pipes; pp < &pipes[NPIPES]; pp++ )
  138.         if ( pp->fp == fp )
  139.             return ( pp );
  140.  
  141.     return ( (PIPE *)NULL );
  142. }
  143.  
  144. /*
  145.  *    cancel a pipe
  146.  */
  147.     static int
  148. killPipe(PIPE *pp, int mode)
  149. {
  150.     int result = (!mode) ? 0 : -1;
  151.     int serrno = errno;
  152.  
  153.     fclose(pp->fp);
  154.  
  155.     if ( pp->file != NULL )
  156.     {
  157.         result = unlink(pp->file);
  158.  
  159.         if ( !mode )
  160.             serrno = errno;
  161.         else
  162.             result = -1;
  163.         free(pp->file);
  164.     }
  165.  
  166.     if ( pp->command != NULL )
  167.         free(pp->command);
  168.  
  169.     pp->fp = (FILE *)NULL;
  170.  
  171.     errno = serrno;
  172.     return ( result );
  173. }
  174.  
  175. /*
  176.  *    init PIPE structure
  177.  */
  178.     static PIPE *
  179. newPipe(char *command, char *mode)
  180. {
  181.     FILE *fp;
  182.     PIPE *pp;
  183.     char tmpfile[256];
  184.     static char *tmpdir = NULL;
  185.  
  186.     /*  one-time search for tmp directory  */
  187.     if ( (tmpdir == NULL) &&
  188.          ((tmpdir = getenv("TMPDIR")) == NULL) &&
  189.          ((tmpdir = getenv("TMP")) == NULL) &&
  190.          ((tmpdir = getenv("TEMP")) == NULL) )
  191.         tmpdir = ".";
  192.  
  193.     /*  make temp file  */
  194.     strcat(strcpy(tmpfile, tmpdir), "/ppXXXXXX");
  195.     mktemp(tmpfile);
  196.     if ( (fp = fopen(tmpfile, "w")) == (FILE *)NULL )
  197.         return ( (PIPE *)NULL );
  198.  
  199.     /*  make PIPE entry  */
  200.     if ( (pp = findPipe((FILE *)NULL)) == (PIPE *)NULL )
  201.     {
  202.         fclose(fp);
  203.         unlink(tmpfile);
  204.         errno = EMFILE;
  205.         return ( (PIPE *)NULL );
  206.     }
  207.  
  208.     pp->fp = fp;
  209.     pp->mode = strdup(mode);
  210.     pp->command = strdup(command);
  211.     pp->file = strdup(tmpfile);
  212.  
  213.     /*  errors ??  */
  214.     if ( (pp->command == NULL) || (pp->file == NULL) )
  215.     {
  216.         killPipe(pp, 1);
  217.         errno = ENOMEM;
  218.         return ( (PIPE *)NULL );
  219.     }
  220.  
  221.     return ( pp );
  222. }
  223.  
  224. /*  END of popen.c  */
  225.