/* RpcBonsai.c 
    Client and Server Lupine-level functions for RPC 
    L. Stewart, January 18, 1983  5:16 PM, create from rpcfir.c
    L. Stewart, January 19, 1983  10:49 AM, length bugs
    L. Stewart, March 2, 1983  3:33 PM, Dispatcher bugs
    L. Stewart, March 3, 1983  10:03 AM, Dispatcher bugs
    L. Stewart, March 6, 1983  4:04 PM, GetFixed (temporary!!!)
    L. Stewart, May 24, 1983  4:28 PM, swapped1
 */

#include <Signal.h>
#include <Queue.h>
#include <Ec.h>
#include <Env.h>
#include <Rpc.h>
#include <RpcInternal.h>
#include <RpcLupine.h>
#include <RpcPkt.h>
#include <RpcBind.h>
#include <RpcBonsai.h>
  
#define lupineOffset 4

    /* from RpcPktIO, etc. */
extern int Call();
extern int *mySoc;
extern StartCall();

    /* from RpcSignals */
extern int RejectUnbound;

    /* from Pup Package */
extern struct PBI *GetPBI();
extern ReleasePBI();

    /* from Signaller */
extern DISABLE();
extern ENABLEWithFrame();
extern SIGNAL();

    /* from Runtime */
extern Call1();
extern CallersFrame();
extern MoveBlock();
extern MyFrame();

  /* First proc index is 4. */

static UnwindPkt(sig, code, seal)
  int sig, code;
  struct Seal1 *seal;
  {
  ReleasePBI(seal->data[0]);
  DISABLE(seal);
  };

static struct PBI
*GetUnwindPkt(seal)
  struct Seal1 *seal;
  {
  struct PBI *pkt;
  pkt = GetPBI(mySoc);
  ENABLEWithFrame(UNWIND, &UnwindPkt, seal, CallersFrame(MyFrame()));
  seal->data[0] = (int) pkt;
  return (pkt);
  };

/* *************** Client Interface to RPC *************** */

/* The client calls StartBonsai(seal) to receive a buffer area.
    (Really a pointer into a PBI)

    The client constructs the call
    The client calls
      CallBonsai(seal, length);

    The results of the call, if any are found in the same place.
    The client calls CleanupCall(seal) to finish.

 */

int *StartBonsai(interface, seal)
  struct ImportInstance *interface;
  struct Seal1 *seal;
  {
  struct PBI *pkt;
  struct Header *hdr;
  /* Releases on unwind ! */
  pkt = GetUnwindPkt(seal);
  StartCall(pkt, interface, interface->currentConversation);
  hdr = pkt->pup;
  return(&hdr->callData.words[0]);
  };

CallBonsai(seal, arglen)
  struct Seal1 *seal;
  int arglen;
  {
  Call(seal->data[0], arglen, maxDataLength);
  };

CleanupCall(seal)
  struct Seal1 *seal;
  {
  ReleasePBI(seal->data[0]);
  DISABLE(seal);
  };

/* client procedure is called with integer pointer to procedure
    index.  (First argument is ptr[1].)
    Client procedure will store return arguments
    starting at ptr[0] and return the number of
    words of return arguments
 */

int BonsaiDispatcher(pkt, newLength, conversation, sSpecsT)
  struct PBI *pkt;
  int newLength;
  int *conversation;
  struct SSpecsTable *sSpecsT;
  {
  int rout, argLen, *wp;
  int thisProc;
  struct Header *hdr;
  hdr = pkt->pup;
  wp = &hdr->callData.words[0];
  rout = Swab(*wp);
  if ((rout < lupineOffset) || (rout > sSpecsT->maxProcs)) SIGNAL(RejectUnbound);
  thisProc = sSpecsT->procs[rout];
  if (thisProc == 0) SIGNAL(RejectUnbound);
  return (Call1(thisProc, wp));
  };

/* GetServerConversation is the same as the one in RPCFir */

/* ***** Utilities ***** */

int *StringToPkt(pp, s)
  int *pp;
  struct ShortSTRING *s;
  {
  int len;
  if (s == 0) *pp++ = swapped1; /* isNil */
  else {
    *pp++ = 0; /* isNil */
    *pp++ = Swab(s->length);
    len = (s->length+1) >> 1;  /* text only */
    MoveBlock(pp, &s->text[0], len);
    pp += len;
    };
  return (pp);
  };

/* These procedures return the allocated object, but also update
    the client's copy of the pointer into the packet.
 */

struct ShortSTRING
*AllocStringFromPkt(pp)
  int **pp;
  {
  int len, *wp;
  struct ShortSTRING *s;
  wp = *pp;
  if (*wp) {
    *pp = wp+1;
    return(0);
    };
  len = (Swab(wp[1])+5)/2;
  if (len > 100) CallSwat(ecLarkImpl + 22);
  s = (struct ShortSTRING *) GetFixed(len);
  MoveBlock(s, wp, len);
  s->maxLength = Swab(s->maxLength);
  s->length = s->maxLength;
  *pp = wp + len;
  return(s);
  };

int *AllocWordsFromPkt(pp, swap)
  int **pp;
  int swap;  /* boolean */
  {
  int len, *wp;
  int *wseq;
  wp = *pp;
  if (*wp) {
    *pp = wp+1;
    return(0);
    };
  len = Swab(wp[1]);
  if (len > 100) CallSwat(ecLarkImpl + 22);
  wseq = GetFixed(len+1);
  *wseq = Swab(wp[3]);
  Marshall(swap, wseq+1, &wp[4], len);
  *pp = wp + len + 4;
  return(wseq);
  };

SwabInPlace(addr, words)
  int *addr, words;
  {
  Marshall(true, addr, addr, words);
  };