/* Notes */ /*{{{C}}}*//*{{{*/ /* 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 */ /*{{{*/ #ifdef DMALLOC #include "dmalloc.h" #endif #include #include #include #include #include #include "default.h" #include "display.h" #include "eval.h" #include "main.h" #include "parser.h" #include "sheet.h" #include "xdr.h" /*}}}*/ typedef struct Old_token_struc { Type type; union { char *string; double flt; long integer; Operator op; char *lident; int fident; int location[3]; char *err; } u; } OldToken; /* xdr_token */ /*{{{*/ static bool_t xdr_token(XDR *xdrs, OldToken *t) { int x,result; if (xdrs->x_op == XDR_DECODE) memset(t,0,sizeof(OldToken)); else return false; x=t->type; if (t->type==OPERATOR) x|=t->u.op<<8; result=xdr_int(xdrs,&x); if ((x&0xff)==OPERATOR) t->u.op=(x>>8)&0xff; t->type=x&0xff; if (result==0) return result; switch (t->type) { /* EMPTY */ /*{{{*/ case EMPTY: { return 1; } /*}}}*/ /* STRING */ /*{{{*/ case STRING: { return xdr_wrapstring(xdrs,&(t->u.string)); } /*}}}*/ /* FLOAT */ /*{{{*/ case FLOAT: { return xdr_double(xdrs,&(t->u.flt)); } /*}}}*/ /* INT */ /*{{{*/ case INT: { return xdr_long(xdrs,&(t->u.integer)); } /*}}}*/ /* OPERATOR */ /*{{{*/ case OPERATOR: { return 1; /* since op is encoded in type */ } /*}}}*/ /* LIDENT */ /*{{{*/ case LIDENT: { return xdr_wrapstring(xdrs,&(t->u.lident)); } /*}}}*/ /* FIDENT */ /*{{{*/ case FIDENT: { return xdr_int(xdrs,&(t->u.fident)); } /*}}}*/ /* LOCATION */ /*{{{*/ case LOCATION: { return (xdr_int(xdrs,&(t->u.location[0])) && xdr_int(xdrs,&(t->u.location[1])) && xdr_int(xdrs,&(t->u.location[2]))); } /*}}}*/ /* EEK */ /*{{{*/ case EEK: { return xdr_wrapstring(xdrs,&(t->u.err)); } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } return 0; } /*}}}*/ /* xdr_tokenptr */ /*{{{*/ static bool_t xdr_tokenptr(XDR *xdrs, OldToken **t) { bool_t nonnull; if (!xdr_bool(xdrs, &nonnull)) return false; if (!nonnull) { *t = (OldToken *)0; return true; } *t = malloc(sizeof(OldToken)); return xdr_token(xdrs, *t); } /*}}}*/ /* xdr_tokenptrvec */ /*{{{*/ static bool_t xdr_tokenptrvec(XDR *xdrs, OldToken ***t) { unsigned int len; int result; assert(t!=(OldToken***)0); if (xdrs->x_op!=XDR_DECODE) assert(0); if (!xdr_u_int(xdrs, &len)) return false; *t = malloc(sizeof(OldToken*) * (len+1)); (*t)[len] = (OldToken*)0; for (size_t i = 0; i < len; ++i) if (!xdr_tokenptr(xdrs, *t + i)) return false; return true; } /*}}}*/ /* 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); assert(xdrs->x_op == XDR_DECODE); OldToken **ot; for (TokVariety tv = BASE_CONT; tv <= ITER_CONT; ++tv) { if (!xdr_tokenptrvec(xdrs, &ot)) return false; size_t veclen = 0; while (ot[veclen]) ++veclen; Token **nt = malloc(sizeof(Token*) * (veclen + 1)); nt[veclen] = NULLTOKEN; for (size_t ti = 0; ti < veclen; ++ti) { nt[ti] = malloc(sizeof(Token)); cleartoken(nt[ti]); nt[ti]->type = ot[ti]->type; switch (ot[ti]->type) { case EMPTY: break; case STRING: nt[ti]->u.string = ot[ti]->u.string; break; case FLOAT: nt[ti]->u.flt = ot[ti]->u.flt; break; case INT: nt[ti]->u.integer = ot[ti]->u.integer; break; case OPERATOR: nt[ti]->u.op = ot[ti]->u.op; break; case LIDENT: nt[ti]->u.lident = ot[ti]->u.lident; break; case FIDENT: nt[ti]->u.fident = ot[ti]->u.fident; break; case LOCATION: nt[ti]->u.location[0] = ot[ti]->u.location[0]; nt[ti]->u.location[1] = ot[ti]->u.location[1]; nt[ti]->u.location[2] = ot[ti]->u.location[2]; break; case EEK: nt[ti]->u.err = ot[ti]->u.err; break; default: assert(0); } free(ot[ti]); } free(ot); Token tok = eval_safe(nt, LITERAL); tvecfree(nt); if (tok.type == EEK) { tfree(&tok); return false; } cell->tok[tv] = tok; } 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)|((cell->transparent&1)<<4)|((cell->ignored&1)<<5)|((cell->bold&1)<<6)|((cell->underline&1)<<7); 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); cell->transparent=((x&(1<<4))!=0); cell->ignored=((x&(1<<5))!=0); cell->bold=((x&(1<<6))!=0); cell->underline=((x&(1<<7))!=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)); } /*}}}*/ /* xdr_magic */ /*{{{*/ #define MAGIC0 (('#'<<24)|('!'<<16)|('t'<<8)|'e') #define MAGIC1 (('a'<<24)|('p'<<16)|('o'<<8)|'t') #define MAGIC2 (('\n'<<24)|('x'<<16)|('d'<<8)|'r') bool_t xdr_magic(XDR *xdrs) { long m0,m1,m2; m0=MAGIC0; m1=MAGIC1; m2=MAGIC2; return (xdr_long(xdrs,&m0) && m0==MAGIC0 && xdr_long(xdrs,&m1) && m1==MAGIC1 && xdr_long(xdrs,&m2) && m2==MAGIC2); } /*}}}*/ /* savexdr -- save a spread sheet in XDR */ /*{{{*/ const char *savexdr(Sheet *sheet, const char *name, unsigned int *count) { return _("Saving in xdr format is no longer supported. Use portable text."); /* variables */ /*{{{*/ FILE *fp; XDR xdrs; int x,y,z; /*}}}*/ *count=0; if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno); xdrstdio_create(&xdrs,fp,XDR_ENCODE); if (!xdr_magic(&xdrs)) { xdr_destroy(&xdrs); (void)fclose(fp); return strerror(errno); } for (x=sheet->dimx-1; x>=0; --x) for (z=sheet->dimz-1; z>=0; --z) { int width; int u; width=columnwidth(sheet,x,z); if (width!=DEF_COLUMNWIDTH) { u=0; if (xdr_int(&xdrs,&u)==0 || xdr_column(&xdrs,&x,&z,&width)==0) { xdr_destroy(&xdrs); (void)fclose(fp); return strerror(errno); } } for (y=sheet->dimy-1; y>=0; --y) { if (CELL_ATC(sheet,x,y,z)!=NULLCELL) { u=1; if (xdr_int(&xdrs,&u)==0 || xdr_int(&xdrs,&x)==0 || xdr_int(&xdrs,&y)==0 || xdr_int(&xdrs,&z)==0 || xdr_cell(&xdrs,CELL_ATC(sheet,x,y,z))==0) { xdr_destroy(&xdrs); (void)fclose(fp); return strerror(errno); } ++*count; } } } xdr_destroy(&xdrs); if (fclose(fp)==EOF) return strerror(errno); sheet->changed=0; return (const char*)0; } /*}}}*/ /* loadxdr -- load a spread sheet in XDR */ /*{{{*/ const char *loadxdr(Sheet *sheet, const char *name) { /* variables */ /*{{{*/ FILE *fp; XDR xdrs; Location w; int width; int u; int olderror; Cell *nc; /*}}}*/ if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno); xdrstdio_create(&xdrs,fp,XDR_DECODE); if (!xdr_magic(&xdrs)) { #if 0 xdr_destroy(&xdrs); fclose(fp); return _("This is not a teapot worksheet in XDR format"); #else xdr_destroy(&xdrs); rewind(fp); xdrstdio_create(&xdrs,fp,XDR_DECODE); #endif } freesheet(sheet,0); while (xdr_int(&xdrs,&u)) switch (u) { /* 0 -- column width element */ /*{{{*/ case 0: { if (xdr_column(&xdrs,&(w[X]),&(w[Z]),&width)==0) { olderror=errno; xdr_destroy(&xdrs); (void)fclose(fp); return strerror(olderror); } setwidth(sheet,w[X],w[Z],width); break; } /*}}}*/ /* 1 -- cell element */ /*{{{*/ case 1: { if (xdr_int(&xdrs,&(w[X]))==0 || xdr_int(&xdrs,&(w[Y]))==0 || xdr_int(&xdrs,&(w[Z]))==0) { olderror=errno; xdr_destroy(&xdrs); (void)fclose(fp); return strerror(olderror); } nc = initcellofsheet(sheet, w); if (xdr_cell(&xdrs, nc)==0) { freecellofsheet(sheet, w); olderror=errno; xdr_destroy(&xdrs); (void)fclose(fp); return strerror(olderror); } break; } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: { xdr_destroy(&xdrs); fclose(fp); sheet->changed=0; cachelabels(sheet); forceupdate(sheet); return _("Invalid record, loading aborted"); } /*}}}*/ } xdr_destroy(&xdrs); if (fclose(fp)==EOF) return strerror(errno); sheet->changed=0; cachelabels(sheet); forceupdate(sheet); redraw_sheet(sheet); return (const char*)0; } /*}}}*/