#include "types.h"
#include <signal.h>
#include <stdio.h>

#ifdef BSD
#define strchr(a,b) index(a,b)
#endif

#ifdef sun
typedef short uid_t;
#endif

/* Maximum size of command */
#define ARGSPACESIZE 1000

extern char *strchr ();

static uid_t *pids;
static int fds;

FILE *
vpopen (program, type)
     char *program, *type;
{
  FILE *iop;
  int argc, pdes[2], pid;
  char argspace[ARGSPACESIZE];
  char *argv[15];

  if (*type != 'r' && *type != 'w' || type[1])
    return (NULL);

  if (!pids)
    {
      if ((fds = getdtablesize ()) <= 0)
	return (NULL);
      if (!(pids = (uid_t *) malloc ((u_int) (fds * sizeof (uid_t)))))
	return (NULL);
      bzero (pids, fds * sizeof (uid_t));
    }
  if (pipe (pdes) < 0)
    return (NULL);

  /* break up string into pieces, put into argv, and \0 delimit */
  strncpy (argspace, program, ARGSPACESIZE);
  argv[0] = argspace;
  argc = 1;
  while (argv[argc] = strchr (argv[argc - 1], ' '))
    *(argv[argc++]++) = '\0';

  iop = NULL;
  switch (pid = vfork ())
    {
    case -1:			/* error */
      (void) close (pdes[0]);
      (void) close (pdes[1]);
      return iop;
      /* NOTREACHED */
    case 0:			/* child */
/*   (bub)
      if (*type == 'r')
	{
	  if (pdes[1] != 1)
	    {
	      dup2 (pdes[1], 1);
	      (void) close (pdes[1]);
	    }
	  * Try to get stderr piped as well. *
	  pdes[2] = 1;
	  (void) close (pdes[0]);
	}
      else
	{
	  if (pdes[0] != 0)
	    {
	      dup2 (pdes[0], 0);
	      (void) close (pdes[0]);
	    }
	  (void) close (pdes[1]);
	}
*/

      execv (argv[0], argv);
      _exit (1);
    }
  /* parent; assume fdopen can't fail...  */
  if (*type == 'r')
    {
      iop = fdopen (pdes[0], type);
      (void) close (pdes[1]);
    }
  else
    {
      iop = fdopen (pdes[1], type);
      (void) close (pdes[0]);
    }
  pids[fileno (iop)] = pid;

  return iop;
}

vpclose (iop)
     FILE *iop;
{
  register int fdes;
  long omask;
  int pid, stat_loc;
  u_int waitpid ();

  /*
   * pclose returns -1 if stream is not associated with a
   * `popened' command, or, if already `pclosed'.
   */
  if (pids[fdes = fileno (iop)] == 0)
    return (-1);
  (void) fclose (iop);
  /* This looks good (bub) */
  omask = sigblock (SIGINT | SIGQUIT | SIGHUP);
/*  omask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) | sigmask (SIGHUP));*/
  while ((pid = wait (&stat_loc)) != pids[fdes] && pid != -1) ;
  (void) sigsetmask (omask);
  pids[fdes] = 0;
  return (stat_loc);
}

FILE *
vpopen_grep (program, arg1, arg2, arg3, type)
     char *program, *type, *arg1, *arg2, *arg3;
{
  FILE *iop;
  int argc, pdes[3], pid;
  char argspace[ARGSPACESIZE];
  char *argv[15];

  if (*type != 'r' && *type != 'w' || type[1])
    return (NULL);

  if (!pids)
    {
      if ((fds = getdtablesize ()) <= 0)
	return (NULL);
      if (!(pids = (uid_t *) malloc ((u_int) (fds * sizeof (uid_t)))))
	return (NULL);
      bzero (pids, fds * sizeof (uid_t));
    }
  if (pipe (pdes) < 0)
    return (NULL);

  iop = NULL;
  switch (pid = vfork ())
    {
    case -1:			/* error */
      (void) close (pdes[0]);
      (void) close (pdes[1]);
      return iop;
      /* NOTREACHED */
    case 0:			/* child */
      if (*type == 'r')
	{
	  if (pdes[1] != 1)
	    {
	      dup2 (pdes[1], 1);
	      (void) close (pdes[1]);
	    }
	  /* Try to get stderr piped as well. */
	  pdes[2] = 1;
	  (void) close (pdes[0]);
	}
      else
	{
	  if (pdes[0] != 0)
	    {
	      dup2 (pdes[0], 0);
	      (void) close (pdes[0]);
	    }
	  (void) close (pdes[1]);
	}
      execl (program, program, arg1, arg2, arg3, 0);
      _exit (1);
    }
  /* parent; assume fdopen can't fail...  */
  if (*type == 'r')
    {
      iop = fdopen (pdes[0], type);
      (void) close (pdes[1]);
    }
  else
    {
      iop = fdopen (pdes[1], type);
      (void) close (pdes[0]);
    }
  pids[fileno (iop)] = pid;

  return iop;
}