[comp.sys.ibm.pc] popen/pclose available for MS-DOS/MS C?

ben@cunixc.columbia.edu (Ben Fried) (02/23/88)

Has anyone implemented an MS-DOS version of the unix "popen" and
"pclose" library routines for MS-DOS?  I'm porting a unix program to
MS-DOS that uses those calls a lot.

Please reply to me via mail - I don't read this newsgroup regularly.

Thanks.

Ben Fried
ben@cunixc.columbia.edu		ben@cuvma.bitnet
ben@columbia.edu

madd@bu-cs.BU.EDU (Jim Frost) (02/29/88)

In article <446@cunixc.columbia.edu> ben@cunixc.columbia.edu (Ben Fried) writes:
>
>Has anyone implemented an MS-DOS version of the unix "popen" and
>"pclose" library routines for MS-DOS?  I'm porting a unix program to
>MS-DOS that uses those calls a lot.
>
>Please reply to me via mail - I don't read this newsgroup regularly.

[this was sent via email as well but it might interest other readers]

You may be in for quite a bit of trouble, depending on how the pipe
calls are to be used.

MS-DOS does not support multitasking.  Pipes as defined in UNIX
require this.  The closest you can come on MS-DOS is saving the output
from one program and invoking the next.  Of course, some programs
expect operation to be concurrent, and this really goofs them up.

Implementing popen() and pclose() is very simple if you don't need
multitasking:

-- cut here --
/* popen/pclose:
 *
 * simple MS-DOS piping scheme to imitate UNIX pipes
 */

/* information needed between popen and pclose
 */

static char *prgname[32];          /* program name if write pipe */
static int pipetype[32];           /* 1=read 2=write */
static char pipename[32][MAXFILE]; /* pipe file name */

/* open a pipe
 */

FILE *popen(prg,type)
char *prg,*type;
{ FILE *p;
  int ostdin;
  char tmpfile[MAXFILE];

  strcpy(tmpfile,ufilen()); /* get a unique file name */
  switch(*type) {

/* for write style pipe, pclose handles program execution
 */

    case 'w' :
      if ((p= fopen(tmpfile,"w")) != NULL) {
        pipetype[fileno(p)]= 1;
        strcpy(pipename[fileno(p)],tmpfile);
        prgname[fileno(p)]= prg;
      }
      return(p);

/* read pipe must create tmp file, set up stdout to point to the temp
 * file, and run the program.  note that if the pipe file cannot be
 * opened, it'll return a condition indicating pipe failure, which is
 * fine.
 */

    case 'r' :
      if ((p= fopen(tmpfile,"w")) != NULL) {
        pipetype[fileno(p)]= 2;
        strcpy(pipename[fileno(p)],tmpfile);
        ostdout= dup(fileno(stdout));   /* we need this later */
        dup2(fileno(stdout),fileno(p)); /* substitute for stdout */
        system(prg);                    /* run the program */
        dup2(fileno(stdout),ostdout);   /* repair stdout */
        fclose(p);                      /* close redirected stdout */
        return(fopen(tmpfile,"r"));     /* return pointer to tmp file */
      }
      return(NULL);                     /* everyone has their problems */

/* screwy call or unsupported type
 */

    default :
      printf("popen: unknown pipe style\n");
      exit(1);
  }
}

/* close a pipe
 */

void pclose(p)
FILE *p;
{ int n;
  int ostdout;
  FILE *p2;

  switch(pipetype[fileno(p)]) {

/* close the temp file, open again as read, redirect stdin from that
 * file, run the program, then clean up.
 */

    case 1 :
      n= fileno(p);
      fclose(p);
      if ((p2= fopen(pipename[n],"r")) != NULL) {
        ostdin= dup(fileno(stdin));     /* save stdin for later */
        dup2(fileno(stdin),fileno(p2)); /* redirect to tmp file */
        system(prgname[n]);             /* run the program */
        dup2(fileno(stdin),ostdin);     /* repair stdin */
        fclose(p2);
        unlink(pipename[n]);            /* erase tmp file */
        return;
      }
      printf("pclose: could not reopen temporary file\n");
      exit(1);

/* close the temp file and remove it
 */

    case 2 :
      n= fileno(p);        /* get file number for unlink */
      fclose(p);           /* close the file */
      unlink(pipename[n]); /* erase the file */
      return;

/* if we're neither read nor write, we have problems
 */

    default :
      printf("pclose: internal error\n");
      exit(1);
  }
}

-- cut here --

I haven't tried to debug these -- they're straight from my head -- but
they should give you the idea.  These won't be very robust.  Some
things that you might want to do:

	* replace system() calls with something else
	* clean up file redirection
	* give pipetype[] array entries that aren't being used a value
	  of 0 to make sure that the pipe was actually opened

For many applications, these routines should operate just as they would
in UNIX.

Good luck,

jim frost
madd@bu-it.bu.edu

madd@bu-cs.BU.EDU (Jim Frost) (02/29/88)

Addendum to my posting of simple popen/pclose routines:

The function ufilen() is undefined; what it is supposed to do is
return a pointer to a string containing a unique file name.  I suppose
a real simple one could be like this:

-- cut here --
/* ufilen.c:
 *
 * returns a unique file name
 */

char *ufilen()
{ static char name[10];
  static int num= 0;

  sprintf(name,"\\pipe%d.tmp",num++);
  return(name);
}
-- cut here --

This would at least create a unique name for each pipe created by that
process.  A variety of better methods exist (such as using the MS-DOS
[version 3.0 or greater] function 5ah, Create Unique File [not
recommended for this type of use though]), so alter as necessary.

jim frost
madd@bu-it.bu.edu