/* (C) Copyright International Business Machines Corporation 23 January */
/* 1990.  All Rights Reserved. */
/*  */
/* See the file USERAGREEMENT distributed with this software for full */
/* terms and conditions of use. */
#ifndef lint
static char sccsinfo[] = "@(#)hxdr.c	1.10 3/13/90";
#endif

#define _BSD 43

#define HXDR_VERSION 6
				/* change this when there is a change in */
				/*  data formats. */

#include <stdio.h>
#include <rpc/rpc.h>

#include "ops.h"
#include "storage.h"
#include "shape.h"

static XDR xdr_descriptor;

FILE *f;

XDR *
hxdr_read(fname)
char *fname;
{
    f = fopen(fname, "r");
    if (not f) {
#ifdef DEBUG
      if (debug_level(1)) 
        (void) fprintf(stderr, "Couldn't open '%s'", fname);
#endif DEBUG
      return(nil);
    }

#ifdef DEBUG
    if (debug_level(2))
      (void) fprintf(stderr, "XDR Reading '%s'.\n", fname);
#endif DEBUG

    xdrstdio_create(&xdr_descriptor, f, XDR_DECODE);
    return(&xdr_descriptor);
}

XDR *
hxdr_write(fname)
char *fname;
{
    f = fopen(fname, "w");
    if (not f)
      return(nil);
    xdrstdio_create(&xdr_descriptor, f, XDR_ENCODE);
    return(&xdr_descriptor);
}



xdr_status
xdr_datarep(xdrs, drpp, shape)
XDR *xdrs;
datarep **drpp;
shapep shape;
{
    extern datarep *datarepmap[];

    tsdrno drnumber;

    if (xdrs->x_op isnt XDR_FREE) {

      if (xdrs->x_op is XDR_ENCODE) {
        drnumber = (*drpp)->number;
      }

      if (shape->tsdr is &dr_bottom) {
        if (!xdr_u_short(xdrs, &drnumber))
          return(XDR_FAIL);
      }
      else
        drnumber = shape->tsdr->number;
      
      if (xdrs->x_op is XDR_DECODE) {
        *drpp = datarepmap[drnumber];
      }
    }

    return(XDR_OK);
}


xdr_status
hxdr_main(xdrs, obj)
XDR *xdrs;
object *obj;
{
    xdr_status hxdr_object();
    unsigned version;
    shapeobj shape;
    xdr_status rc;
    void free_shape(), init_shares(), term_shares();

    version = HXDR_VERSION;

    if (not xdr_u_int(xdrs, &version))
      return(XDR_FAIL);

    if (version isnt HXDR_VERSION) {
	nilerror("hxdr_main", "Attempt to load file with incompatible XDR format");
	return(XDR_FAIL);
    }

    shape.tsdr = &dr_bottom;

    init_shares();
    rc = hxdr_object(xdrs, obj, &shape);
    free_shape(&shape);
    term_shares();

    return(rc);
}


xdr_status 
hxdr_object(xdrs, obj, shape)
XDR *xdrs;
object *obj;
shapep shape;
{
  xdr_status rc1, rc2;

  rc1 = xdr_datarep(xdrs, & obj->tsdr, shape);
  rc2 = obj->tsdr->xdr(xdrs, obj, shape);
  return(rc1 and rc2);
}


void
free_shape(shape)
shapep shape;
{
  switch (shape->tsdr->number) {
  case 1:    /* &dr_bottom */
    /* do nothing */
    break;
  case 2:    /* &dr_boolean */
  case 3:    /* &dr_integer */
  case 4:    /* &dr_enumeration */
  case 5:    /* &dr_ord_enumeration */
  case 6:    /* &dr_nominal */
  case 7:    /* &dr_real */
    free_shape_scalar(shape);
    break;
  case 8:    /* &dr_record */
    free_shape_record(shape);
    break;
  case 9:    /* &dr_variant */
    free_shape_variant(shape);
    break;
  case 10:   /* &dr_table */
    free_shape_table(shape);
    break;
  case 11:   /* &dr_polymorph */
    free_shape_polymorph(shape);
    break;
  case 12:   /* &dr_inport */
    /* can't happen now */
    break;
  case 13:   /* &dr_outport */
    free_shape_scalar(shape);
    break;
  /* case 14 doesn't exist */
  case 15:   /* &dr_callmessage */
    free_shape_callmessage(shape);
    break;
  case 16:   /* &dr_program */
    free_shape_program(shape);
    break;
  }
}


NILOP(o_write)
{
    predef_exception retcode;
    predef_exception che_write();

    if ((retcode = che_write(DstObj, SrcObj, args->sched))
	isnt Normal)
      raise_builtin(retcode);
}

/* che_write is called directly from generated C-code. */
predef_exception
che_write(dstobj, srcobj, sched)
objectp dstobj;
objectp srcobj;
schedblock *sched;
{
    XDR *xdrs;
    predef_exception retcode;

    xdrs = hxdr_write(stringval(srcobj));

    if (not xdrs)
      retcode = Depletion;
    else
      if (hxdr_main(xdrs, dstobj)) 
	retcode = Normal;
      else
	retcode = Depletion;

    (void) fclose(f);
    return(retcode);
}


NILOP(o_read)
{
    predef_exception retcode;
    predef_exception che_read();

    if ((retcode = che_read(DstObj, SrcObj, args->sched))
	isnt Normal)
      raise_builtin(retcode);
}

/* che_read is called directly from generated C-code. */
predef_exception
che_read(dstobj, srcobj, sched)
objectp dstobj;
objectp srcobj;
schedblock *sched;
{
    void re_finalize();
    XDR *xdrs;
    object readObj;
    extern flag cherm_flag;
    predef_exception retcode;

    xdrs = hxdr_read(stringval(srcobj));

    if (not xdrs)
      retcode = Depletion;
    else {
      if (hxdr_main(xdrs, &readObj)) {
          if (not cherm_flag)
            re_finalize(dstobj, F_DISCARD, sched);
          /* finalize the value of the destination; */
          *(dstobj) = readObj;
	  retcode = Normal;
      }
      else {
        xdr_free(hxdr_main, &readObj);
	retcode = Depletion;
      }
    }
      
    if (f) {
      (void) fclose(f);
    }
    return(retcode);
}

/* support for storage sharing */
static int ntshare;
static int maxtshare;
static dfd_table **tshares;
#define STDNTSHARE 500		/* big enough to handle most cases */
static dfd_table *stdtshares[STDNTSHARE];

static int npshare;
static int maxpshare;
static pd_program **pshares;
#define STDNPSHARE 50		/* big enough to handel most cases */
static pd_program *stdpshares[STDNPSHARE];

void
init_shares()
{
  ntshare = npshare = 0;
  maxtshare = STDNTSHARE;
  tshares = stdtshares;
  maxpshare = STDNPSHARE;
  pshares = stdpshares;
}

void
term_shares()
{
  int i;
  for (i = 0; i < ntshare; i++)
    tshares[i]->shareidx = -1;
  if (tshares isnt stdtshares)
    freemain(tshares, maxtshare*sizeof(dfd_table *));
  if (pshares isnt stdpshares)
    freemain(pshares, maxpshare*sizeof(pd_program *));
}

int
add_share_tbl(tbl)
dfd_table *tbl;
{
  dfd_table **newshares;
  int newmax;
  if (ntshare == maxtshare) {
    newmax = 2*maxtshare;
    if ((newshares = (dfd_table **)
	 getmain(newmax * sizeof(dfd_table *))) is nil)
      return(-1);
    bcopy(tshares, newshares, maxtshare*sizeof(dfd_table *));
    if (tshares isnt stdtshares)
      freemain(tshares, maxtshare * sizeof(dfd_table *));
    maxtshare = newmax;
    tshares = newshares;
  }
  tshares[ntshare] = tbl;
  tbl->shareidx = ntshare;
  return(ntshare ++);
}

int
find_share_tbl(tbl)
dfd_table *tbl;
{
  if (tbl->shareidx >= 0)
    if (tbl->shareidx < ntshare)
      if (tshares[tbl->shareidx] == tbl)
	return(tbl->shareidx);
  return(-1);
}

dfd_table *
get_share_tbl(idx)
int idx;
{
  return(tshares[idx]);
}

int
add_share_prog(prog)
pd_program *prog;
{
  pd_program **newshares;
  int newmax;
  if (npshare == maxpshare) {
    newmax = 2 * maxpshare;
    if ((newshares = (pd_program **) 
	 getmain(newmax * sizeof(pd_program *))) is nil)
      return(-1);
    bcopy(pshares, newshares, maxpshare*sizeof(pd_program *));
    if (pshares isnt stdpshares)
      freemain(pshares, maxpshare*sizeof(pd_program *));
    maxpshare = newmax;
    pshares = newshares;
  }
  pshares[npshare] = prog;
  return(npshare ++);
}

int
find_share_prog(prog)
pd_program *prog;
{
  int i;
  for (i = 0; i < npshare; i++)
    if (pshares[i] == prog)
      return(i);
  return(-1);
}

pd_program *
get_share_prog(idx)
int idx;
{
  return(idx < npshare ? pshares[idx] : NULL);
}
