
static char rcsid[] =
	"$Id: pmsg.c,v 1.7 1997/06/27 17:32:33 pvmsrc Exp $";

/*
 *         PVM version 3.4:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  J. J. Dongarra, G. E. Fagg, M. Fischer
 *          G. A. Geist, J. A. Kohl, R. J. Manchek, P. Mucci,
 *         P. M. Papadopoulos, S. L. Scott, and V. S. Sunderam
 *                   (C) 1997 All Rights Reserved
 *
 *                              NOTICE
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted
 * provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * Neither the Institutions (Emory University, Oak Ridge National
 * Laboratory, and University of Tennessee) nor the Authors make any
 * representations about the suitability of this software for any
 * purpose.  This software is provided ``as is'' without express or
 * implied warranty.
 *
 * PVM version 3 was funded in part by the U.S. Department of Energy,
 * the National Science Foundation and the State of Tennessee.
 */

/*
 *	pmsg.c
 *
 *	Libpvm and pvmd message descriptors
 *
$Log: pmsg.c,v $
 * Revision 1.7  1997/06/27  17:32:33  pvmsrc
 * Updated for WIN32 header files & Authors.
 *
 * Revision 1.6  1997/04/30  21:32:14  pvmsrc
 * SGI Compiler Warning Cleanup.
 * 	- fixed up return codes for trace message packing stuff.
 *
 * Revision 1.5  1997/04/09  14:40:32  pvmsrc
 * PVM patches from the base 3.3.10 to 3.3.11 versions where applicable.
 * Originals by Bob Manchek. Altered by Graham Fagg where required.
 *
 * Fixes bogus XDR en/decoding when passing short values.
 * Original patch was meant for lpvmpack.c but code is now in pmsg.c
 *
 * Revision 1.4  1997/01/28  19:26:57  pvmsrc
 * New Copyright Notice & Authors.
 *
 * Revision 1.3  1996/10/25  13:57:32  pvmsrc
 * Replaced old #includes for protocol headers:
 * 	- <pvmsdpro.h>, "ddpro.h", "tdpro.h"
 * With #include of new combined header:
 * 	- <pvmproto.h>
 *
 * Revision 1.2  1996/10/24  22:09:21  pvmsrc
 * Moved #include "global.h" below other #include's for typing.
 * Added #include <pvmtev.h> & new "lpvm.h" for tracing & libpvm globals.
 * Added new user-defined trace event packing encoders:
 * 	- new enc_trc_init(), enc_trc_*() routines.
 * 	- new dec_trc_init(), dec_trc_*() routines.
 * 	- added new trace encoding vector in struct encvec encoders[],
 * 		with new selection in pmsg_setenc() for enc = 4 from
 * 		0x40000000 for user-defined tracing.
 *
 * Revision 1.1  1996/09/23  23:44:26  pvmsrc
 * Initial revision
 *
 *
 */

#include <stdio.h>
#ifdef NEEDMENDIAN
#include <machine/endian.h>
#endif
#ifdef NEEDENDIAN
#include <endian.h>
#endif
#ifdef NEEDSENDIAN
#include <sys/endian.h>
#endif
#ifndef WIN32
#include <rpc/types.h>
#include <rpc/xdr.h>
#else
#include "..\xdr\types.h"
#include "..\xdr\xdr.h"
#endif
#include <pvm3.h>
#include <pvmproto.h>
#include "pvmalloc.h"
#include "pvmfrag.h"
#include "pmsg.h"
#include "listmac.h"
#include "bfunc.h"
#include "lpvm.h"
#include <pvmtev.h>
#include "global.h"


/***************
 **  Globals  **
 **           **
 ***************/


/***************
 **  Private  **
 **           **
 ***************/

#ifdef	CLUMP_ALLOC
#ifndef	PMSG_CLUMP
#define	PMSG_CLUMP	50
#endif
static struct pmsg freepmsgs;			/* cache of pmsgs */
static int numpmsgs = 0;
#endif


/****************************
*  Generate data signature  *
*                           *
****************************/

static int
ibol(o, p, n)
	int o;
	char *p;
	int n;
{
	int i, j;

	if (p[0] == 0) {
		i = 0;	/* ll */
	} else if (p[0] == n - 1) {
		i = 3;	/* hh */
	} else if (p[0] == n / 2) {
		i = 2;	/* hl */
	} else if (p[0] == n / 2 - 1) {
		i = 1;	/* lh */
	} else {
		fprintf(stderr, "can't generate signature for my integer byte order\n");
		abort();
	}

	j = ffs(n) - 1;
/*
	printf(".%d%d.%d%d%d", (i & 2) ? 1 : 0, (i & 1) ? 1 : 0
			(j & 4) ? 1 : 0, (j & 2) ? 1 : 0, (j & 1) ? 1 : 0);
*/
	return ((i << 3) | j) << o;
}


/*
*  (float)1.0 =
*  IEEE single ll   00 00 80 3f
*  IEEE double ll   00 00 00 00 00 00 f0 3f
*  IEEE single hh   3f 80 00 00
*  IEEE double hh   3f f0 00 00 00 00 00 00
*  CRAY       (hh)  40 01 80 00 00 00 00 00
*  Convex s   (hh)  40 80 00 00
*  Convex d   (hh)  40 10 00 00 00 00 00 00
*  IBM370 s
*  IBM370 d
*  VAX xxxx?
*/

struct floatsig {
	int length;
	unsigned char *bytes;
	char *name;
};

/*
* signatures for float = 1.0 in hh byte order, all formats
*/

static unsigned char fs1[] = { 0x3f, 0x80, 0x00, 0x00 };
static unsigned char fs2[] = { 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static unsigned char fs4[] = { 0x40, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 };
static unsigned char fs5[] = { 0x40, 0x80, 0x00, 0x00 };
static unsigned char fs6[] = { 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

static struct floatsig thesigs[] = {
	{ 0, 0, "UNKNOWN" },
	{ 4, fs1, "IEEE_single" },
	{ 8, fs2, "IEEE_double" },
	{ 0, 0, "UNDEFINED" },
	{ 8, fs4, "Cray" },
	{ 4, fs5, "Convex_single" },
	{ 8, fs6, "Convex_double" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
	{ 0, 0, "UNDEFINED" },
};


static int
fbol(o, p, n)
	int o;
	unsigned char *p;
	int n;
{
	int i, j;

	for (i = 0; i < 16; i++) {
		if (thesigs[i].length == n) {
			for (j = 0; j < n; j++)
				if (p[j] != thesigs[i].bytes[j])
					break;
			if (j == n)
				return ((3 << 4) | i) << o;

			for (j = 0; j < n; j++)
				if (p[n - 1 - j] != thesigs[i].bytes[j])
					break;
			if (j == n)
				return i << o;
		}
	}
	fprintf(stderr, "can't generate signature for my integer byte order\n");
	abort();
	return 0;
}


/*	pvm_getdsig()
*
*	Return data signature for executable, describing representations
*	of integers and floats.
*
*	Bits:
*    0:2  short int size
*    3:4  short int byte order
*    5:7  int size
*    8:9  int byte order
*   10:12  long int size
*   13:14  long int byte order
*   15:18  float format
*   19:20  float byte order
*   21:24  double float format
*   25:26  double float byte order
*   27:31  0
*
*	Sizes are 2 ** (0..7) bytes
*	Byte order specifies overall order and half-folding:
*		00  Little endian (e.g. 0 1 2 3)
*		01  Little, but half-swapped (1 0 3 2 or 3 2 1 0 7 6 5 4)
*		10  Big, but half swapped (2 3 0 1 or 4 5 6 7 0 1 2 3)
*		11  Big endian (3 2 1 0)
*/

int
pvmgetdsig()
{
	static int myfmt = -1;

	short i0;
	int i1;
	long i2;
	float f0;
	double f1;
	int i, j;
	int fmt;

	if (myfmt != -1)
		return myfmt;

	fmt = 0;

	i0 = 0;
	for (i = 0; i < sizeof(i0); i++)
		i0 += (short)i << (i * 8);
	fmt |= ibol(0, (char *) &i0, (int) sizeof(i0));

	i1 = 0;
	for (i = 0; i < sizeof(i1); i++)
		i1 += (int)i << (i * 8);
	fmt |= ibol(5, (char *) &i1, (int) sizeof(i1));

	i2 = 0;
	for (i = 0; i < sizeof(i2); i++)
		i2 += (long)i << (i * 8);
	fmt |= ibol(10, (char *) &i2, (int) sizeof(i2));

	f0 = 1.0;
	fmt |= fbol(15, (unsigned char *) &f0, (int) sizeof(f0));

	f1 = 1.0;
	fmt |= fbol(21, (unsigned char *) &f1, (int) sizeof(f1));

	myfmt = fmt;
	return fmt;
}


/****************************
 **  Message manipulation  **
 **                        **
 ****************************/


static struct pmsg *
pmsg_get()
{
	struct pmsg *mp;
	int n;

#ifdef	CLUMP_ALLOC
	if (numpmsgs == 0) {
		freepmsgs.m_link = freepmsgs.m_rlink = &freepmsgs;
		if (!(mp = TALLOC(PMSG_CLUMP, struct pmsg, "pmsgs")))
			return (struct pmsg *)0;
		for (n = PMSG_CLUMP; n-- > 0; ) {
			LISTPUTBEFORE(&freepmsgs, mp, m_link, m_rlink);
			mp++;
		}
		numpmsgs = PMSG_CLUMP;
	}
	numpmsgs--;
	mp = freepmsgs.m_link;
	LISTDELETE(mp, m_link, m_rlink);

#else
	mp = TALLOC(1, struct pmsg, "pmsg");
#endif

	return mp;
}


static void
pmsg_put(mp)
	struct pmsg *mp;
{
#ifdef	CLUMP_ALLOC
	if (numpmsgs == 0)
		freepmsgs.m_link = freepmsgs.m_rlink = &freepmsgs;
	LISTPUTBEFORE(&freepmsgs, mp, m_link, m_rlink);
	numpmsgs++;

#else
	PVM_FREE(mp);
#endif
}


/*	pmsg_new()
*
*	Create a new message.
*	Returns pointer to message struct or NULL if no memory available.
*/

struct pmsg *
pmsg_new(master)
	int master;			/* true if a master (no data) node */
{
	struct pmsg *mp;

	if (!(mp = pmsg_get()))
		goto fail;

	mp->m_ref = 1;
	if (master) {
		mp->m_link = mp->m_rlink = mp;
		mp->m_frag = 0;
	} else {
		mp->m_link = mp->m_rlink = 0;
		if (!(mp->m_frag = fr_new(0))) {
			PVM_FREE(mp);
			goto fail;
		}
	}
	mp->m_codef = 0;
	mp->m_cfrag = 0;
	mp->m_mid = 0;
	mp->m_len = 0;
	mp->m_ctx = 0;
	mp->m_tag = 0;
	mp->m_wid = 0;
	mp->m_src = 0;
	mp->m_dst = 0;
	mp->m_enc = 0;
	mp->m_flag = 0;
	mp->m_cpos = 0;
	mp->m_crc = 0;
	return mp;

fail:
	return (struct pmsg *)0;
}


/*	pmsg_free()
*
*	Free a message or list of messages.  If m_frag is nonzero, this is
*	a slave node; unlink and free it and its frag list.  Else, it's
*	a master node; free all slave nodes too.
*/

static void
pmsg_free(mp)
	struct pmsg *mp;
{
	if (mp->m_frag) {	/* slave message */
		if (mp->m_link && mp->m_rlink) {
			LISTDELETE(mp, m_link, m_rlink);
		}
		fr_unref(mp->m_frag);

	} else {	/* master */
		while (mp->m_link != mp)
			pmsg_free(mp->m_link);
	}
	pmsg_put(mp);
}


/*	pmsg_unref()
*
*	Decrement message ref count, and free message if ref count reaches 0.
*/

void
pmsg_unref(mp)
	struct pmsg *mp;
{
	if (--mp->m_ref < 1)
		pmsg_free(mp);
}


/*	pmsg_extend()
*
*	Add a new empty fragment to the end of a message.
*/

int
pmsg_extend(mp)
	struct pmsg *mp;
{
	struct frag *fp;

	if (fp = fr_new(pvmfrgsiz)) {
		fp->fr_dat += MAXHDR;
		LISTPUTBEFORE(mp->m_frag, fp, fr_link, fr_rlink);
		return 0;
	}
	return PvmNoMem;
}


/*	pmsg_decmore()
*
*	Step to the next fragment to unpack.
*/

int
pmsg_decmore(mp)
	struct pmsg *mp;
{
#if 0
	mp->m_cpos = 0;
	if (mp->m_cfrag == mp->m_frag)		/* no message left */
		return PvmNoData;
	mp->m_cfrag = mp->m_cfrag->fr_link;
	if (mp->m_cfrag == mp->m_frag)
		return PvmNoData;
	return 0;
#endif
	mp->m_cpos = 0;
	if (mp->m_cfrag == mp->m_frag)		/* no message left */
		return PvmNoData;
	while ((mp->m_cfrag = mp->m_cfrag->fr_link) != mp->m_frag)
		if (mp->m_cfrag->fr_len > 0)
			break;
	if (mp->m_cfrag == mp->m_frag)
		return PvmNoData;
	return 0;
}


/*	bytepk()
*
*	Insert a stream of bytes into message.  Allocate more fragments as
*	necessary.
*	Returns 0 else PvmNoMem if malloc fails.
*/

static int
bytepk(mp, cp, num, siz, lnc)
	struct pmsg *mp;
	char *cp;			/* base of data */
	int num;			/* num of chunks */
	int siz;			/* size of chunk */
	int lnc;			/* lead to next chunk */
{
	struct frag *fp;			/* working frag */
	int togo;					/* bytes left in chunk */
	int r;						/* bytes (space) left in frag */

	if (siz == lnc) {		/* if contiguous, treat as single chunk */
		lnc = (siz *= num);
		num = 1;
	}
	lnc -= siz;		/* now bytes between chunks */

	while (num-- > 0) {		/* copy chunks until done */

		for (togo = siz; togo > 0; ) {
			fp = mp->m_frag->fr_rlink;
			r = fp->fr_max - (fp->fr_dat - fp->fr_buf) - fp->fr_len;

			if (togo <= r) {	/* space in frag for entire chunk */
				BCOPY(cp, fp->fr_dat + fp->fr_len, togo);
				fp->fr_len += togo;
				cp += togo;
				togo = 0;

			} else {
				if (r > 0) {	/* space for part of chunk */
					BCOPY(cp, fp->fr_dat + fp->fr_len, r);
					fp->fr_len += r;
					togo -= r;
					cp += r;

				} else {		/* no space, add new frag */
					if (r = pmsg_extend(mp))
						return r;
				}
			}
		}
		cp += lnc;
	}
	return 0;
}


/*	byteupk()
*
*	Extract bytes from message, continuing to new fragments as necessary.
*	Returns 0 else PvmNoData if end of message reached early.
*/

#ifdef IMA_CSPP
static void pre_bcopy(unsigned int s1, unsigned int s2, int n);
#endif

static int
byteupk(mp, cp, num, siz, lnc)
	struct pmsg *mp;
	char *cp;			/* base of data */
	int num;			/* num of chunks */
	int siz;			/* size of chunk */
	int lnc;			/* lead to next chunk */
{
	struct frag *fp;			/* working frag */
	int togo;					/* bytes left in chunk */
	int r;						/* bytes (data) left in frag */
#ifdef IMA_CSPP
	int diff_node = mp->m_flag & UB_DIFFNODE;
#endif

	if (siz == lnc) {		/* if contiguous, treat as single chunk */
		lnc = (siz *= num);
		num = 1;
	}
	lnc -= siz;		/* now bytes between chunks */

	while (num-- > 0) {		/* copy chunks until done */

		for (togo = siz; togo > 0; ) {
			fp = mp->m_cfrag;
			r = fp->fr_len - mp->m_cpos;

			if (togo <= r) {	/* frag contains rest of chunk */
#ifdef IMA_CSPP
				fp->fr_num_unpacked += togo;
				if (diff_node) {
					pre_bcopy((unsigned int)(fp->fr_dat + mp->m_cpos),
							(unsigned int)cp, togo);
				} else
#endif
				BCOPY(fp->fr_dat + mp->m_cpos, cp, togo);
				mp->m_cpos += togo;
				cp += togo;
				togo = 0;

			} else {
				if (r > 0) {	/* frag contains part of chunk */
#ifdef IMA_CSPP
					fp->fr_num_unpacked += r;
					if (diff_node) {
						pre_bcopy((unsigned int)(fp->fr_dat + mp->m_cpos),
								(unsigned int)cp, r);
					} else
#endif
					BCOPY(fp->fr_dat + mp->m_cpos, cp, r);
					mp->m_cpos += r;
					togo -= r;
					cp += r;

				} else {		/* no space, add new frag */
					if (r = pmsg_decmore(mp))
						return r;
				}
			}
		}
		cp += lnc;
	}
	return 0;
}


/***************************
 **  Raw-format encoders  **
 **                       **
 ***************************/

/*	enc_raw_init()
*
*	Initialize a message buffer to pack raw data.
*/

static int
enc_raw_init(mp)
	struct pmsg *mp;
{
	if (!(mp->m_flag & MM_PACK)) {
		mp->m_flag &= ~MM_UPACK;
		mp->m_flag |= MM_PACK;
		if (mp->m_frag->fr_link == mp->m_frag)
			return pmsg_extend(mp);
	}
	return 0;
}


/*	dec_raw_init()
*
*	Initialize a message buffer to unpack raw data.
*/

static int
dec_raw_init(mp)
	struct pmsg *mp;
{
	if (!(mp->m_flag & MM_UPACK)) {
		mp->m_flag &= ~MM_PACK;
		mp->m_flag |= MM_UPACK;
		mp->m_cfrag = mp->m_frag->fr_link;
		mp->m_cpos = 0;
	}
	return 0;
}


/*	enc_raw_any()
*
*	Encode any data type into a raw format message buffer.
*/

static int
enc_raw_any(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return bytepk(mp, (char*)vp, cnt, siz, std * siz);
}


/*	dec_raw_any()
*
*	Decode any data type from a raw format message buffer.
*/

static int
dec_raw_any(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return byteupk(mp, (char*)vp, cnt, siz, std * siz);
}


/***************************
 **  XDR-format encoders  **
 **                       **
 ***************************/

#ifdef FAKEXDRFLOAT

/*
** These two are missing on some machines.
*/

static int
xdr_float(xdrp, fp)
	XDR *xdrp;
	float *fp;
{
	return xdr_long(xdrp, (long*)fp);
}


static int
xdr_double(xdrp, dp)
	XDR *xdrp;
	double *dp;
{
	return xdr_long(xdrp, (long*)dp + 1) && xdr_long(xdrp, (long*)dp);
}

#endif/*FAKEXDRFLOAT*/

#if	defined(BOGUSXDR)

/*
** Encoders for machines without XDR routines but with XDR-format
** data.
*/

static int
enc_xdr_init(mp)
	struct pmsg *mp;
{
    return enc_raw_init();
}

static int
enc_xdr_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
	struct frag *fp;
	int cc;

	fp = mp->m_frag->fr_rlink;
	if (cc = bytepk(mp, (char*)vp, cnt, siz, std * siz))
		return cc;
	fp->fr_len = (fp->fr_len + 3) & ~3;
	return 0;
}

static int
enc_xdr_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register short *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (short*)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[3] = *cp;
        buf[2] = *(cp+1);
        if (cc = bytepk(mp, buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register int *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (int *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[3] = *cp;
        buf[2] = *(cp+1);
        buf[1] = *(cp+2);
        buf[0] = *(cp+3);
        if (cc = bytepk(mp, buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register long *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (long *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[3] = *cp;
        buf[2] = *(cp+1);
        buf[1] = *(cp+2);
        buf[0] = *(cp+3);
        if (cc = bytepk(mp, buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register float *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (float *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[3] = *cp;
        buf[2] = *(cp+1);
        buf[1] = *(cp+2);
        buf[0] = *(cp+3);
        if (cc = bytepk(mp, buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register double *np;
    register char *cp;
    char     buf[8];
    int cc = 0;

    for (np = (double *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[7] = *cp;
        buf[6] = *(cp+1);
        buf[5] = *(cp+2);
        buf[4] = *(cp+3);
        buf[3] = *(cp+4);
        buf[2] = *(cp+5);
        buf[1] = *(cp+6);
        buf[0] = *(cp+7);
        if (cc = bytepk(mp, buf, 8, 1, 1))
            return cc;
    }
    return 0;
}

typedef struct {float r, i;} complex;
typedef struct {double r, i;} dcplx;

static int
enc_xdr_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register complex *np;
    register char *cp;
    char buf[8];
    int cc = 0;

    for (np = (complex *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[3] = *cp;
        buf[2] = *(cp+1);
        buf[1] = *(cp+2);
        buf[0] = *(cp+3);
        buf[7] = *(cp+4);
        buf[6] = *(cp+5);
        buf[5] = *(cp+6);
        buf[4] = *(cp+7);
        if (cc = bytepk(mp, buf, 8, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register dcplx *np;
    register char *cp;
    char buf[16];
    int cc = 0;

    for (np = (dcplx *)vp; cnt-- > 0; np += std) {
        cp = (char *)np;
        buf[7] = *cp;
        buf[6] = *(cp+1);
        buf[5] = *(cp+2);
        buf[4] = *(cp+3);
        buf[3] = *(cp+4);
        buf[2] = *(cp+5);
        buf[1] = *(cp+6);
        buf[0] = *(cp+7);
        buf[15] = *(cp+8);
        buf[14] = *(cp+9);
        buf[13] = *(cp+10);
        buf[12] = *(cp+11);
        buf[11] = *(cp+12);
        buf[10] = *(cp+13);
        buf[9] = *(cp+14);
        buf[8] = *(cp+15);
        if (cc = bytepk(mp, buf, 16, 1, 1))
            return cc;
    }
    return 0;
}

static int
dec_xdr_init(mp)
	struct pmsg *mp;
{
    return dec_raw_init();
}

static int
dec_xdr_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
	int cc;

	if (cc = byteupk(mp, (char*)vp, cnt, siz, std * siz))
		return cc;
	mp->m_cpos = (mp->m_cpos + 3) & ~3;
	return 0;
}

static int
dec_xdr_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register short *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (short*)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 4, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[3];
        *(cp+1) = buf[2];
    }
    return 0;
}

static int
dec_xdr_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register int *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (int *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 4, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[3];
        *(cp+1) = buf[2];
        *(cp+2) = buf[1];
        *(cp+3) = buf[0];
    }
    return 0;
}

static int
dec_xdr_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register long *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (long *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 4, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[3];
        *(cp+1) = buf[2];
        *(cp+2) = buf[1];
        *(cp+3) = buf[0];
    }
    return 0;
}

static int
dec_xdr_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register float *np;
    register char *cp;
    char     buf[4];
    int cc = 0;

    for (np = (float *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 4, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[3];
        *(cp+1) = buf[2];
        *(cp+2) = buf[1];
        *(cp+3) = buf[0];
    }
    return 0;
}

static int
dec_xdr_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register double *np;
    register char *cp;
    char     buf[8];
    int cc = 0;

    for (np = (double *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 8, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[7];
        *(cp+1) = buf[6];
        *(cp+2) = buf[5];
        *(cp+3) = buf[4];
        *(cp+4) = buf[3];
        *(cp+5) = buf[2];
        *(cp+6) = buf[1];
        *(cp+7) = buf[0];
    }
    return 0;
}

static int
dec_xdr_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register complex *np;
    register char *cp;
    char     buf[8];
    int cc = 0;

    for (np = (complex *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 8, 1, 1))
            return cc;
        cp = (char *)np;
        *cp = buf[3];
        *(cp+1) = buf[2];
        *(cp+2) = buf[1];
        *(cp+3) = buf[0];
        *(cp+4) = buf[7];
        *(cp+5) = buf[6];
        *(cp+6) = buf[5];
        *(cp+7) = buf[4];
    }
    return 0;
}

static int
dec_xdr_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
    void *vp;
    int cnt, std, siz;
{
    register dcplx *np;
    register char *cp;
    char     buf[16];
    int cc = 0;

    for (np = (dcplx *)vp; cnt-- > 0; np += std) {
        if (cc = byteupk(mp, buf, 16, 1, 1))
            return cc;
        cp = (char *)np;
        *cp     = buf[7];
        *(cp+1) = buf[6];
        *(cp+2) = buf[5];
        *(cp+3) = buf[4];
        *(cp+4) = buf[3];
        *(cp+5) = buf[2];
        *(cp+6) = buf[1];
        *(cp+7) = buf[0];
        *(cp+8) = buf[15];
        *(cp+9) = buf[14];
        *(cp+10) = buf[13];
        *(cp+11) = buf[12];
        *(cp+12) = buf[11];
        *(cp+13) = buf[10];
        *(cp+14) = buf[9];
        *(cp+15) = buf[8];
    }
    return 0;
}

#else	/*BOGUSXDR*/

/*
** These are the normal XDR encoders for machines with XDR functions.
*/

/*	enc_xdr_init()
*
*	Initialize a message buffer to pack XDR format data
*/

static int
enc_xdr_init(mp)
	struct pmsg *mp;
{
	struct frag *fp;
	int cc;

	if (!(mp->m_flag & MM_PACK)) {
		mp->m_flag &= ~MM_UPACK;
		mp->m_flag |= MM_PACK;
		if ((fp = mp->m_frag->fr_link) == mp->m_frag) {
			if (cc = pmsg_extend(mp))
				return cc;
			fp = fp->fr_link;
		}

		xdrmem_create(&mp->m_xdr,
				fp->fr_dat,
				(unsigned)(fp->fr_max - (fp->fr_dat - fp->fr_buf)),
				XDR_ENCODE);
	}
	return 0;
}


/*	enc_xdr_step()
*
*	Add a new fragment to an XDR format message
*/

static int
enc_xdr_step(mp)
	struct pmsg *mp;
{
	struct frag *fp;
	int cc;

	if (cc = pmsg_extend(mp))
		return cc;
	fp = mp->m_frag->fr_rlink;
	xdrmem_create(&mp->m_xdr,
			fp->fr_dat,
			(unsigned)(fp->fr_max - (fp->fr_dat - fp->fr_buf)),
			XDR_ENCODE);
	return 0;
}


static int
enc_xdr_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	struct frag *fp;
	int cc;

	fp = mp->m_frag->fr_rlink;
	if (cc = bytepk(mp, (char*)vp, cnt, 1, std))
		return cc;
	if (fp != mp->m_frag->fr_rlink) {
		fp = mp->m_frag->fr_rlink;
		xdrmem_create(&mp->m_xdr,
				fp->fr_dat,
				(unsigned)(fp->fr_max - (fp->fr_dat - fp->fr_buf)),
				XDR_ENCODE);
	}
	fp->fr_len = (fp->fr_len + 3) & ~3;
	xdr_setpos(&mp->m_xdr, fp->fr_len);
	return 0;
}


static int
enc_xdr_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register short *np;
	int cc = 0;

	for (np = (short*)vp; cnt-- > 0; np += std)
		if (!xdr_short(&mp->m_xdr, np)) {
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_short(&mp->m_xdr, np)) {
					cc = PvmNoMem;
					break;
				}
		}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register int *np;
	int cc = 0;

	for (np = (int*)vp; cnt-- > 0; np += std)
		if (!xdr_int(&mp->m_xdr, np)) {
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_int(&mp->m_xdr, np)) {
					cc = PvmNoMem;
					break;
				}
		}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register long *np;
	int cc = 0;

	for (np = (long*)vp; cnt-- > 0; np += std)
		if (!xdr_long(&mp->m_xdr, np)) {
			if ((*np & ~(long)0x7fffffff)
			&& (*np & ~(long)0x7fffffff) != ~(long)0x7fffffff) {
				cc = PvmOverflow;
				break;
			}
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_long(&mp->m_xdr, np)) {
					cc = PvmNoMem;
					break;
				}
		}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_ulong(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register unsigned long *np;
	int cc = 0;

	for (np = (unsigned long*)vp; cnt-- > 0; np += std)
		if (!xdr_u_long(&mp->m_xdr, np)) {
			if (*np & ~(long)0xffffffff) {
				cc = PvmOverflow;
				break;
			}
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_u_long(&mp->m_xdr, np)) {
					cc = PvmNoMem;
					break;
				}
		}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register float *fp;
	int cc = 0;

	for (fp = (float*)vp; cnt-- > 0; fp += std)
		if (!xdr_float(&mp->m_xdr, fp)) {
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, fp)) {
					cc = PvmNoMem;
					break;
				}
		}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register double *dp;
	int cc = 0;
	int n;

	for (dp = (double*)vp; cnt-- > 0; dp += std) {
		if (!xdr_double(&mp->m_xdr, dp)) {
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, dp)) {
					cc = PvmNoMem;
					break;
				}
		}
		mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	}
	return cc;
}


static int
enc_xdr_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register float *xp;
	int cc = 0;

	std = std * 2 - 1;
	for (xp = (float*)vp; cnt-- > 0; xp += std) {
		if (!xdr_float(&mp->m_xdr, xp)) {
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, xp)) {
					cc = PvmNoMem;
					break;
				}
		}
		xp++;
		if (!xdr_float(&mp->m_xdr, xp)) {
			mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, xp)) {
					cc = PvmNoMem;
					break;
				}
		}
	}
	mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
enc_xdr_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register double *zp;
	int cc = 0;

	std = std * 2 - 1;
	for (zp = (double*)vp; cnt-- > 0; zp += std) {
		if (!xdr_double(&mp->m_xdr, zp)) {
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, zp)) {
					cc = PvmNoMem;
					break;
				}
		}
		mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
		zp++;
		if (!xdr_double(&mp->m_xdr, zp)) {
			if (cc = enc_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, zp)) {
					cc = PvmNoMem;
					break;
				}
		}
		mp->m_frag->fr_rlink->fr_len = xdr_getpos(&mp->m_xdr);
	}
	return cc;
}


/*	dec_xdr_init()
*
*	Initialize a message buffer to unpack XDR format data.
*/

static int
dec_xdr_init(mp)
	struct pmsg *mp;
{
	struct frag *fp = mp->m_frag->fr_link;

	if (!(mp->m_flag & MM_UPACK)) {
		mp->m_flag &= ~MM_PACK;
		mp->m_flag |= MM_UPACK;
		mp->m_cfrag = fp;
		mp->m_cpos = 0;
		xdrmem_create(&mp->m_xdr, fp->fr_dat, (unsigned)(fp->fr_len),
				XDR_DECODE);
	}
	return 0;
}


/*	dec_xdr_step()
*
*	Step to the next fragment of an XDR format message.
*
*	The current fragment might not be fully consumed - messages are
*	refragmented on 4-byte boundaries, but XDR 'atomic' sizes for
*	us are 4 bytes and 8 bytes (doubles).
*	If the next fragment exists, copy the remaining bytes to the head
*	of its buffer and continue unpacking.
*	XXX 1. There might not be enough headroom (unlikely).
*	XXX 2. If we share databufs we can't modify them (maybe?).
*/

static int
dec_xdr_step(mp)
	struct pmsg *mp;
{
	struct frag *fp;
	int cc;
	int l;
	char *p;

	if (mp->m_cpos != mp->m_cfrag->fr_len) {
		p = mp->m_cfrag->fr_dat + mp->m_cpos;
		l = mp->m_cfrag->fr_len - mp->m_cpos;

		if (cc = pmsg_decmore(mp))
			return cc;

		fp = mp->m_cfrag;
		if (fp->fr_dat - fp->fr_buf < l) {
			pvmlogerror("aaugh, no space for fixup, kill me\n");
			return PvmBadMsg;

		} else {
/*
			pvmlogprintf("fragment has %d bytes left, doing fixup\n", l);
*/
			fp->fr_dat -= l;
			fp->fr_len += l;
			BCOPY(p, fp->fr_dat, l);
		}

	} else {
		if (cc = pmsg_decmore(mp))
			return cc;
		fp = mp->m_cfrag;
	}
	xdrmem_create(&mp->m_xdr, fp->fr_dat, (unsigned)(fp->fr_len),
			XDR_DECODE);
	return 0;
}


static int
dec_xdr_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	struct frag *fp;
	int cc;

	fp = mp->m_cfrag;
	if (cc = byteupk(mp, (char*)vp, cnt, 1, std))
		return cc;
	if (fp != mp->m_cfrag) {
		fp = mp->m_cfrag;
		xdrmem_create(&mp->m_xdr, fp->fr_dat, (unsigned)(fp->fr_len),
				XDR_DECODE);
	}
	mp->m_cpos = (mp->m_cpos + 3) & ~3;
	xdr_setpos(&mp->m_xdr, mp->m_cpos);
	return 0;
}


static int
dec_xdr_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register short *np;
	int cc = 0;

	for (np = (short*)vp; cnt-- > 0; np += std)
		if (!xdr_short(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_short(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register int *np;
	int cc = 0;

	for (np = (int*)vp; cnt-- > 0; np += std)
		if (!xdr_int(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_int(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register long *np;
	int cc = 0;

	for (np = (long*)vp; cnt-- > 0; np += std)
		if (!xdr_long(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_long(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_ushort(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register unsigned short *np;
	int cc = 0;

	for (np = (unsigned short*)vp; cnt-- > 0; np += std)
		if (!xdr_u_short(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_u_short(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_uint(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register unsigned int *np;
	int cc = 0;

	for (np = (unsigned int*)vp; cnt-- > 0; np += std)
		if (!xdr_u_int(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_u_int(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_ulong(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register unsigned long *np;
	int cc = 0;

	for (np = (unsigned long*)vp; cnt-- > 0; np += std)
		if (!xdr_u_long(&mp->m_xdr, np)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_u_long(&mp->m_xdr, np)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register float *fp;
	int cc = 0;

	for (fp = (float*)vp; cnt-- > 0; fp += std)
		if (!xdr_float(&mp->m_xdr, fp)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, fp)) {
					cc = PvmNoData;
					break;
				}
		}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register double *dp;
	int cc = 0;

	for (dp = (double*)vp; cnt-- > 0; dp += std) {
		if (!xdr_double(&mp->m_xdr, dp)) {
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, dp)) {
					cc = PvmNoData;
					break;
				}
		}
		mp->m_cpos = xdr_getpos(&mp->m_xdr);
	}
	return cc;
}


static int
dec_xdr_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register float *xp;
	int cc = 0;

	std = std * 2 - 1;
	for (xp = (float*)vp; cnt-- > 0; xp += std) {
		if (!xdr_float(&mp->m_xdr, xp)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, xp)) {
					cc = PvmNoData;
					break;
				}
		}
		xp++;
		if (!xdr_float(&mp->m_xdr, xp)) {
			mp->m_cpos = xdr_getpos(&mp->m_xdr);
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_float(&mp->m_xdr, xp)) {
					cc = PvmNoData;
					break;
				}
		}
	}
	mp->m_cpos = xdr_getpos(&mp->m_xdr);
	return cc;
}


static int
dec_xdr_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	register double *zp;
	int cc = 0;

	std = std * 2 - 1;
	for (zp = (double*)vp; cnt-- > 0; zp += std) {
		if (!xdr_double(&mp->m_xdr, zp)) {
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, zp)) {
					cc = PvmNoData;
					break;
				}
		}
		mp->m_cpos = xdr_getpos(&mp->m_xdr);
		zp++;
		if (!xdr_double(&mp->m_xdr, zp)) {
			if (cc = dec_xdr_step(mp))
				break;
			else
				if (!xdr_double(&mp->m_xdr, zp)) {
					cc = PvmNoData;
					break;
				}
		}
		mp->m_cpos = xdr_getpos(&mp->m_xdr);
	}
	return cc;
}

#endif	/*BOGUSXDR*/

/*************************
 **  In-place encoders  **
 **                     **
 *************************/

static int
enc_inp_init(mp)
	struct pmsg *mp;
{
	return 0;
}


static int
enc_inp_any(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	struct frag *fp;

	if (std != 1)
		return PvmNotImpl;
	if (vp && cnt && siz) {
		fp = fr_snew((char *)vp, cnt * siz);
		LISTPUTBEFORE(mp->m_frag, fp, fr_link, fr_rlink);
	}
#if 0
	if (std != 1) {
		if (std < 1)
			return PvmBadParam;
		fp->fr_max = fp->fr_len = siz + (cnt - 1) * std * siz;
		fp->fr_csz = siz;
		fp->fr_lnc = std * siz;
		fp->fr_u.spr = 1;
	}
#endif
	return 0;
}


/*********************
 **  Trace encoders **
 **                 **
 *********************/

static int
enc_trc_init(mp)
	struct pmsg *mp;
{
	struct timeval timestamp;

	int tmp;
	int cc;

	gettimeofday( &timestamp, (struct timezone *) 0 );

	if ( (cc = enc_xdr_init(mp)) )
		return( cc );

	tmp = TEV_MARK_USER_EVENT_RECORD;
	if ((cc = enc_xdr_int(mp, (void *) &tmp, 1, 1, (int) sizeof(int))))
		return( cc );

	tmp = TEV_USER_DEFINED;
	if ((cc = enc_xdr_int(mp, (void *) &tmp, 1, 1, (int) sizeof(int))))
		return( cc );

	tmp = strlen( pvmtevinfo[TEV_USER_DEFINED].name ) + 1;
	if ((cc = enc_xdr_int(mp, (void *) &tmp, 1, 1, (int) sizeof(int))))
		return( cc );

	if ((cc = enc_xdr_byte(mp,
			(void *)(pvmtevinfo[TEV_USER_DEFINED].name), tmp, 1, 1)))
		return( cc );

	if ((cc = enc_xdr_int(mp, (void *) &(timestamp.tv_sec), 1, 1,
			(int) sizeof(int))))
		return( cc );
	if ((cc = enc_xdr_int(mp, (void *) &(timestamp.tv_usec), 1, 1,
			(int) sizeof(int))))
		return( cc );

	return( 0 );
}

int /* not static */
enc_trc_fin(mp)
	struct pmsg *mp;
{
	int tmp;

	tmp = TEV_MARK_USER_EVENT_RECORD_END;
	return( enc_xdr_int(mp, (void *) &tmp, 1, 1, (int) sizeof(int)) );
}

static int
enc_trc_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_BYTE | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_BYTE | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_byte(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_SHORT | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_SHORT | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_short(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_INT | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_INT | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_int(mp, vp, cnt, std, siz);
	}

	/* Weasel Hack to Sneak in Trace Markers, with cnt == 0...  :-)   */
	/* Need to be able to insert markers without other data type and  */
	/* array size crapola - it's either this or a new pvm_pkmarker()  */
	/* routine and an enc_mrk for each encoding (which is more bogus).*/
	else if ( vp != NULL && *((int *) vp) < 0 ) {
		return enc_xdr_int(mp, vp, 1, 1, (int) sizeof(int));
	}

	return 0;
}

static int
enc_trc_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_LONG | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_LONG | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_long(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_ulong(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_ULONG | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_ULONG | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
#if	defined(I860_NODE)
		/* XXX are handwritten anyhow */
		return enc_xdr_long(mp, vp, cnt, std, siz);
#else
		return enc_xdr_ulong(mp, vp, cnt, std, siz);
#endif
	}
	return 0;
}

static int
enc_trc_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_FLOAT | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_FLOAT | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_float(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_DOUBLE | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_DOUBLE | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_double(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_CPLX | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_CPLX | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_cplx(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
enc_trc_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	int type;
	int cc;

	if ( cnt )
	{
		if ( cnt == 1 ) {
			type = TEV_DATA_DCPLX | TEV_DATA_SCALAR;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		else {
			type = TEV_DATA_DCPLX | TEV_DATA_ARRAY;
			if ( (cc = enc_xdr_int(mp, (void *) &type, 1, 1,
					(int) sizeof(int))) )
				return cc;
			if ( (cc = enc_xdr_int(mp, (void *) &cnt, 1, 1,
					(int) sizeof(int))) )
				return cc;
		}
		return enc_xdr_dcplx(mp, vp, cnt, std, siz);
	}
	return 0;
}

static int
dec_trc_init(mp)
	struct pmsg *mp;
{
	return dec_xdr_init(mp);
}

static int
dec_trc_byte(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_byte(mp, vp, cnt, std, siz);
}

static int
dec_trc_short(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_short(mp, vp, cnt, std, siz);
}

static int
dec_trc_int(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_int(mp, vp, cnt, std, siz);
}

static int
dec_trc_long(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_long(mp, vp, cnt, std, siz);
}

static int
dec_trc_ushort(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
#if	defined(I860_NODE)
	/* XXX are handwritten anyhow */
	return dec_xdr_short(mp, vp, cnt, std, siz);
#else
	return dec_xdr_ushort(mp, vp, cnt, std, siz);
#endif
}

static int
dec_trc_uint(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
#if	defined(I860_NODE)
	/* XXX are handwritten anyhow */
	return dec_xdr_int(mp, vp, cnt, std, siz);
#else
	return dec_xdr_uint(mp, vp, cnt, std, siz);
#endif
}

static int
dec_trc_ulong(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
#if	defined(I860_NODE)
	/* XXX are handwritten anyhow */
	return dec_xdr_long(mp, vp, cnt, std, siz);
#else
	return dec_xdr_ulong(mp, vp, cnt, std, siz);
#endif
}

static int
dec_trc_float(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_float(mp, vp, cnt, std, siz);
}

static int
dec_trc_double(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_double(mp, vp, cnt, std, siz);
}

static int
dec_trc_cplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_cplx(mp, vp, cnt, std, siz);
}

static int
dec_trc_dcplx(mp, vp, cnt, std, siz)
	struct pmsg *mp;
	void *vp;
	int cnt, std, siz;
{
	return dec_xdr_dcplx(mp, vp, cnt, std, siz);
}


/*******************************************
 **  Alien (can't do it) en/decoder stub  **
 **                                       **
 *******************************************/

static int
enc_alien()
{
	return PvmBadMsg;
}


/****************************
 **  Encoder switch table  **
 **                        **
 ****************************/

static struct encvec encoders[] = {

	{	enc_raw_init, dec_raw_init,		/* Raw (native) 0 */
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any,
		enc_raw_any, dec_raw_any },

	{	enc_xdr_init, dec_xdr_init,		/* XDR 1 */
		enc_xdr_byte, dec_xdr_byte,
		enc_xdr_short, dec_xdr_short,
		enc_xdr_int, dec_xdr_int,
		enc_xdr_long, dec_xdr_long,
#if	defined(I860_NODE)
		enc_xdr_short, dec_xdr_short,	/* XXX are handwritten anyhow */
		enc_xdr_int, dec_xdr_int,
		enc_xdr_long, dec_xdr_long,
#else
		enc_xdr_short, dec_xdr_ushort,
		enc_xdr_int, dec_xdr_uint,
		enc_xdr_ulong, dec_xdr_ulong,
#endif
		enc_xdr_float, dec_xdr_float,
		enc_xdr_double, dec_xdr_double,
		enc_xdr_cplx, dec_xdr_cplx,
		enc_xdr_dcplx, dec_xdr_dcplx },

	{	enc_inp_init, enc_alien,		/* In place (encode only) 2 */
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien,
		enc_inp_any, enc_alien },

	{	enc_trc_init, dec_trc_init,		/* Trace (a la XDR + annot) 4 */
		enc_trc_byte, dec_trc_byte,
		enc_trc_short, dec_trc_short,
		enc_trc_int, dec_trc_int,
		enc_trc_long, dec_trc_long,
		enc_trc_short, dec_trc_ushort,
		enc_trc_int, dec_trc_uint,
		enc_trc_ulong, dec_trc_ulong,
		enc_trc_float, dec_trc_float,
		enc_trc_double, dec_trc_double,
		enc_trc_cplx, dec_trc_cplx,
		enc_trc_dcplx, dec_trc_dcplx },

	{	enc_alien, dec_raw_init,		/* Alien (can't deal) 5 */
		enc_alien, dec_raw_any,			/* unpacking bytes allowed */
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien,
		enc_alien, enc_alien },
};


/*	pmsg_setlen()
*
*	Set m_len field of pmsg (after packing because we don't keep track
*	of it).
*/

int
pmsg_setlen(mp)
	struct pmsg *mp;
{
	struct frag *fp, *fp2;
	int l = 0;

	fp = fp2 = mp->m_frag;
	while ((fp = fp->fr_link) != fp2)
		l += fp->fr_len;
	mp->m_len = l;
	return l;
}


/*	pmsg_setenc()
*
*	Set encoding parameter for message, initialize encode/decode vector.
*/

int
pmsg_setenc(mp, enc)
	struct pmsg *mp;
	int enc;
{
	mp->m_enc = enc;
	if (enc == pvmmydsig)		/* native */
		enc = 0;
	else if (enc == 0x10000000)	/* xdr */
		enc = 1;
	else if (enc == 0x20000000)	/* inplace */
		enc = 2;
	else if (enc == 0x40000000) /* trace */
		enc = 3;
	else						/* alien */
		enc = 4;
	mp->m_codef = &encoders[enc];
	return 0;
}


int
pmsg_dump(mp, lvl)
	struct pmsg *mp;
	int lvl;			/* 0 - summary, 1 - frag lengths, 2 - frag data */
{
	struct frag *fp;

	if (mp->m_flag & MM_PACK)
		pmsg_setlen(mp);
#ifdef	MCHECKSUM
	pvmlogprintf(
	"pmsg_dump(0x%x) ref=%d mid=%d len=%d ctx=0x%x tag=%d wid=0x%x src=0x%x dst=0x%x enc=0x%x flag=%d crc=0x%x\n",
			mp, mp->m_ref, mp->m_mid, mp->m_len,
			mp->m_ctx, mp->m_tag, mp->m_wid, mp->m_src, mp->m_dst,
			mp->m_enc, mp->m_flag, pmsg_crc(mp));

#else
	pvmlogprintf(
	"pmsg_dump(0x%x) ref=%d mid=%d len=%d ctx=0x%x tag=%d wid=0x%x src=0x%x dst=0x%x enc=0x%x flag=%d\n",
			mp, mp->m_ref, mp->m_mid, mp->m_len,
			mp->m_ctx, mp->m_tag, mp->m_wid, mp->m_src, mp->m_dst,
			mp->m_enc, mp->m_flag);
#endif
	if (lvl > 0) {
		for (fp = mp->m_frag->fr_link; fp != mp->m_frag; fp = fp->fr_link) {
			pvmlogprintf(" frag=0x%x max=%d ofs=%d len=%d\n",
				fp, fp->fr_max, fp->fr_dat - fp->fr_buf, fp->fr_len);
			if (lvl > 1)
				pvmhdump(fp->fr_dat, fp->fr_len, "  ");
		}
	}
	return 0;
}


/*	pmsg_pack()
*
*	Pack a message into another message, including header fields.
*/

int
pmsg_pack(mp, mp2)
	struct pmsg *mp;		/* message to pack into */
	struct pmsg *mp2;		/* message to include */
{
	struct frag *fp;
	int cc;

	if (mp2->m_flag & MM_PACK)
		pmsg_setlen(mp2);

	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_len, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_ctx, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_tag, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_wid, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_enc, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_crc, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_src, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->enc_int) (mp, (void*)&mp2->m_dst, 1, 1, sizeof(int)))
		return cc;
	if (fp = mp2->m_frag)
		while ((fp = fp->fr_link) != mp2->m_frag) {
			if (cc = (mp->m_codef->enc_int)
					(mp, (void*)&fp->fr_len, 1, 1, sizeof(int)))
				return cc;
			if (cc = (mp->m_codef->enc_byte)
					(mp, (void*)fp->fr_dat, fp->fr_len, 1, 1))
				return cc;
		}
	return cc;
}


/*	pmsg_packbody()
*
*	Pack body of a message into another message.
*	Shares fragments between the messages.
*/

int
pmsg_packbody(mp, mp2)
	struct pmsg *mp;		/* message to pack into */
	struct pmsg *mp2;		/* message to include body of */
{
	struct frag *fp, *fp2;
	int cc;

	if (mp->m_enc != mp2->m_enc)
		cc = PvmMismatch;
	else {
		cc = 0;
		if ((fp = mp2->m_frag) && fp->fr_link != fp) {
			fp2 = mp->m_frag->fr_rlink;
			if (fp2 != mp->m_frag && fp2->fr_len == 0) {
				LISTDELETE(fp2, fr_link, fr_rlink);
				fr_unref(fp2);
			}
			while ((fp = fp->fr_link) != mp2->m_frag) {
				fp2 = fr_new(0);
				fp2->fr_buf = fp->fr_buf;
				fp2->fr_max = fp->fr_max;
				fp2->fr_dat = fp->fr_dat;
				fp2->fr_len = fp->fr_len;
				da_ref(fp->fr_buf);
				LISTPUTBEFORE(mp->m_frag, fp2, fr_link, fr_rlink);
			}
		}
	}
	return cc;
}


/*	pmsg_unpack()
*
*	Unpack a message from a message.
*/

int
pmsg_unpack(mp, mp2)
	struct pmsg *mp;		/* message to unpack from */
	struct pmsg *mp2;		/* blank message to write on */
{
	struct frag *fp;
	int cc;
	int mlen;
	int frl;

	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mlen, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_ctx, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_tag, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_wid, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_enc, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_crc, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_src, 1, 1, sizeof(int)))
		return cc;
	if (cc = (mp->m_codef->dec_int)
			(mp, (void*)&mp2->m_dst, 1, 1, sizeof(int)))
		return cc;

	mp2->m_len = 0;

	if (mlen < 0)
		cc = PvmBadMsg;
	else {
		while (mlen > 0) {
			if (cc = (mp->m_codef->dec_int)
					(mp, (void*)&frl, 1, 1, sizeof(int)))
				break;
			if (!(fp = fr_new(frl + MAXHDR))) {
				cc = PvmNoMem;
				break;
			}
			fp->fr_dat += MAXHDR;
			fp->fr_len = frl;
			if (cc = (mp->m_codef->dec_byte)
					(mp, (void*)fp->fr_dat, frl, 1, 1))
				break;
			LISTPUTBEFORE(mp2->m_frag, fp, fr_link, fr_rlink);
			mp2->m_len += frl;
			mlen -= frl;
		}
		pmsg_setenc(mp2, mp2->m_enc);
	}
	return cc;
}


/**************************
 **  Vendor Custom Code  **
 **                      **
 **************************/


#ifdef IMA_CSPP
static void internal_pre_bcopy(unsigned int, unsigned int, int);
void read_prefetch_region(unsigned int, int);

static void
pre_bcopy(s1, s2, n)
	unsigned int s1;
	unsigned int s2;
	int n;
{
	int offset;

	/* make life easy.  only work on chunks of at least 4 lines */
	if (n < 320) {
		read_prefetch_region(s1 & ~0x3f, n + (s1 & 0x3f));
		BCOPY((void *)s1, (void *)s2, n);
		return;
	}
	/* force starting alignment */
	offset = (unsigned int)s1 & 0x3f;
	if (offset) {
		offset = 64 - offset;
		BCOPY((void *)s1, (void *)s2, offset);
		s1 += offset;
		s2 += offset;
		n -= offset;
	}

	/* deal with case where n is not a multiple of 64 */
	offset = n & 0x3f;
	if (offset) {
		n &= ~0x3f;
		internal_pre_bcopy(s1, s2, n);
		s1 += n;
		s2 += n;
		BCOPY((void *)s1, (void *)s2, offset);
		return;
	}

	/* n is a multiple of 64 */
	internal_pre_bcopy(s1, s2, n);
	return;
}

static void
internal_pre_bcopy(s1, s2, n)
	unsigned int s1;
	unsigned int s2;
	int n;
{
	read_prefetch_region(s1, 192);				/* prefetch 0, 1 & 2 */
	while (1) {
		read_prefetch_region(s1+192, 64);		/* prefetch 3 */
		if (n == 256)
			break;
		BCOPY((void *)s1, (void *)s2, 64);						/* copy 0 */
		s1 += 64; s2 += 64; n -= 64;
		read_prefetch_region(s1+192, 64);		/* prefetch 0 */
		if (n == 256)
			break;
		BCOPY((void *)s1, (void *)s2, 64);						/* copy 1 */
		s1 += 64; s2 += 64; n -= 64;
		read_prefetch_region(s1+192, 64);		/* prefetch 1 */
		if (n == 256)
			break;
		BCOPY((void *)s1, (void *)s2, 64);						/* copy 2 */
		s1 += 64; s2 += 64; n -= 64;
		read_prefetch_region(s1+192, 64);		/* prefetch 2 */
		if (n == 256)
			break;
		BCOPY((void *)s1, (void *)s2, 64);						/* copy 3 */
		s1 += 64; s2 += 64; n -= 64;
	}
	BCOPY((void *)s1, (void *)s2, 256); /* last 4 lines */
}
#endif

