/*
 *
 *	Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
 *    	Developed by the MIT Student Information Processing Board (SIPB).
 *    	For copying information, see the file mit-copyright.h in this release.
 *
 */
/*
 *	$Source: /afs/sipb.mit.edu/project/discuss/.cvsroot/discuss/source/libds/tmem.c,v $
 *	$Author: srz $
 *	$Header: /afs/sipb.mit.edu/project/discuss/.cvsroot/discuss/source/libds/tmem.c,v 1.7 1995/03/18 07:26:12 srz Exp $
 *
 *	tfile module for ``memory'' tfiles. 
 * 
 *	$Log: tmem.c,v $
 * Revision 1.7  1995/03/18  07:26:12  srz
 * Replace bcopy(), bzero() to mem... equivalents.
 *
 * Revision 1.6  1994/09/24  04:07:44  srz
 * Changed source tree to use configure instead of Imake.  Added WEAK_REALM
 * authentication.  Fixed up includes, etc, for new configure...  still needs
 * more testing.
 *
 * Revision 1.5  1994/09/19  03:47:24  raeburn
 * tcreate first arg is now an off_t
 *
 * Revision 1.4  1992/06/26 02:19:04  raeburn
 * getting in sync with current source tree
 *
 * Revision 1.3  89/06/03  00:22:16  srz
 * Added standard copyright notice.
 * 
 * Revision 1.2  89/06/03  00:13:07  srz
 * Ken's changes.
 * 
 * Revision 1.1  88/03/11  00:05:45  wesommer
 * Initial revision
 * 
 */

#ifndef lint
static char rcsid_tmem_c[] =
    "$Header: /afs/sipb.mit.edu/project/discuss/.cvsroot/discuss/source/libds/tmem.c,v 1.7 1995/03/18 07:26:12 srz Exp $";
#endif lint

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <string.h>

#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <discuss/tfile.h>

#define min(x,y) ((x)<(y)?(x):(y))

enum iovdir { SCATTER, GATHER };
	
static int iovmove (direct, iovpp, buf, len)
	register enum iovdir direct;
	struct iovec **iovpp;
	register char *buf;
	register int len;	
{
	register int moved = 0;
	register int count;
	register struct iovec *iovp;
	
	iovp = *iovpp;
	while (len > 0) {
		count = min (iovp->iov_len, len);
		if (direct == SCATTER) 
		        memcpy(iovp->iov_base, buf, count);
		else
		        memcpy(buf, iovp->iov_base, count);
		len -= count;
		moved += count;
		buf += count;
		iovp->iov_base += count;
		iovp->iov_len -= count;
		if (iovp->iov_len == 0) {
			iovp ++;
			if (iovp->iov_len == 0)
				break;
		}
	}
	*iovpp = iovp;
	return moved;
}

static int tmem(op, infop, info, argp, argn, result)
	int op, argn;
	register int *result, *info;
	char **infop, *argp;
{
	*result = 0;		/* optimist */
	switch (op) {
	case TFOPEN:
	case TFCLOSE:
		return 0;
	case TFREAD:
		return iovmove (GATHER, (struct iovec **)infop,
				argp, argn);
	case TFWRITE:
		return iovmove (SCATTER, (struct iovec **)infop,
				argp, argn);
	case TFDESTROY:
		if (*(char **)info)
			free (*(char **)info);
		return 0;
	default:
		*result = EINVAL;
		return -1;
	}
}

tfile mem_tfile (buffer, length)
	char *buffer;
	int length;
{
	register struct iovec *ts =
		(struct iovec *) malloc (2 * sizeof (struct iovec));
	ts[0].iov_base = buffer;
	ts[0].iov_len = length;
	ts[1].iov_len = 0;
	return tcreate ((off_t) length, (char *) ts, (int)ts, tmem);
}

tfile memv_tfile (vec)
	register struct iovec *vec;
{
	register int i, len;
	for (i=0, len = 0; vec[i].iov_len; i++)
		len += vec[i].iov_len;
		
	return tcreate ((off_t) len, (char *) vec, 0, tmem);
}
