
/*
 *           PVM 3.2:  Parallel Virtual Machine System 3.2
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  A. L. Beguelin, J. J. Dongarra, G. A. Geist,
 *    W. C. Jiang, R. J. Manchek, B. K. Moore, and V. S. Sunderam
 *                   (C) 1992 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 3.2 was funded in part by the U.S. Department of Energy, the
 * National Science Foundation and the State of Tennessee.
 */

/*
 *	lpvmpack.c
 *
 *	Typed packing/unpacking, message buffer manip.
 *
$Log: lpvmpack.c,v $
 * Revision 1.2  1993/10/04  19:20:22  manchek
 * fixed vpackf() - floats get passed as doubles, must unpack that way
 *
 * Revision 1.1  1993/08/30  23:26:48  manchek
 * Initial revision
 *
 */

#include <stdio.h>
#ifdef IMA_BSD386
#include <machine/endian.h>
#endif
#ifdef IMA_LINUX
#include <endian.h>
#endif
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <ctype.h>
#ifdef	__STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <pvm3.h>
#include "global.h"
#include "tdpro.h"
#include "ddpro.h"
#include "pvmfrag.h"
#include "pvmumbuf.h"
#include "listmac.h"
#include "bfunc.h"

struct dat_blk {
	int type;		/* data type */
	void *base;		/* base address */
	int cnt;		/* number of elements */
	int std;		/* lead to next element */
};

/* struct dat_blk type codes */
#define	INP_BYTE	1
#define	INP_INT		2
#define	INP_SHORT	3
#define	INP_LONG	4
#define	INP_FLOAT	5
#define	INP_DFLOAT	6
#define	INP_CPLX	7
#define	INP_DCPLX	8


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

extern int pvmfrgsiz;			/* from lpvm.c */
extern struct mhp *pvmmidh;		/* from pvmumbuf.c */
extern int pvmmidhsiz;			/* from pvmumbuf.c */
extern int pvmmyndf;			/* from lpvm.c */
extern int pvmmytid;			/* from lpvm.c */
extern int pvmudpmtu;			/* from lpvm.c */

int pvmrbufmid = 0;				/* current recv/unpack mid */
int pvmsbufmid = 0;				/* current send/pack mid */


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

static char rcsid[] = "$Id: lpvmpack.c,v 1.2 1993/10/04 19:20:22 manchek Exp $";


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

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

static int
bytepk(cp, num, siz, lnc)
	char *cp;	/* base of data */
	int num;	/* num of chunks */
	int siz;	/* size of chunk */
	int lnc;	/* lead to next chunk */
{
	struct umbuf *up = midtobuf(pvmsbufmid);	/* working message */
	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 = up->ub_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 = enc_step())
						return r;
				}
			}
		}
		cp += lnc;
	}
	return 0;
}


/*	byteupk()
*
*	Extract bytes from rbuf.
*	Returns 0 else PvmNoData if end of message reached early.
*/

static int
byteupk(cp, num, siz, lnc)
	char *cp;	/* base of data */
	int num;	/* num of chunks */
	int siz;	/* size of chunk */
	int lnc;	/* lead to next chunk */
{
	struct umbuf *up = midtobuf(pvmrbufmid);	/* working message */
	struct frag *fp;			/* working frag */
	int togo;					/* bytes left in chunk */
	int r;						/* bytes (data) 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 = up->ub_cfrag;
			r = fp->fr_len - up->ub_cpos;

			if (togo <= r) {	/* frag contains rest of chunk */
				BCOPY(fp->fr_dat + up->ub_cpos, cp, togo);
				up->ub_cpos += togo;
				cp += togo;
				togo = 0;

			} else {
				if (r > 0) {	/* frag contains part of chunk */
					BCOPY(fp->fr_dat + up->ub_cpos, cp, r);
					up->ub_cpos += r;
					togo -= r;
					cp += r;

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


static int
enc_raw_init()
{
	return 0;
}


static int
dec_raw_init()
{
	struct umbuf *up = midtobuf(pvmrbufmid);

	up->ub_cfrag = up->ub_frag->fr_link;
	up->ub_cpos = 0;
	return 0;
}


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


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


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

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


int
xdr_double(xdrp, dp)
	XDR *xdrp;
	double *dp;
{
		return xdr_long(xdrp, (long*)dp + 1)
				&& xdr_long(xdrp, (long*)dp);
}
#endif/*IMA_BSD386*/

#if	defined(I860_NODE)

static int
enc_xdr_init()
{
    return 0;
}

static int
enc_xdr_byte(vp, cnt, std, siz)
    void *vp;
    int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	struct frag *fp;
	int cc;

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

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

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

static int
enc_xdr_int(vp, cnt, std, siz)
    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(buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_long(vp, cnt, std, siz)
    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(buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_float(vp, cnt, std, siz)
    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(buf, 4, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_double(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(buf, 8, 1, 1))
            return cc;
    }
    return 0;
}

static int
enc_xdr_dcplx(vp, cnt, std, siz)
    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(buf, 16, 1, 1))
            return cc;
    }
    return 0;
}

static int
dec_xdr_init()
{
    struct umbuf *up = midtobuf(pvmrbufmid);

    up->ub_cfrag = up->ub_frag->fr_link;
    up->ub_cpos = 0;
    return 0;
}

static int
dec_xdr_byte(vp, cnt, std, siz)
    void *vp;
    int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	struct frag *fp;
	int cc;

	fp = up->ub_cfrag;
	if (cc = byteupk((char*)vp, cnt, siz, std * siz))
		return cc;
	up->ub_cpos = (up->ub_cpos + 3) & ~3;
	return 0;
}

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

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

static int
dec_xdr_int(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(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(vp, cnt, std, siz)
    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(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	/*I860_NODE*/

static int
enc_xdr_init()
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	struct frag *fp = up->ub_frag->fr_link;

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


static int
enc_xdr_step()
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	struct frag *fp = up->ub_frag->fr_rlink;
	int cc;

	fp->fr_len = xdr_getpos(&up->ub_encxdr);
	if (cc = enc_step())
		return cc;
	fp = fp->fr_link;
	xdrmem_create(&up->ub_encxdr,
			fp->fr_dat,
			(unsigned)(fp->fr_max - (fp->fr_dat - fp->fr_buf)),
			XDR_ENCODE);
	return 0;
}


static int
enc_xdr_byte(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	struct frag *fp;
	int cc;

	fp = up->ub_frag->fr_rlink;
	if (cc = bytepk((char*)vp, cnt, 1, std))
		return cc;
	if (fp != up->ub_frag->fr_rlink) {
		fp = up->ub_frag->fr_rlink;
		xdrmem_create(&up->ub_encxdr,
				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(&up->ub_encxdr, fp->fr_len);
	return 0;
}


static int
enc_xdr_short(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register short *np;
	int cc = 0;

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


static int
enc_xdr_int(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register int *np;
	int cc = 0;

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


static int
enc_xdr_long(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register long *np;
	int cc = 0;

	for (np = (long*)vp; cnt-- > 0; np += std)
		if (!xdr_long(xob, np)) {
			if (cc = enc_xdr_step())
				break;
			else
				if (!xdr_long(xob, np)) {
					cc = PvmNoMem;
					break;
				}
		}
	up->ub_frag->fr_rlink->fr_len = xdr_getpos(xob);
	return cc;
}


static int
enc_xdr_float(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register float *fp;
	int cc = 0;

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


static int
enc_xdr_double(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register double *dp;
	int cc = 0;

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


static int
enc_xdr_cplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register float *xp;
	int cc = 0;

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


static int
enc_xdr_dcplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmsbufmid);
	XDR *xob = &up->ub_encxdr;
	register double *zp;
	int cc = 0;

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


static int
dec_xdr_init()
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	struct frag *fp = up->ub_frag->fr_link;

	up->ub_cfrag = fp;
	up->ub_cpos = 0;
	xdrmem_create(&up->ub_decxdr, fp->fr_dat, (unsigned)(fp->fr_len),
			XDR_DECODE);
	return 0;
}


static int
dec_xdr_step()
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	struct frag *fp;
	int cc;

	if (cc = dec_step())
		return cc;
	fp = up->ub_cfrag;
	xdrmem_create(&up->ub_decxdr, fp->fr_dat, (unsigned)(fp->fr_len),
			XDR_DECODE);
	return 0;
}


static int
dec_xdr_byte(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	struct frag *fp;
	int cc;

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


static int
dec_xdr_short(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register short *np;
	int cc = 0;

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


static int
dec_xdr_int(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register int *np;
	int cc = 0;

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


static int
dec_xdr_long(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register long *np;
	int cc = 0;

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


static int
dec_xdr_ushort(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register unsigned short *np;
	int cc = 0;

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


static int
dec_xdr_uint(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register unsigned int *np;
	int cc = 0;

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


static int
dec_xdr_ulong(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register unsigned long *np;
	int cc = 0;

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


static int
dec_xdr_float(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register float *fp;
	int cc = 0;

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


static int
dec_xdr_double(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register double *dp;
	int cc = 0;

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


static int
dec_xdr_cplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register float *xp;
	int cc = 0;

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


static int
dec_xdr_dcplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct umbuf *up = midtobuf(pvmrbufmid);
	XDR *xob = &up->ub_decxdr;
	register double *zp;
	int cc = 0;

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

#endif	/*I860_NODE*/

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

static int
enc_inp_init()
{
	return 0;
}


static int
enc_inp_byte(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_BYTE;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_short(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_SHORT;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_int(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_INT;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_long(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_LONG;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_float(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_FLOAT;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_double(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_DFLOAT;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_cplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_CPLX;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


static int
enc_inp_dcplx(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	struct dat_blk d;

	d.type = INP_DCPLX;
	d.base = vp;
	d.cnt = cnt;
	d.std = std;
	return bytepk((char*)&d, 1, sizeof(d), 0);
}


/*******************
 **  Foo encoders **
 **               **
 *******************/

static int
enc_foo_init()
{
	return 0;
}


static int
enc_foo_byte(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	return bytepk((char*)vp, cnt, siz, std * siz);
}


static int
enc_foo_int(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	register int *np;
	char buf[4];
	int n;
	int cc;

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


static int
dec_foo_init()
{
	struct umbuf *up = midtobuf(pvmrbufmid);

	up->ub_cfrag = up->ub_frag->fr_link;
	up->ub_cpos = 0;
	return 0;
}


static int
dec_foo_byte(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	return byteupk((char*)vp, cnt, siz, std * siz);
}


static int
dec_foo_int(vp, cnt, std, siz)
	void *vp;
	int cnt, std, siz;
{
	register int *np;
	char buf[4];
	int cc;

	for (np = (int*)vp; cnt-- > 0; np += std) {
		if (cc = byteupk(buf, 4, 1, 1))
			return cc;
		*np = (0x80 & buf[0] ? ~0xffffffff : 0)
		+ ((0xff & buf[0]) << 24)
		+ ((0xff & buf[1]) << 16)
		+ ((0xff & buf[2]) << 8)
		+ (0xff & buf[3]);
	}
	return 0;
}


static int
enc_foo_err()
{
	return PvmNotImpl;	/* don't implement this :-) */
}


/*******************************************
 **  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_long, 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_byte, enc_alien,
		enc_inp_short, enc_alien,
		enc_inp_int, enc_alien,
		enc_inp_long, enc_alien,
		enc_inp_short, enc_alien,
		enc_inp_int, enc_alien,
		enc_inp_long, enc_alien,
		enc_inp_float, enc_alien,
		enc_inp_double, enc_alien,
		enc_inp_cplx, enc_alien,
		enc_inp_dcplx, enc_alien },

	{	enc_foo_init, dec_foo_init,		/* Foo (for pvmd) 3 */
		enc_foo_byte, dec_foo_byte,
		enc_foo_err, enc_foo_err,
		enc_foo_int, dec_foo_int,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err,
		enc_foo_err, enc_foo_err },

	{	enc_alien, enc_alien,			/* Alien (can't deal) 4 */
		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,
		enc_alien, enc_alien },
};


/*	enctovec()
*
*	Map data encoding value to encode/decode function vector
*/

struct encvec *
enctovec(enc)
	int enc;
{
	if (enc == 0)			/* xdr */
		return &encoders[1];
	if (enc == 1)			/* foo */
		return &encoders[3];
	if (enc == pvmmyndf)	/* native */
		return &encoders[0];
	return &encoders[4];	/* alien */
}


int
enc_step()
{
	struct frag *fp = midtobuf(pvmsbufmid)->ub_frag;
	struct frag *nfp;

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


int
dec_step()
{
	struct umbuf *up = midtobuf(pvmrbufmid);

	up->ub_cpos = 0;
	if (up->ub_cfrag == up->ub_frag)		/* no message left */
		return PvmNoData;
	up->ub_cfrag = up->ub_cfrag->fr_link;
	if (up->ub_cfrag == up->ub_frag)
		return PvmNoData;
	return 0;
}


/************************
 **  Libpvm Functions  **
 **                    **
 ************************/

int
pvm_mkbuf(enc)
	int enc;		/* data format */
{
	int mid;
	struct umbuf *up;
	struct frag *fp;

	switch (enc) {						/* verify encoding */
	case PvmDataDefault:
		enc = 0;		/* XXX this just forces XDR */
		break;

	case PvmDataRaw:
		enc = pvmmyndf;
		break;

	case PvmDataFoo:
		enc = 1;
		break;

	case PvmDataInPlace:
		return lpvmerr("pvm_mkbuf", PvmNotImpl);
		break;

	default:
		return lpvmerr("pvm_mkbuf", PvmBadParam);
	}
	if ((mid = umbuf_new()) <= 0)
		return lpvmerr("pvm_mkbuf", mid);

	up = midtobuf(mid);					/* set encoders */
	up->ub_enc = enc;
	up->ub_codef = enctovec(enc);
	up->ub_src = pvmmytid;

	fp = fr_new(pvmfrgsiz);			/* make a blank frag to write in */
	fp->fr_dat += MAXHDR;
	LISTPUTBEFORE(up->ub_frag, fp, fr_link, fr_rlink);

	return mid;
}


int
pvm_freebuf(mid)
	int mid;		/* message handle */
{
	int cc;

	if (pvmsbufmid == mid)
		pvmsbufmid = 0;
	if (pvmrbufmid == mid)
		pvmrbufmid = 0;
	if ((cc = umbuf_free(mid)) < 0)
		return lpvmerr("pvm_freebuf", cc);
	return 0;
}


int
pvm_setsbuf(mid)
	int mid;
{
	int omid;
	struct umbuf *up = 0;

	if (mid < 0)
		return lpvmerr("pvm_setsbuf", PvmBadParam);
	if (mid) {
		if (mid >= pvmmidhsiz || !(up = pvmmidh[mid].m_umb))
			return lpvmerr("pvm_setsbuf", PvmNoSuchBuf);
		if (mid == pvmrbufmid)
			pvmrbufmid = 0;
	}
	omid = pvmsbufmid > 0 ? pvmsbufmid : 0;
	pvmsbufmid = mid;
	if (up && !(up->ub_flag & UB_PACK)) {
		(up->ub_codef->enc_init)();
		up->ub_flag &= ~UB_UPACK;
		up->ub_flag |= UB_PACK;
	}
	return omid;
}


int
pvm_getsbuf()
{
	return pvmsbufmid > 0 ? pvmsbufmid : 0;
}


int
pvm_setrbuf(mid)
	int mid;
{
	int omid;
	struct umbuf *up = 0;

	if (mid < 0)
		return lpvmerr("pvm_setrbuf", PvmBadParam);
	if (mid) {
		if (mid >= pvmmidhsiz || !(up = pvmmidh[mid].m_umb))
			return lpvmerr("pvm_setrbuf", PvmNoSuchBuf);
		if (mid == pvmsbufmid)
			pvmsbufmid = 0;
	}
	omid = pvmrbufmid > 0 ? pvmrbufmid : 0;
	pvmrbufmid = mid;
	if (up && !(up->ub_flag & UB_UPACK)) {
		(up->ub_codef->dec_init)();
		up->ub_flag &= ~UB_PACK;
		up->ub_flag |= UB_UPACK;
	}
	return omid;
}


int
pvm_getrbuf()
{
	return pvmrbufmid > 0 ? pvmrbufmid : 0;
}


int
pvm_initsend(enc)
	int enc;
{
	int mid;

	if ((mid = pvm_mkbuf(enc)) < 0)
		return lpvmerr("pvm_initsend", mid);
	if (pvmsbufmid > 0)
		pvm_freebuf(pvmsbufmid);
	pvm_setsbuf(mid);
	return mid;
}


int
pvm_bufinfo(mid, len, code, tid)
	int mid;
	int *len;
	int *code;
	int *tid;
{
	struct umbuf *up;

	if (mid <= 0)
		return lpvmerr("pvm_bufinfo", PvmBadParam);
	if (mid >= pvmmidhsiz || !(up = pvmmidh[mid].m_umb))
		return lpvmerr("pvm_bufinfo", PvmNoSuchBuf);
	if (len)
		*len = up->ub_len;
	if (code)
		*code = up->ub_cod;
	if (tid)
		*tid = up->ub_src;
	return PvmOk;
}


int
pvm_pkbyte(cp, cnt, std)
	char *cp;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkbyte", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_byte)((void*)cp, cnt, std, 1))
		return lpvmerr("pvm_pkbyte", cc);
	return PvmOk;
}


int
pvm_upkbyte(cp, cnt, std)
	char *cp;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkbyte", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_byte)((void*)cp, cnt, std, 1))
		return lpvmerr("pvm_upkbyte", cc);
	return PvmOk;
}


int
pvm_pkcplx(xp, cnt, std)
	float *xp;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkcplx", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_cplx)
			((void*)xp, cnt, std, sizeof(float)*2))
		return lpvmerr("pvm_pkcplx", cc);
	return PvmOk;
}


int
pvm_upkcplx(xp, cnt, std)
	float *xp;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkcplx", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_cplx)
			((void*)xp, cnt, std, sizeof(float)*2))
		return lpvmerr("pvm_upkcplx", cc);
	return PvmOk;
}


int
pvm_pkdcplx(zp, cnt, std)
	double *zp;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkdcplx", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_dcplx)
			((void*)zp, cnt, std, sizeof(double)*2))
		return lpvmerr("pvm_pkdcplx", cc);
	return PvmOk;
}


int
pvm_upkdcplx(zp, cnt, std)
	double *zp;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkdcplx", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_dcplx)
			((void*)zp, cnt, std, sizeof(double)*2))
		return lpvmerr("pvm_upkdcplx", cc);
	return PvmOk;
}


int
pvm_pkdouble(dp, cnt, std)
	double *dp;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkdouble", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_double)
			((void*)dp, cnt, std, sizeof(double)))
		return lpvmerr("pvm_pkdouble", cc);
	return PvmOk;
}


int
pvm_upkdouble(dp, cnt, std)
	double *dp;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkdouble", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_double)
			((void*)dp, cnt, std, sizeof(double)))
		return lpvmerr("pvm_upkdouble", cc);
	return PvmOk;
}


int
pvm_pkfloat(fp, cnt, std)
	float *fp;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkfloat", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_float)
			((void*)fp, cnt, std, sizeof(float)))
		return lpvmerr("pvm_pkfloat", cc);
	return PvmOk;
}


int
pvm_upkfloat(fp, cnt, std)
	float *fp;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkfloat", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_float)
			((void*)fp, cnt, std, sizeof(float)))
		return lpvmerr("pvm_upkfloat", cc);
	return PvmOk;
}


int
pvm_pkint(np, cnt, std)
	int *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkint", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_int)
			((void*)np, cnt, std, sizeof(int)))
		return lpvmerr("pvm_pkint", cc);
	return PvmOk;
}


int
pvm_pkuint(np, cnt, std)
	unsigned int *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkuint", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_int)
			((void*)np, cnt, std, sizeof(int)))
		return lpvmerr("pvm_pkuint", cc);
	return PvmOk;
}


int
pvm_upkint(np, cnt, std)
	int *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkint", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_int)
			((void*)np, cnt, std, sizeof(int)))
		return lpvmerr("pvm_upkint", cc);
	return PvmOk;
}


int
pvm_upkuint(np, cnt, std)
	unsigned int *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkuint", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_uint)
			((void*)np, cnt, std, sizeof(int)))
		return lpvmerr("pvm_upkuint", cc);
	return PvmOk;
}


int
pvm_pklong(np, cnt, std)
	long *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pklong", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_long)
			((void*)np, cnt, std, sizeof(long)))
		return lpvmerr("pvm_pklong", cc);
	return PvmOk;
}


int
pvm_pkulong(np, cnt, std)
	unsigned long *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkulong", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_long)
			((void*)np, cnt, std, sizeof(long)))
		return lpvmerr("pvm_pkulong", cc);
	return PvmOk;
}


int
pvm_upklong(np, cnt, std)
	long *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upklong", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_long)
			((void*)np, cnt, std, sizeof(long)))
		return lpvmerr("pvm_upklong", cc);
	return PvmOk;
}


int
pvm_upkulong(np, cnt, std)
	unsigned long *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkulong", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_ulong)
			((void*)np, cnt, std, sizeof(long)))
		return lpvmerr("pvm_upkulong", cc);
	return PvmOk;
}


int
pvm_pkshort(np, cnt, std)
	short *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkshort", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_short)
			((void*)np, cnt, std, sizeof(short)))
		return lpvmerr("pvm_pkshort", cc);
	return PvmOk;
}


int
pvm_pkushort(np, cnt, std)
	unsigned short *np;
	int cnt, std;
{
	int cc;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkushort", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_short)
			((void*)np, cnt, std, sizeof(short)))
		return lpvmerr("pvm_pkushort", cc);
	return PvmOk;
}


int
pvm_upkshort(np, cnt, std)
	short *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkshort", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_short)
			((void*)np, cnt, std, sizeof(short)))
		return lpvmerr("pvm_upkshort", cc);
	return PvmOk;
}


int
pvm_upkushort(np, cnt, std)
	unsigned short *np;
	int cnt, std;
{
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkushort", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_ushort)
			((void*)np, cnt, std, sizeof(short)))
		return lpvmerr("pvm_upkushort", cc);
	return PvmOk;
}


int
pvm_pkstr(cp)
	char *cp;
{
	int cc;
	int l = strlen(cp) + 1;

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_pkstr", PvmNoBuf);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_int)
			((void*)&l, 1, 1, sizeof(int)))
		return lpvmerr("pvm_pkstr", cc);
	if (cc = (midtobuf(pvmsbufmid)->ub_codef->enc_byte)
			((void*)cp, l, 1, 1))
		return lpvmerr("pvm_pkstr", cc);
	return PvmOk;
}


int
pvm_upkstr(cp)
	char *cp;
{
	int l;
	int cc;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_upkstr", PvmNoBuf);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_int)
			((void*)&l, 1, 1, sizeof(int)))
		return lpvmerr("pvm_upkstr", cc);
	if (cc = (midtobuf(pvmrbufmid)->ub_codef->dec_byte)
			((void*)cp, l, 1, 1))
		return lpvmerr("pvm_upkstr", cc);
	return PvmOk;
}


int
pvm_vpackf(fmt, ap)
	char *fmt;
	va_list ap;
{
	char *p = fmt;
	int cc;
	int cnt, std;			/* count and stride of element */
	int vh, vl, vu;			/* short, long, unsigned variety */
	int isv;				/* param is a value not address */
	struct encvec *codef;
	char tc, *cp;			/* each type and a pointer */
	short th, *hp;
	int tn, *np;
	long tl, *lp;
	float tf, *fp;
	double td, *dp;

	if (p[0] == '%' && p[1] == '+') {
		cc = va_arg(ap, int);
		if ((cc = pvm_initsend(cc)) < 0)
			goto hork;
		p += 2;
	}

	if (pvmsbufmid <= 0)
		return lpvmerr("pvm_packf", PvmNoBuf);

	codef = midtobuf(pvmsbufmid)->ub_codef;

	while (*p) {
		if (*p++ == '%') {
			cnt = 1;
			std = 1;
			isv = 1;
			vl = vh = vu = 0;
			if (*p == '*') {
				cnt = va_arg(ap, int);
				isv = 0;
				p++;
			} else
				if (isdigit(*p)) {
					cnt = atoi(p);
					isv = 0;
					while (isdigit(*++p)) ;
				}
			if (*p == '.') {
				isv = 0;
				if (*++p == '*') {
					std = va_arg(ap, int);
					p++;
				} else
					if (isdigit(*p)) {
						std = atoi(p);
						while (isdigit(*++p)) ;
					}
			}
			for (cc = 1; cc; ) {
				switch (*p++) {

				case 'h':
					vh = 1;
					break;

				case 'l':
					vl = 1;
					break;

				case 'u':
					vu = 1;
					break;

				default:
					p--;
					cc = 0;
				}
			}

			switch (*p++) {

			case 'c':
				if (isv) {
					tc = va_arg(ap, char);
					cp = &tc;
				} else
					cp = va_arg(ap, char *);
				cc = (codef->enc_byte) ((void*)cp, cnt, std, 1);
#ifdef	DEBUGPACKF
				printf("%d %d %s%schar\n", cnt, std, (vu ? "unsigned " : ""),
						(isv ? "" : "&"));
#endif
				break;

			case 'd':
				if (vl) {
					if (isv) {
						tl = va_arg(ap, long);
						lp = &tl;
					} else
						lp = va_arg(ap, long *);
					cc = (codef->enc_long)
							((void*)lp, cnt, std, sizeof(long));
				} else
					if (vh) {
						if (isv) {
							th = va_arg(ap, short);
							hp = &th;
						} else
							hp = va_arg(ap, short *);
						cc = (codef->enc_short)
								((void*)hp, cnt, std, sizeof(short));
					} else {
						if (isv) {
							tn = va_arg(ap, int);
							np = &tn;
						} else
							np = va_arg(ap, int *);
						cc = (codef->enc_int)
								((void*)np, cnt, std, sizeof(int));
					}
#ifdef	DEBUGPACKF
				printf("%d %d %s%s%s%sint\n", cnt, std,
						(vu ? "unsigned " : ""), 
						(vl ? "long " : ""), 
						(vh ? "short " : ""),
						(isv ? "" : "&"));
#endif
				break;

			case 'f':
				if (vl) {
					if (isv) {
						td = va_arg(ap, double);
						dp = &td;
					} else
						dp = va_arg(ap, double *);
					cc = (codef->enc_double)
							((void*)dp, cnt, std, sizeof(double));
				} else {
					if (isv) {
/*
						tf = va_arg(ap, float);
*/
						td = va_arg(ap, double);
						tf = td;
						fp = &tf;
					} else
						fp = va_arg(ap, float *);
					cc = (codef->enc_float)
							((void*)fp, cnt, std, sizeof(float));
				}
#ifdef	DEBUGPACKF
				printf("%d %d %s%s\n", cnt, std, (isv ? "" : "&"),
						(vl ? "double" : "float"));
#endif
				break;

			case 'x':
				if (vl) {
					dp = va_arg(ap, double *);
					cc = (codef->enc_dcplx)
							((void*)dp, cnt, std, sizeof(double)*2);
				} else {
					fp = va_arg(ap, float *);
					cc = (codef->enc_cplx)
							((void*)fp, cnt, std, sizeof(float)*2);
				}
#ifdef	DEBUGPACKF
				printf("%d %d %s&cplx\n", cnt, std, (vl ? "double " : ""));
#endif
				break;

			case 's':
				cp = va_arg(ap, char *);
				cnt = strlen(cp) + 1;
				if (!(cc = (codef->enc_int) ((void*)&cnt, 1, 1, sizeof(int))))
					cc = (codef->enc_byte) ((void*)cp, cnt, 1, 1);
#ifdef	DEBUGPACKF
				printf("string\n");
#endif
				break;

			default:
				cc = PvmBadParam;
				break;
			}

			if (cc)
				goto hork;
		}
/*
		else
			printf("'%c'\n", *(p - 1));
*/
	}
	return PvmOk;

hork:
	return lpvmerr("pvm_packf", cc);
}


int
#ifdef __STDC__
pvm_packf(const char *fmt, ...)
#else
pvm_packf(va_alist)
	va_dcl
#endif
{
	va_list ap;
	int cc;

#ifdef __STDC__
	va_start(ap, fmt);
#else
	char    *fmt;

	va_start(ap);
	fmt = va_arg(ap, char *);
#endif

	cc = pvm_vpackf(fmt, ap);
	va_end(ap);

	return cc;
}


int
pvm_vunpackf(fmt, ap)
	char *fmt;
	va_list ap;
{
	char *p = fmt;
	int cc;
	int cnt, std;		/* count and stride of element */
	int vh, vl, vu;		/* short, long, unsigned variety */
	struct encvec *codef;
	char *cp;			/* pointers for each type */
	short *hp;
	int *np;
	long *lp;
	float *fp;
	double *dp;

	if (pvmrbufmid <= 0)
		return lpvmerr("pvm_unpackf", PvmNoBuf);

	codef = midtobuf(pvmrbufmid)->ub_codef;

	while (*p) {
		if (*p++ == '%') {
			cnt = 1;
			std = 1;
			vl = vh = vu = 0;
			if (*p == '*') {
				cnt = va_arg(ap, int);
				p++;
			} else
				if (isdigit(*p)) {
					cnt = atoi(p);
					while (isdigit(*++p)) ;
				}
			if (*p == '.') {
				if (*++p == '*') {
					std = va_arg(ap, int);
					p++;
				} else
					if (isdigit(*p)) {
						std = atoi(p);
						while (isdigit(*++p)) ;
					}
			}
			for (cc = 1; cc; ) {
				switch (*p++) {

				case 'h':
					vh = 1;
					break;

				case 'l':
					vl = 1;
					break;

				case 'u':
					vu = 1;
					break;

				default:
					p--;
					cc = 0;
				}
			}

			switch (*p++) {

			case 'c':
				cp = va_arg(ap, char *);
				cc = (codef->dec_byte) ((void*)cp, cnt, std, 1);
				break;

			case 'd':
				if (vl) {
					lp = va_arg(ap, long *);
					cc = (vu ? codef->dec_ulong : codef->dec_long)
							((void*)lp, cnt, std, sizeof(long));
				} else
					if (vh) {
						hp = va_arg(ap, short *);
						cc = (vu ? codef->dec_ushort : codef->dec_short)
								((void*)hp, cnt, std, sizeof(short));
					} else {
						np = va_arg(ap, int *);
						cc = (vu ? codef->dec_uint : codef->dec_int)
								((void*)np, cnt, std, sizeof(int));
					}
				break;

			case 'f':
				if (vl) {
					dp = va_arg(ap, double *);
					cc = (codef->dec_double)
							((void*)dp, cnt, std, sizeof(double));
				} else {
					fp = va_arg(ap, float *);
					cc = (codef->dec_float)
							((void*)fp, cnt, std, sizeof(float));
				}
				break;

			case 'x':
				if (vl) {
					dp = va_arg(ap, double *);
					cc = (codef->dec_dcplx)
							((void*)dp, cnt, std, sizeof(double)*2);
				} else {
					fp = va_arg(ap, float *);
					cc = (codef->dec_cplx)
							((void*)fp, cnt, std, sizeof(float)*2);
				}
				break;

			case 's':
				cp = va_arg(ap, char *);
				if (!(cc = (codef->dec_int) ((void*)&cnt, 1, 1, sizeof(int))))
					cc = (codef->dec_byte) ((void*)cp, cnt, 1, 1);
				break;

			default:
				cc = PvmBadParam;
				break;
			}

			if (cc)
				goto hork;
		}
	}
	return PvmOk;

hork:
	return lpvmerr("pvm_unpackf", cc);
}


int
#ifdef __STDC__
pvm_unpackf(const char *fmt, ...)
#else
pvm_unpackf(va_alist)
	va_dcl
#endif
{
	va_list ap;
	int cc;

#ifdef __STDC__
	va_start(ap, fmt);
#else
	char    *fmt;

	va_start(ap);
	fmt = va_arg(ap, char *);
#endif

	cc = pvm_vunpackf(fmt, ap);
	va_end(ap);

	return cc;
}


