 /*
  * Khoros: $Id: Pipe.c,v 1.3 1992/03/20 23:37:52 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: Pipe.c,v 1.3 1992/03/20 23:37:52 dkhoros Exp $";
#endif

 /*
  * $Log: Pipe.c,v $
 * Revision 1.3  1992/03/20  23:37:52  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name: Pipe.c					<<<<
   >>>>								<<<<
   >>>>   description: Khoros pipe (descriptor) routines	<<<<
   >>>>								<<<<
   >>>>      routines: pipe_tempnam				<<<<
   >>>>		       pipe_open				<<<<
   >>>>		       pipe_close				<<<<
   >>>>		       pipe_read				<<<<
   >>>>		       pipe_write				<<<<
   >>>>		       pipe_lseek				<<<<
   >>>>		       pipe_tell				<<<<
   >>>>		       pipe_access				<<<<
   >>>>		       pipe_unlink				<<<<
   >>>>		       pipe_lock				<<<<
   >>>>		       pipe_descriptors				<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



#ifdef KPIPE

#include "internals.h"	
#include "Pipe.h"	


/**************************************************************
*
* MODULE NAME: pipe_tempnam
*
*     PURPOSE: This function initializes a tempnam for a "pipe"
*	       type transport.  Given a request with a filename of
*	       the following syntax:
*
*			"pipe=[in,out]"
*			"pipe=-"
*			"pipe=#"
*
*	       This routine creates a pipe and returns the template
*	       in the following syntax:
*
*			"pipe=[in,out]"
*
*       INPUT: 
*
*        
*      OUTPUT:  depending whether we sucessfully created the template
*      		returns 0 or -1 if an error occurs
*
* CALLED FROM:  internal routine called from kopen()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int pipe_tempnam(identifier, template, result)

char *identifier;
char *template;
char *result;
{
	int	fid[2];


	/*
	 *  Create a pipe for the transport
	 */
	if (pipe(fid) == -1)
	{
	   perror("pipe_tempnam:   Pipe creation error....");
	   return(-1);
	}
	else
	{
	   if (identifier == NULL)
	      (void) sprintf(result,"pipe=[%d,%d]", fid[0], fid[1]);
	   else
	      (void) sprintf(result,"%s=[%d,%d]", identifier, fid[0], fid[1]);
	}
	return(0);
}

/**************************************************************
*
* MODULE NAME: pipe_open
*
*     PURPOSE: This function opens a "pipe" connection.  It is the
*	       internal driver to open a pipe, which is called by
*	       the user when they call kopen().  kopen() calls when
*	       it gets an open request with a filename of the following
*	       syntax:
*
*			"pipe=[in,out]"
*			"pipe=-"   (stdin or stdout)
*			"pipe=#"   (stderr)
*
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 if an error occurs
*
* CALLED FROM:  internal routine called from kopen()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int pipe_open(path, flags, mode, file)

char  *path;
int   flags;
int   mode;
kfile *file;
{
	int	   access, fid[2];
	ResourceStruct *resources;


	/*
	 *  Assign the string to the appropriate pipe.
	 */
	fid[0] = fid[1] = -1;
	if (sscanf(path," [ %d , %d ]", &fid[0], &fid[1]) != 2)
	{
	   if (strcmp(path,"-") == 0)
	   {
	      access = flags & O_ACCMODE;
	      if (access == O_RDONLY)
	         fid[0] = fileno(stdin);
	      else if (access == O_WRONLY)
	         fid[1] = fileno(stdout);
	      else
	      {
	         (void) fprintf(stderr,"pipe_open:  Invalid open mode...\n\n");
	         (void) fprintf(stderr,"  '-' can be opened for either reading \
or writing, but open access flags are\n  currently set to (%d)\n", access); 
	         return(-1);
	      }
	   }
	   else if (strcmp(path,"#") == 0)
	   {
	      fid[1] = fileno(stderr);
	   }
	}

	/*
	 *  See if the user wants the O_NONBLOCK set
	 */
	if (mode & O_NONBLOCK)
	{
	   fcntl(fid[0], F_SETFL, O_NONBLOCK);
	   fcntl(fid[1], F_SETFL, O_NONBLOCK);
	}

	/*
	 *  See if the user wants the O_NONBLOCK set
	 */
	if (mode & O_NDELAY)
	{
	   fcntl(fid[0], F_SETFL, O_NDELAY);
	   fcntl(fid[1], F_SETFL, O_NDELAY);
	}

	if (!(resources = (ResourceStruct *) calloc(1,sizeof(ResourceStruct))))
	{
	   (void) fprintf(stderr,"pipe_open:  Not enough memory....\n\n");
	   (void) fprintf(stderr," Unable to malloc (%d) bytes for the khoros \
pipe structure.\n", sizeof(ResourceStruct));
	   return(-1);
	}
	resources->fid[0] = fid[0];
	resources->fid[1] = fid[1];
	file->resources = (caddr_t) resources;
	return(0);
}



/**************************************************************
*
* MODULE NAME: pipe_close
*
*     PURPOSE: This function closes a "pipe".  It is the internal driver
*	       to close a data pipe, which is called by the user
*	       when they call kclose().  kclose() calls the "pipe" internal
*	       drivers by the nature of the transport, which is dictated
*	       by the initial kopen().
*
*
*       INPUT:  file - the kfile structure.
*
*      OUTPUT:  returns whether we were able to close the pipe
*
* CALLED FROM:  internal routine called from kclose()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int pipe_close(file)

kfile *file;
{
	int	   status;
	ResourceStruct *resources = (ResourceStruct *) file->resources;

	/*
	 *  Simply call close() since "kfile" is just a regular file
	 *  descriptor.
	 */
	if (resources->fid[0] != -1)
	   status = close(resources->fid[0]);
	if (resources->fid[1] != -1)
	   status = close(resources->fid[1]);
	return(status);
}



/**************************************************************
*
* MODULE NAME: pipe_read
*
*     PURPOSE: This function reads a "pipe".  It is the internal driver
*	       to read data from a pipe, which is called by the user
*	       when they call kread().  kread() calls the "pipe" internal
*	       drivers by the nature of the transport, which is dictated
*	       by the kopen().
*
*
*       INPUT:  file - the kfile structure.
*		ptr  - the pointer to store the data into.
*		nbytes - the number of bytes to read.
*
*      OUTPUT:  returns the number of bytes read from the file
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int pipe_read(file, ptr, nbytes)

kfile *file;
char  *ptr;
int   nbytes;
{
	int	   count;
	int	   numread = 0;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call read() since "kfile" is just a regular file
	 *  descriptor.
	 */
	do
	{
	   count = MIN(nbytes - numread, DefaultPageSize);
	   count = read(resources->fid[0], (char *) (ptr + numread), count);
	   numread += count;
	}
	while (numread < nbytes && count > 0);

	return(numread);
}



/**************************************************************
*
* MODULE NAME: pipe_write
*
*     PURPOSE: This function writes to a "pipe".  It is the internal driver
*	       to write data from the supplied data array to a pipe, which
*	       is called by the user when they call kwrite().  kwrite() calls
*	       the "pipe" internal drivers by the nature of the transport,
*	       which is dictated by the kopen().
*
*
*       INPUT:  id   - the kfile structure.
*		ptr  - the pointer to write the data from.
*		nbytes - the number of bytes to read.
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int pipe_write(file, ptr, nbytes)

kfile *file;
char  *ptr;
int   nbytes;
{
	int	   count;
	int	   numwrite = 0;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call write() since "kfile" is just a regular file
	 *  descriptor.
	 */
	do
	{
	    count = MIN(nbytes - numwrite, DefaultPageSize);
	    count = write(resources->fid[1], (char *) (ptr + numwrite), count);
	    numwrite += count;
	} while (numwrite < nbytes && count > 0);

	return(numwrite);
}



/**************************************************************
*
* MODULE NAME: pipe_lseek
*
*     PURPOSE: This function is used to do a "lseek".  It is the internal
*	       driver to rewind to a specific point so that the data can be
*	       skipped or re-read.  This is called when the user calls
*	       klseek().  klseek() calls the "pipe" internal drivers by the
*	       nature of the transport, which is dictated by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		offset - the offset in which to seek
*		whence - the control of how the offset will be applied
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int pipe_lseek(file, offset, whence)

kfile *file;
int   offset;
int   whence;
{
	int	   pos;
	ResourceStruct *resources = (ResourceStruct *) file->resources;

	/*
	 *  Simply call lseek() since "kfile" is just a regular file
	 *  descriptor.
	 */
	pos = lseek(resources->fid[0], offset, whence);
	return(pos);
}



/**************************************************************
*
* MODULE NAME: pipe_tell
*
*     PURPOSE: This function is used to do a "lseek".  It is the internal
*	       driver to rewind to a specific point so that the data can be
*	       skipped or re-read.  This is called when the user calls
*	       ktell().  ktell() calls the "pipe" internal drivers by the
*	       nature of the transport, which is dictated by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		offset - the offset in which to seek
*		whence - the control of how the offset will be applied
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int pipe_tell(file)

kfile *file;
{
	int	   pos;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call tell() since "kfile" is just a regular file
	 *  descriptor.
	 */
	pos = tell(resources->fid[0]);
	return(pos);
}



/**************************************************************
*
* MODULE NAME: pipe_unlink
*
*     PURPOSE: This function initializes a tempnam for a "file"
*	       type transport.  Given a request with a filename of
*	       the following syntax:
*
*			"pipe=[in,out]"
*
*       INPUT: 
*
*        
*      OUTPUT:  returns -1 or 0 depending whether we
*		sucessfully created the template
*
* CALLED FROM:  internal routine called from kunlink()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int pipe_unlink(identifier, filename)

char *identifier;
char *filename;
{
	int	fid[2], status1, status2;


	fid[0] = fid[1] = -1;
	(void) sscanf(filename," [ %d , %d ]", &fid[0], &fid[1]);

	if (fid[0] != -1)
	{
	   if ((status1 = close(fid[0])) == -1)
	      if (errno == EBADF) status1 = 0;
	}

	if (fid[1] != -1)
	{
	   if ((status2 = close(fid[1])) == -1)
	      if (errno == EBADF) status2 = 0;
	}
	return(status1 | status2);
}



/**************************************************************
*
* MODULE NAME: pipe_lock
*
*     PURPOSE: This function locks a "pipe" transport.  Given
*	       a request with a filename of the following syntax:
*
*			"pipe=[in,out]"
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 depending whether we
*		sucessfully created the template
*
* CALLED FROM:  internal routine called from kflock()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int pipe_lock(file, operation)

kfile *file;
int   operation;
{
	int	status;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	status = flock(resources->fid, operation);
	return(status);
}



/**************************************************************
*
* MODULE NAME: pipe_descriptors
*
*     PURPOSE: This function shouldn't exist, but there is occasion
*	       when the user wants to know the actual file descriptor
*	       associated with the file descriptor.
*
*       INPUT: file structure
*
*        
*      OUTPUT:  inum - the input file descriptor
*
* CALLED FROM:  internal routine called from kdescriptor()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int pipe_descriptors(file, inum, onum)

kfile *file;
int   *inum, *onum;
{
	int	status;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	if (inum != NULL) *inum = resources->fid[0];
	if (onum != NULL) *onum = resources->fid[1];
	return(0);
}

#endif  /* KPIPE */
/* don`t add after the endif */
