🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.gcc.help
Article #50688

Re: popen in libc.a for MS-DOS

#50688
From: Elliott Pacetti
Date: Mon, 09 Aug 1993 21:41
278 lines
8244 bytes
Jose Osuna writes in help-gcc
>Does there exist a version of libc.a for PCs which contains the
>function popen? In stdio.h it is mentioned, but the library libc.a,
>at least the one I have, does not list it.
>
>Thanks for any hints
>
>Jose

  Here's a popen()/pclose I wrote for MSDOS you are welcome to
use.  It doesn't work exactly like UNIX popen()/pclose() but it
is the same principle.  It is somewhat documented so you
shouldn't have any problems using it.

Elliott

/*
   This is popen() and pclose() for MSDOG.  They were developed using
   Microsoft C, but should port easily to DOS C any compiler.

   These routines are hacks, that is they SIMULATE thier UNIX
   counterparts.  Since MSDOS and won't allow concurrent process spawning,
   you can't really pipe.  I came up with this nearly stupid way around
   piping because I wanted to have some portability between UNIX and MSDOS.
   I'm probably not the first person to have this idea or implement it, but
   I think I'm the first to give it away for free (no points?!).

   The functions simulate popen() and pclose() by redirecting stdin or
   stdout, then spawning a child processes via system().

   If you popen() for read, the stdout is redirected to a temporary
   file, and the child is spawned.  The stdout is reopened via dup2(), the
   temporary file is opened for read and a file pointer to it is returned.

   If you popen() for write, a temporary file is opened for write, and
   a file pointer to it is returned.  When you pclose(), the stdin is
   redirected to the temporary file and the child is spawned.

   In both cases, pclose() closes and unlinks the temporary file.

   A static linked list of C structures is built to store necessary
   info for all popen()ed files so you can popen() more than one file at
   a time.

   The popen() function will return NULL on an error, or a valid FILE
   *pointer on a successful open.  The pclose() function will return
   negative one (-1) on an error or zero (0) on a successful close.

   The function prototypes are:

   FILE *popen(command, mode)
        char *command, char *mode;

   int pclose(pp)
       FILE *pp;

   Where command is a character string equivilant to a MSDOS command
   line, mode is "r" for read or "w" for write, and pp is a pointer to a
   file opened through popen().

   A main() function has been included for testing purposes, to compile
   it define the preprocessor token TEST at compile time.
 */

#include <io.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>

/* function prototypes */
FILE *popen ();
int pclose ();

/* hold file pointer, descriptor, command, mode, temporary file name */
struct pipe_list
  {
    FILE *fp;
    int fd;
    char *command, mode[2], temp_name[13];
    struct pipe_list *next;
  };

/* static, global list pointer */
static struct pipe_list *pl = NULL;

FILE *
popen (cm, md)
     char *cm, *md;             /* program name, pipe mode */
{
  struct pipe_list *l1, *l2;
  static char *tn = NULL;       /* temporary file basename */

  if (!tn)
    if ((tn = mktemp ("pXXXXXX")) == NULL)
      return (NULL);

  /* make new node */
  if ((l1 = (struct pipe_list *) malloc (sizeof (struct pipe_list))) == NULL)
      return (NULL);

  /* zero out elemets to we'll get here */
  l1->fd = 0;
  l1->fp = NULL;
  l1->next = NULL;

  /* if empty list - just grab new node */
  if (!pl)
    pl = l1;
  else
    {
      /* otherwise, find last node in list */
      ++(l1->fd);
      l2 = pl;
      while (l2->next)
        {
          ++(l1->fd);
          l2 = l2->next;
        };
      /* add new node to list */
      l2->next = l1;
    }

  /* stick in elements we know already */
  strcpy (l1->mode, md);
  sprintf (l1->temp_name, "%s.%d", tn, l1->fd);

  /* if can save the program name, build temp file */
  if (l1->command = strdup (cm))
    {
      /* if caller wants to read */
      if (!strcmp (l1->mode, "r"))
        {
          /* dup stdout */
          if ((l1->fd = dup (fileno (stdout))) == EOF)
            l1->fp = NULL;
          else if (!(l1->fp = freopen (l1->temp_name, "wb", stdout)))
            l1->fp = NULL;
          else
            /* exec cmd */
          if (system (cm) == EOF)
            l1->fp = NULL;
          /* reopen real stdout */
          if (dup2 (l1->fd, fileno (stdout)) == EOF)
            l1->fp = NULL;
          else
            /* open file for reader */
            l1->fp = fopen (l1->temp_name, "r");
        }
      else
        /* if caller wants to write */
      if (!strcmp (l1->mode, "w"))
        /* open temp file */
        l1->fp = fopen (l1->temp_name, "w");
      else
        /* unknown mode */
        l1->fp = NULL;
    }
  return (l1->fp);              /* return == NULL ? ERROR : OK */
}

int
pclose (pp)
     FILE *pp;
{
  struct pipe_list *l1, *l2;    /* list pointers */
  int retval;                   /* function return value */

  /* if pointer is first node */
  if (pl->fp == pp)
    {
      /* save node and take it out the list */
      l1 = pl;
      pl = l1->next;
    }
  else
    /* if more than one node in list */
  if (pl->next)
    {
      /* find right node */
      for (l2 = pl, l1 = pl->next; l1; l2 = l1, l1 = l2->next)
        if (l1->fp == pp)
          break;

      /* take node out of list */
      l2->next = l1->next;
    }
  else
    return (-1);

  /* if FILE not in list - return error */
  if (l1->fp == pp)
    {
      /* close the (hopefully) popen()ed file */
      fclose (l1->fp);

      /* if pipe was opened to write */
      if (!strcmp (l1->mode, "w"))
        {
          /* dup stdin */
          if ((l1->fd = dup (fileno (stdin))) == EOF)
            retval = -1;
          else
            /* open temp stdin */
          if (!(l1->fp = freopen (l1->temp_name, "rb", stdin)))
            retval = -1;
          else
            /* exec cmd */
          if (system (l1->command) == EOF)
            retval = -1;
          else
            /* reopen stdin */
          if (dup2 (l1->fd, fileno (stdin)) == EOF)
            retval = -1;
        }
      else
        /* if pipe was opened to read */
      if (!strcmp (l1->mode, "r"))
        retval = 0;
      else
        /* invalid mode */
        retval = -1;
    }
  unlink (l1->temp_name);       /* remove temporary file */
  free (l1->command);           /* dealloc memory */
  free (l1);                    /* dealloc memory */
  l1 = NULL;                    /* make pointer bogus */

  return (retval);              /* retval==0 ? OK : ERROR */
}

#ifdef TEST
/* little test routine - for non-believers (like me).
   Note that it does no diagnostics!  It takes for granted
   that it will work! #define TEST to try it */
main ()
{
  FILE *pp1, *pp2, *pp3, *pp4;

  pp1 = popen ("find \"find\"", "w");
  Write2pipe (pp1);

  pp2 = popen ("dir /w", "r");
  Readfrompipe (pp2);

  pp3 = popen ("more", "w");
  Write2pipe (pp3);

  pp4 = popen ("dir", "r");
  Readfrompipe (pp4);

  pclose (pp1);
  pclose (pp3);
  pclose (pp4);
  pclose (pp2);
}

Write2pipe (pipe)
     FILE *pipe;
{
  char buf[81];
  FILE *pp;

  pp = fopen ("popen.c", "r");

  while (fgets (buf, 80, pp) != NULL)
    fprintf (pipe, "%s", buf);
}
Readfrompipe (pipe)
     FILE *pipe;
{
  char buf[81];

  while (fgets (buf, 80, pipe) != NULL)
    printf ("%s", buf);
}
#endif
Technical Details
Message-ID: <9308092137.AA03191@aeneas.MIT.EDU>
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!sol.ctr.columbia.edu!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!fl-ngnet.army.mil!pacetti

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 11318c,ac1d16f32193e6ad
X-Google-Attributes: gid11318c,public
X-Google-ArrivalTime: 1993-08-09 14:51:33 PST
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!sol.ctr.columbia.edu!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!fl-ngnet.army.mil!pacetti
From: pacetti@fl-ngnet.army.mil (Elliott Pacetti)
Newsgroups: gnu.gcc.help
Subject: Re:  popen in libc.a for MS-DOS
Date: 9 Aug 1993 17:41:04 -0400
Organization: GNUs Not Usenet
Lines: 278
Sender: daemon@cis.ohio-state.edu
Distribution: gnu
Message-ID: <9308092137.AA03191@aeneas.MIT.EDU>