/*
 * $RCSfile: part.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: part.c,v $
 * Revision 1.2  1996/01/29 19:49:20  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  21:41:44  slm
 * Initial revision
 *
 * Revision 1.13.3.1  1994/10/27  20:52:04  hkaram
 * New branch
 *
 * Revision 1.13  1994/02/05  00:07:53  menze
 *   [ 1994/01/30          menze ]
 *   assert.h renamed xk_assert.h
 */

#include "xtype.h"
#include "part.h"
#include "xk_assert.h"
#include "platform.h"
#include "x_util.h"
#include "x_libc.h"

void
partInit(participants, number)
Part *participants;
int  number;
{
    int i;

    participants->len = 0;
    for (i = 0; i < number; i++) {
	participants[i].stack.top = 0;
	participants[i].len = number;
    }
}

void
partStackPush(stack, addr, length)
PartStack *stack;
void      *addr;
int       length;
{
    xAssert(stack->top >= 0);
    if (stack->top >= PART_MAX_STACK)
	Kabort("participant stack overflow");
    stack->arr[stack->top].ptr = addr;
    stack->arr[stack->top].len = length;
    stack->top++;
}

void *
partStackPop(stack)
PartStack *stack;
{
    xAssert(stack->top >= 0);
    if (stack->top == 0 || stack->top > PART_MAX_STACK)
	return 0;
    return stack->arr[--stack->top].ptr;
}

int
partStackTopByteLen(participant)
Part participant;
{
    PartStack *stack = &participant.stack;

    xAssert(stack->top >= 0);
    xAssert(stack->top <= PART_MAX_STACK);
    if (stack->top <= 0 || stack->top > PART_MAX_STACK)
	return -1;
    return  stack->arr[stack->top - 1].len;
}

/*
 * Very quick, very dirty ...
 *
 * External participant representation:
 *
 *     number of Participants
 *         number in part1 stack
 *	       stack elem 1 len stack elements from bottom-to-top
 *		   stack elem 1 data
 *		   stack elem 2 len
 *		   stack elem 2 data
 *			...
 * 	   number in part2 stack
 *	       stack elem 1 len stack elements from bottom-to-top
 *		   stack elem 1 data
 *		   stack elem 2 len
 *		   stack elem 2 data
 *		...
 */

#define CHECK_BUF_LEN(_incLen)                                        \
	if ((char *)buf + (_incLen) - (char *)bufStart > (*bufLen)) { \
	    xFree(bufStart);                                          \
	    return XK_FAILURE;                                        \
	}

XkReturn
partExternalize(p, dstBuf, bufLen)
Part *p;
void *dstBuf;
int  *bufLen;	/* length of buffer, number of bytes written */
{
    char *bufStart, *buf;
    int  i, j, len, numParts;

    /*
     * We keep buf and dstBuf separate until the very end (when we copy buf
     * into dstBuf) because some of the pointers in the participant we are
     * externalizing may point into the interior of dstBuf.
     */
    bufStart = xMalloc(*bufLen);
    buf = bufStart;
    CHECK_BUF_LEN(sizeof(int));
    *(int *)buf = numParts = partLength(p);
    buf += sizeof(int);
    for (i = 0; i < numParts; i++, p++) {
	/* for each participant */
	CHECK_BUF_LEN(sizeof(int));
	*(int *)buf = p->stack.top;
	buf += sizeof(int);
	for (j = 0; j < p->stack.top; j++) {
	    /* for each stack element */
	    CHECK_BUF_LEN(sizeof(int));
	    len = p->stack.arr[j].len;
	    *(int *)buf = len;
	    buf += sizeof(int);
	    if (len) {
		CHECK_BUF_LEN(len);
		bcopy((char *)p->stack.arr[j].ptr, buf, len);
		buf += len;
	    }
	    else {
		/* special-valued pointer which must be preserved. */
		CHECK_BUF_LEN(sizeof(void *));
		*(void **)buf = p->stack.arr[j].ptr;
		buf += sizeof(void *);
	    }
	    while (! LONG_ALIGNED(buf))
		buf++;
	}
    }
    *bufLen = buf - bufStart;
    bcopy(bufStart, dstBuf, *bufLen);
    xFree(bufStart);
    return XK_SUCCESS;
}

void
partInternalize(p, dummyBuf)
Part *p;
void *dummyBuf;
{
    char *buf = dummyBuf;
    int  i, j, len, numInStack;

    partInit(p, *(int *)buf);
    buf += sizeof(int);
    for (i = 0; i < partLength(p); i++) {
	/* for each participant */
	numInStack = *(int *)buf;
	buf += sizeof(int);
	for (j = 0; j < numInStack; j++) {
	    /* for each stack element */
	    len = *(int *)buf;
	    buf += sizeof(int);
	    if (len) {
		partPush(p[i], buf, len);
		buf += len;
	    }
	    else {
		partPush(p[i], *(void **)buf, 0);
		buf += sizeof(void *);
	    }
	    while (! LONG_ALIGNED(buf))
	        buf++;
	}
    }
}
