/*{{{}}}*/
/*{{{  Notes*/
/*

xdr_enum() is unusable, because enum_t may have a different size than
an enum.  The construction

  int_value=*enum_value;
  result=xdr_int(xdrs,&int_value);
  *enum_value=int_value;
  return result;

solves the problem and works for both encoding and decoding.
Unfortunately, I could not yet find such a solution for a variable sized
array terminated by a special element.

*/
/*}}}  */
/*{{{  #includes*/
#include <rpc/rpc.h>
#include <assert.h>
#include <stdio.h>

#include "sheet.h"
#include "xdr.h"
/*}}}  */

/*{{{  xdr_token*/
static bool_t xdr_token(XDR *xdrs, Token *t)
{
  int x,result;

  if (xdrs->x_op==XDR_DECODE) memset(t,0,sizeof(Token));
  x=t->type;
  result=xdr_int(xdrs,&x);
  t->type=x;
  if (result==0) return result;
  switch (t->type)
  {
    case EMPTY: return 1;
    case STRING: return xdr_wrapstring(xdrs,&(t->u.string));
    case FLOAT: return xdr_double(xdrs,&(t->u.flt));
    case INT: return xdr_long(xdrs,&(t->u.integer));
    case OPERATOR: x=t->u.operator; result=xdr_int(xdrs,&x); t->u.operator=x; return result;
    case IDENT: return xdr_wrapstring(xdrs,&(t->u.ident));  
    case LOCATION: return (xdr_int(xdrs,&(t->u.location[0])) && xdr_int(xdrs,&(t->u.location[1])) && xdr_int(xdrs,&(t->u.location[2])));
    case EEK: return xdr_wrapstring(xdrs,&(t->u.ident));
    default: assert(0);
  }
  return 0;
}  
/*}}}  */
/*{{{  xdr_tokenptr*/
static bool_t xdr_tokenptr(XDR *xdrs, Token **t)
{
  return xdr_pointer(xdrs,(char**)t,sizeof(Token),(xdrproc_t)xdr_token);
}
/*}}}  */
/*{{{  xdr_tokenptrvec*/
static bool_t xdr_tokenptrvec(XDR *xdrs, Token ***t)
{
  unsigned int len;
  int result;

  assert(t!=(Token***)0);
  if (xdrs->x_op!=XDR_DECODE)
  {
    Token **run;
    
    if (*t==(Token**)0) len=0;
    else for (len=1,run=*t; *run!=(Token*)0; ++len,++run);
  }
  result=xdr_array(xdrs,(char**)t,&len,65536,sizeof(Token*),(xdrproc_t)xdr_tokenptr);
  if (len==0) *t=(Token**)0;
  return result;
}
/*}}}  */
/*{{{  xdr_mystring*/
static bool_t xdr_mystring(XDR *xdrs, char **str)
{
  static struct xdr_discrim arms[3]=
  { 
    { 0, (xdrproc_t)xdr_void },
    { 1, (xdrproc_t)xdr_wrapstring },
    { -1, (xdrproc_t)0 }
  };
  enum_t x;
  int res;

  x=(*str!=(char*)0);
  res=xdr_union(xdrs, &x, (char*)str, arms, (xdrproc_t)0);
  if (!x) *str=(char*)0;
  return res;
}
/*}}}  */

/*{{{  Notes*/
/*

The saved sheet consists of three xdr_int()s which specify x, y and z
position of the cell saved with xdr_cell().  Perhaps xdr_cell could be
given those as parameters, which would be more correct concerning the
purpose of the xdr_functions.  Then again, reading the position may
fail (eof), whereas after the position has been read, xdr_cell() must
not fail when loading a sheet.

*/
/*}}}  */
/*{{{  xdr_cell*/
bool_t xdr_cell(XDR *xdrs, Cell *cell)
{
  int result,x;

  assert(cell!=(Cell*)0);
  if (!(xdr_tokenptrvec(xdrs, &(cell->contents)) && xdr_token(xdrs, &(cell->value)))) return 0;
  if (xdr_mystring(xdrs, &(cell->label))==0) return 0;
  x=cell->adjust;
  result=xdr_int(xdrs, &x);
  cell->adjust=x;
  if (result==0) return 0;
  if (xdr_int(xdrs, &(cell->precision))==0) return 0;
  x=(cell->updated&1)|((cell->shadowed&1)<<1)|((cell->scientific&1)<<2)|((cell->locked&1)<<3);
  result=xdr_int(xdrs, &x);
  cell->updated=((x&(1))!=0);
  cell->shadowed=((x&(1<<1))!=0);
  cell->scientific=((x&(1<<2))!=0);
  cell->locked=((x&(1<<3))!=0);
  return result;
}
/*}}}  */
/*{{{  xdr_column*/
bool_t xdr_column(XDR *xdrs, int *x, int *z, int *width)
{
  return (xdr_int(xdrs, x) && xdr_int(xdrs, z) && xdr_int(xdrs, width));
}
/*}}}  */
