Rev 2 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Langage for Statistical Data Analysis* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "Defn.h"#include "Mathlib.h"#include "Fileio.h"/* Static Globals */static char buf[MAXELTSIZE]; /* Buffer for character strings */static char *bufp; /* A pointer to that buffer */static int NSymbol; /* Number of symbols */static int NSave; /* Number of non-symbols */static int NTotal; /* NSymbol + NSave */static int NVSize; /* Number of vector cells */static int *OldOffset; /* Offsets in previous incarnation */static SEXP *NewAddress; /* Addresses in this incarnation */static int VersionId;static SEXP DataLoad(FILE*);static void DataSave(SEXP, FILE*);/* I/O Function Pointers */static void (*OutInit)(FILE*);static void (*OutInteger)(FILE*, int);static void (*OutReal)(FILE*, double);static void (*OutComplex)(FILE*, complex);static void (*OutString)(FILE*, char*);static void (*OutSpace)(FILE*);static void (*OutNewline)(FILE*);static void (*OutTerm)(FILE*);static void (*InInit)(FILE*);static int (*InInteger)(FILE*);static double (*InReal)(FILE*);static complex (*InComplex)(FILE*);static char* (*InString)(FILE*);static void (*InTerm)(FILE*);/*********************************//* *//* Dummy Placeholder Routine *//* *//*********************************/static void Dummy(FILE *fp){}/************************************//* *//* Functions for Ascii Pickling *//* *//************************************/static void AsciiOutInteger(FILE *fp, int i){if(i == NA_INTEGER) fprintf(fp, "NA");else fprintf(fp, "%d", i);}static int AsciiInInteger(FILE *fp){int x;fscanf(fp, "%s", buf);if(strcmp(buf, "NA") == 0) return NA_INTEGER;else {sscanf(buf, "%d", &x);return x;}}static void AsciiOutReal(FILE *fp, double x){if(!FINITE(x)) fprintf(fp, "NA");else fprintf(fp, "%g", x);}static double AsciiInReal(FILE *fp){double x;fscanf(fp, "%s", buf);if(strcmp(buf, "NA") == 0) x = NA_REAL;else sscanf(buf, "%lg", &x);return x;}static void AsciiOutComplex(FILE *fp, complex x){if(!FINITE(x.r) || !FINITE(x.i)) fprintf(fp, "NA NA");else fprintf(fp, "%g %g", x.r, x.i);}static complex AsciiInComplex(FILE *fp){complex x;fscanf(fp, "%s", buf);if(strcmp(buf, "NA") == 0) x.r = NA_REAL;else sscanf(buf, "%lg", &x.r);fscanf(fp, "%s", buf);if(strcmp(buf, "NA") == 0) x.i = NA_REAL;else sscanf(buf, "%lg", &x.i);return x;}static void AsciiOutSpace(FILE *fp){fputc(' ', fp);}static void AsciiOutNewline(FILE *fp){fputc('\n', fp);}/* TODO: To make saved files completely portable, the output *//* representation of strings should be completely ascii. This *//* includes control characters and non-ascii characters. *//* This could be done with \ooo escapes. */static void AsciiOutString(FILE *fp, char *s){char *p = s;fputc('\"', fp);while(*p) {switch(*p) {case '\n': fputc('\\', fp); fputc('n', fp); break;case '\t': fputc('\\', fp); fputc('t', fp); break;case '\v': fputc('\\', fp); fputc('v', fp); break;case '\b': fputc('\\', fp); fputc('b', fp); break;case '\r': fputc('\\', fp); fputc('r', fp); break;case '\f': fputc('\\', fp); fputc('f', fp); break;case '\a': fputc('\\', fp); fputc('a', fp); break;case '\\': fputc('\\', fp); fputc('\\', fp); break;case '\?': fputc('\\', fp); fputc('\?', fp); break;case '\'': fputc('\\', fp); fputc('\'', fp); break;case '\"': fputc('\\', fp); fputc('\"', fp); break;default: fputc(*p, fp); break;}p++;}fputc('\"', fp);}static char *AsciiInString(FILE *fp){int c, quote;bufp = buf;while ((c = R_fgetc(fp)) != '"');while ((c = R_fgetc(fp)) != R_EOF && c != '"') {if (c == '\\') {if((c = R_fgetc(fp)) == R_EOF) break;switch(c) {case 'n': c = '\n'; break;case 't': c = '\t'; break;case 'v': c = '\v'; break;case 'b': c = '\b'; break;case 'r': c = '\r'; break;case 'f': c = '\f'; break;case 'a': c = '\a'; break;case '\\': c = '\\'; break;case '\?': c = '\?'; break;case '\'': c = '\''; break;case '\"': c = '\"'; break;default: break;}}*bufp++ = c;}*bufp = '\0';return buf;}void AsciiSave(SEXP s, FILE *fp){OutInit = Dummy;OutInteger = AsciiOutInteger;OutReal = AsciiOutReal;OutComplex = AsciiOutComplex;OutString = AsciiOutString;OutSpace = AsciiOutSpace;OutNewline = AsciiOutNewline;OutTerm = Dummy;DataSave(s, fp);}SEXP AsciiLoad(FILE *fp){VersionId = 0;InInit = Dummy;InInteger = AsciiInInteger;InReal = AsciiInReal;InComplex = AsciiInComplex;InString = AsciiInString;InTerm = Dummy;return DataLoad(fp);}SEXP AsciiLoadOld(FILE *fp, int version){VersionId = version;InInit = Dummy;InInteger = AsciiInInteger;InReal = AsciiInReal;InComplex = AsciiInComplex;InString = AsciiInString;InTerm = Dummy;return DataLoad(fp);}#ifdef HAVE_RPC_XDR_H/***********************************************//* *//* Functions for Binary Pickling Using XDR *//* *//***********************************************/#include <rpc/rpc.h>XDR xdrs;static void XdrOutInit(FILE *fp){xdrstdio_create(&xdrs, fp, XDR_ENCODE);}static void XdrOutTerm(FILE *fp){xdr_destroy(&xdrs);}static void XdrInInit(FILE *fp){xdrstdio_create(&xdrs, fp, XDR_DECODE);}static void XdrInTerm(FILE *fp){xdr_destroy(&xdrs);}static void XdrOutInteger(FILE *fp, int i){if (!xdr_int(&xdrs, &i)) {xdr_destroy(&xdrs);error("a write error occured\n");}}static int XdrInInteger(FILE * fp){int i;if (!xdr_int(&xdrs, &i)) {xdr_destroy(&xdrs);error("a read error occured\n");}return i;}static void XdrOutReal(FILE *fp, double x){if (!xdr_double(&xdrs, &x)) {xdr_destroy(&xdrs);error("a write error occured\n");}}static double XdrInReal(FILE * fp){double x;if (!xdr_double(&xdrs, &x)) {xdr_destroy(&xdrs);error("a read error occured\n");}return x;}static void XdrOutComplex(FILE *fp, complex x){if (!xdr_double(&xdrs, &(x.r)) | !xdr_double(&xdrs, &(x.i))) {xdr_destroy(&xdrs);error("a write error occured\n");}}static complex XdrInComplex(FILE * fp){complex x;if (!xdr_double(&xdrs, &(x.r)) | !xdr_double(&xdrs, &(x.i))) {xdr_destroy(&xdrs);error("a read error occured\n");}return x;}static void XdrOutString(FILE *fp, char *s){if(!xdr_string(&xdrs, &s, MAXELTSIZE-1)) {xdr_destroy(&xdrs);error("a write error occured\n");}}static char *XdrInString(FILE *fp){char *bufp = buf;if(!xdr_string(&xdrs, &bufp, MAXELTSIZE-1)) {xdr_destroy(&xdrs);error("a read error occured\n");}return buf;}static void XdrSave(SEXP s, FILE *fp){OutInit = XdrOutInit;OutInteger = XdrOutInteger;OutReal = XdrOutReal;OutComplex = XdrOutComplex;OutString = XdrOutString;OutSpace = Dummy;OutNewline = Dummy;OutTerm = XdrOutTerm;DataSave(s, fp);}static SEXP XdrLoad(FILE *fp){VersionId = 0;InInit = XdrInInit;InInteger = XdrInInteger;InReal = XdrInReal;InComplex = XdrInComplex;InString = XdrInString;InTerm = XdrInTerm;return DataLoad(fp);}#endif/*************************************//* *//* Functions for Binary Pickling *//* *//*************************************/static void BinaryOutInteger(FILE *fp, int i){if (fwrite(&i, sizeof(int), 1, fp) != 1)error("a write error occured");}static int BinaryInInteger(FILE * fp){int i;if (fread(&i, sizeof(int), 1, fp) != 1)error("a read error occured\n");return i;}static void BinaryOutReal(FILE *fp, double x){if (fwrite(&x, sizeof(double), 1, fp) != 1)error("a write error occured\n");}static double BinaryInReal(FILE * fp){double x;if (fread(&x, sizeof(double), 1, fp) != 1)error("a read error occured\n");return x;}static void BinaryOutComplex(FILE *fp, complex x){if (fwrite(&x, sizeof(complex), 1, fp) != 1)error("a write error occured\n");}static complex BinaryInComplex(FILE * fp){complex x;if (fread(&x, sizeof(complex), 1, fp) != 1)error("a read error occured\n");return x;}static void BinaryOutString(FILE *fp, char *s){int n = strlen(s)+1; /* NULL too */if (fwrite(s, sizeof(char), n, fp) != n)error("a write error occured\n");}static char *BinaryInString(FILE *fp){bufp = buf;do {*bufp = R_fgetc(fp);}while (*bufp++);return buf;}void BinarySave(SEXP s, FILE *fp){OutInit = Dummy;OutInteger = BinaryOutInteger;OutReal = BinaryOutReal;OutComplex = BinaryOutComplex;OutString = BinaryOutString;OutSpace = Dummy;OutNewline = Dummy;OutTerm = Dummy;DataSave(s, fp);}SEXP BinaryLoad(FILE *fp){VersionId = 0;InInit = Dummy;InInteger = BinaryInInteger;InReal = BinaryInReal;InComplex = BinaryInComplex;InString = BinaryInString;InTerm = Dummy;return DataLoad(fp);}SEXP BinaryLoadOld(FILE *fp, int version){VersionId = version;InInit = Dummy;InInteger = BinaryInInteger;InReal = BinaryInReal;InComplex = BinaryInComplex;InString = BinaryInString;InTerm = Dummy;return DataLoad(fp);}/*******************************************//* *//* Magic Numbers for R Save File Types *//* *//*******************************************/void R_WriteMagic(FILE *fp, int number){unsigned char buf[5];number = abs(number);buf[0] = (number/1000) % 10 + '0';buf[1] = (number/100) % 10 + '0';buf[2] = (number/10) % 10 + '0';buf[3] = number % 10 + '0';buf[4] = '\n';fwrite((char*)buf, sizeof(char), 5, fp);}int R_ReadMagic(FILE *fp){unsigned char buf[6];int d1, d2, d3, d4, d1234;fread((char*)buf, sizeof(char), 5, fp);/* Intel gcc seems to screw up a single expression here */d1 = (buf[3]-'0') % 10;d2 = (buf[2]-'0') % 10;d3 = (buf[1]-'0') % 10;d4 = (buf[0]-'0') % 10;return d1234 = d1 + 10*d2 + 100*d3 + 1000*d4;}static void ReallocVector(SEXP s, int length){long size;switch (TYPEOF(s)) {case CHARSXP:size = 1 + BYTE2VEC(length + 1);break;case LGLSXP:case INTSXP:case FACTSXP:case ORDSXP:if (length <= 0) size = 0;else size = 1 + INT2VEC(length);break;case REALSXP:if (length <= 0) size = 0;else size = 1 + FLOAT2VEC(length);break;case CPLXSXP:if (length <= 0) size = 0;else size = 1 + COMPLEX2VEC(length);break;case STRSXP:case VECSXP:case EXPRSXP:if (length <= 0) size = 0;else size = 1 + PTR2VEC(length);break;default:error("invalid type in ReallocVector\n");}if (R_VMax - R_VTop < size)error("restore memory exhausted (should not happen)\n");LENGTH(s) = length;if (size > 0) {CHAR(s) = (char *) (R_VTop + 1);BACKPOINTER(*R_VTop) = s;R_VTop += size;}else CHAR(s) = (char*)0;}static void ReallocString(SEXP s, int length){long size = 1 + BYTE2VEC(length + 1);if (R_VMax - R_VTop < size)error("restore memory exhausted (should not happen)\n");if (TYPEOF(s) != CHARSXP)error("ReallocString: type conflict\n");CHAR(s) = (char*)(R_VTop + 1);LENGTH(s) = length;TAG(s) = R_NilValue;NAMED(s) = 0;ATTRIB(s) = R_NilValue;BACKPOINTER(*R_VTop) = s;R_VTop += size;}static void MarkSave(SEXP s){int i, len;if(s == R_NilValue || s == R_GlobalEnv|| s == R_UnboundValue|| s == R_MissingArg) return;if (s && !MARK(s)) {MARK(s) = 1;if (ATTRIB(s) != R_NilValue)MarkSave(ATTRIB(s));switch (TYPEOF(s)) {case BUILTINSXP:case SPECIALSXP:NSave++;break;case SYMSXP:NSymbol++;break;case CHARSXP:NSave++;NVSize += 1 + BYTE2VEC(LENGTH(s) + 1);break;case LGLSXP:case FACTSXP:case ORDSXP:case INTSXP:NSave++;NVSize += 1 + INT2VEC(LENGTH(s));break;case REALSXP:NSave++;NVSize += 1 + FLOAT2VEC(LENGTH(s));break;case CPLXSXP:NSave++;NVSize += 1 + COMPLEX2VEC(LENGTH(s));break;case STRSXP:case VECSXP:case EXPRSXP:NSave++;NVSize += 1 + PTR2VEC(len=LENGTH(s));for (i=0; i < len; i++)MarkSave(VECTOR(s)[i]);break;case ENVSXP:NSave++;MarkSave(FRAME(s));MarkSave(ENCLOS(s));break;case CLOSXP:case PROMSXP:case LISTSXP:case LANGSXP:case DOTSXP:NSave++;MarkSave(TAG(s));MarkSave(CAR(s));MarkSave(CDR(s));break;}}}static int NodeToOffset(SEXP s){if (s == R_NilValue) return -1;if (s == R_GlobalEnv) return -2;if (s == R_UnboundValue) return -3;if (s == R_MissingArg) return -4;return s - R_NHeap;;}static SEXP OffsetToNode(int offset){int l, m, r;if(offset == -1) return R_NilValue;if(offset == -2) return R_GlobalEnv;if(offset == -3) return R_UnboundValue;if(offset == -4) return R_MissingArg;/* binary search for offset */l = 0;r = NTotal - 1;do {m = (l + r)/2;if(offset < OldOffset[m])r = m - 1;elsel = m + 1;}while(offset != OldOffset[m] && l <= r);if(offset == OldOffset[m]) return NewAddress[m];error("unresolved node during restore\n");}static void DataSave(SEXP s, FILE *fp){int i, j, k, l, n;char *strp;SEXP t;/* compute the storage requirements *//* and write these to the save file *//* NSymbol = # of symbols written *//* NSave = # of symbols written *//* NVSize = # of vector cells written */NSave = 0;NSymbol = 0;NVSize = 0;unmarkPhase();MarkSave(s);OutInit(fp);OutInteger(fp, NSymbol); OutSpace(fp);OutInteger(fp, NSave); OutSpace(fp);OutInteger(fp, NVSize); OutNewline(fp);/* write out any required symbols */k = 0; n = 0;for (i=0 ; i<R_NSize ; i++) {if (MARK(&R_NHeap[i])) {if(TYPEOF(&R_NHeap[i]) == SYMSXP) {OutInteger(fp, n);OutSpace(fp);OutInteger(fp, NodeToOffset(&R_NHeap[i]));OutSpace(fp);OutString(fp, CHAR(PRINTNAME(&R_NHeap[i])));OutNewline(fp);k++;}n++;}}if(k != NSymbol || n != NSymbol+NSave)error("symbol count conflict\n");/* write out the forwarding address table */k = 0; n = 0;for (i=0 ; i<R_NSize ; i++) {if (MARK(&R_NHeap[i])) {if(TYPEOF(&R_NHeap[i]) != SYMSXP) {OutInteger(fp, n);OutSpace(fp);OutInteger(fp, NodeToOffset(&R_NHeap[i]));OutNewline(fp);k++;}n++;}}if(k != NSave || n != NSymbol+NSave)error("node count conflict\n");k = 0; n = 0;for (i = 0; i < R_NSize; i++) {if (MARK(&R_NHeap[i])) {if(TYPEOF(&R_NHeap[i]) != SYMSXP) {OutInteger(fp, n);OutSpace(fp);OutInteger(fp, TYPEOF(&R_NHeap[i]));OutSpace(fp);OutInteger(fp, OBJECT(&R_NHeap[i]));OutSpace(fp);OutInteger(fp, LEVELS(&R_NHeap[i]));OutSpace(fp);OutInteger(fp, NodeToOffset(ATTRIB(&R_NHeap[i])));OutSpace(fp);switch (TYPEOF(&R_NHeap[i])) {case LISTSXP:case LANGSXP:case CLOSXP:case PROMSXP:case ENVSXP:OutInteger(fp, NodeToOffset(CAR(&R_NHeap[i])));OutSpace(fp);OutInteger(fp, NodeToOffset(CDR(&R_NHeap[i])));OutSpace(fp);OutInteger(fp, NodeToOffset(TAG(&R_NHeap[i])));OutNewline(fp);break;case SPECIALSXP:case BUILTINSXP:OutInteger(fp, strlen(PRIMNAME(&R_NHeap[i])));OutSpace(fp);OutString(fp, PRIMNAME(&R_NHeap[i]));OutNewline(fp);break;case CHARSXP:OutInteger(fp, LENGTH(&R_NHeap[i]));OutSpace(fp);OutString(fp, CHAR(&R_NHeap[i]));OutNewline(fp);break;case REALSXP:l = LENGTH(&R_NHeap[i]);OutInteger(fp, l);OutNewline(fp);for (j = 0; j < l; j++) {OutReal(fp, REAL(&R_NHeap[i])[j]);if((j+1)%10 == 0 || j==l-1)OutNewline(fp);elseOutSpace(fp);}break;case CPLXSXP:l = LENGTH(&R_NHeap[i]);OutInteger(fp, l);OutNewline(fp);for (j = 0; j < l; j++) {OutComplex(fp, COMPLEX(&R_NHeap[i])[j]);if((j+1)%10 == 0 || j==l-1)OutNewline(fp);elseOutSpace(fp);}break;case INTSXP:case LGLSXP:case FACTSXP:case ORDSXP:l = LENGTH(&R_NHeap[i]);OutInteger(fp, l);OutNewline(fp);for (j = 0; j < l; j++) {OutInteger(fp, INTEGER(&R_NHeap[i])[j]);if((j+1)%10 == 0 || j==l-1)OutNewline(fp);elseOutSpace(fp);}break;case STRSXP:case VECSXP:case EXPRSXP:l = LENGTH(&R_NHeap[i]);OutInteger(fp, l);OutNewline(fp);for (j = 0; j < l; j++) {OutInteger(fp, NodeToOffset(VECTOR(&R_NHeap[i])[j]));if((j+1)%10 == 0 || j==l-1)OutNewline(fp);elseOutSpace(fp);}}k++;}n++;}}if(k != NSave) error("node count conflict\n");/* write out the offset of the list */OutInteger(fp, NodeToOffset(s));OutNewline(fp);OutTerm(fp);}static void RestoreSEXP(SEXP s, FILE *fp){unsigned int i, j, k, l;int len, t1;TYPEOF(s) = InInteger(fp);if(VersionId) {switch(VersionId) {case 16:/* In the version 0.16.1 -> 0.50 switch *//* we really introduced complex values *//* and found that numeric/complex numbers *//* had to be contiguous. Hence this switch */if(TYPEOF(s) == STRSXP) TYPEOF(s) = CPLXSXP;else if(TYPEOF(s) == CPLXSXP) TYPEOF(s) = STRSXP;break;default:error("restore compatibility error - no version %d compatibility\n", VersionId);}}OBJECT(s) = InInteger(fp);LEVELS(s) = InInteger(fp);ATTRIB(s) = OffsetToNode(InInteger(fp));switch (TYPEOF(s)) {case LISTSXP:case LANGSXP:case CLOSXP:case PROMSXP:case ENVSXP:CAR(s) = OffsetToNode(InInteger(fp));CDR(s) = OffsetToNode(InInteger(fp));TAG(s) = OffsetToNode(InInteger(fp));break;case SPECIALSXP:case BUILTINSXP:len = InInteger(fp);PRIMOFFSET(s) = StrToInternal(InString(fp));break;case CHARSXP:LENGTH(s) = len = InInteger(fp);ReallocString(s, len);strcpy(CHAR(s), InString(fp));break;case REALSXP:LENGTH(s) = len = InInteger(fp);ReallocVector(s, len);for (j = 0; j < len; j++)REAL(s)[j] = InReal(fp);break;case CPLXSXP:LENGTH(s) = len = InInteger(fp);ReallocVector(s, len);for (j = 0; j < len; j++)COMPLEX(s)[j] = InComplex(fp);break;case INTSXP:case FACTSXP:case ORDSXP:case LGLSXP:LENGTH(s) = len = InInteger(fp);;ReallocVector(s, len);for (j = 0; j < len; j++)INTEGER(s)[j] = InInteger(fp);break;case STRSXP:case VECSXP:case EXPRSXP:LENGTH(s) = len = InInteger(fp);ReallocVector(s, len);for (j = 0; j < len; j++) {VECTOR(s)[j] = OffsetToNode(InInteger(fp));}break;}}static SEXP DataLoad(FILE *fp){int i, j, k;char *vmaxsave;/* read in the size information */InInit(fp);NSymbol = InInteger(fp);NSave = InInteger(fp);NVSize = InInteger(fp);NTotal = NSymbol + NSave;/* allocate the forwarding-address tables *//* these are non-relocatable, so we must *//* save the current non-relocatable base */vmaxsave = vmaxget();OldOffset = (int*)R_alloc(NSymbol+NSave, sizeof(int));NewAddress = (SEXP*)R_alloc(NSymbol+NSave, sizeof(SEXP));for(i=0 ; i<NTotal ; i++) {OldOffset[i] = 0;NewAddress[i] = R_NilValue;}/* read in the required symbols *//* expanding the symbol table and *//* computing the forwarding addresses */for(i=0 ; i<NSymbol ; i++) {j = InInteger(fp);OldOffset[j] = InInteger(fp);NewAddress[j] = install(InString(fp));}/* symbols are all installed *//* gc() and check space */gc();/* a gc after this point will be a disaster *//* because nothing will have been protected */if ((VECREC *)vmaxget() - R_VTop < NVSize)error("vector heap is too small to restore data\n");if (R_Collected < NSave)error("cons heap is too small to restore data\n");/* build the full forwarding table *//* allocating SEXPs from the free list */for(i=0 ; i<NSave ; i++) {j = InInteger(fp);OldOffset[j] = InInteger(fp);NewAddress[j] = R_FreeSEXP;R_FreeSEXP = CDR(R_FreeSEXP);}/* restore the saved nodes */for (i=0 ; i < NSave ; i++) {RestoreSEXP(NewAddress[InInteger(fp)], fp);}/* restore the heap */vmaxset(vmaxsave);/* return the "top-level" object *//* this is usually a list */InTerm(fp);return OffsetToNode(InInteger(fp));}void R_SaveToFile(SEXP obj, FILE *fp, int ascii){if(ascii) {R_WriteMagic(fp, R_MAGIC_ASCII);AsciiSave(obj, fp);}else {#ifdef HAVE_RPC_XDR_HR_WriteMagic(fp, R_MAGIC_XDR);XdrSave(obj, fp);#elseR_WriteMagic(fp, R_MAGIC_BINARY);BinarySave(obj, fp);#endif}}SEXP R_LoadFromFile(FILE *fp){SEXP ans;switch(R_ReadMagic(fp)) {#ifdef HAVE_RPC_XDR_Hcase R_MAGIC_XDR:ans = XdrLoad(fp);break;#endifcase R_MAGIC_BINARY:ans = BinaryLoad(fp);break;case R_MAGIC_ASCII:ans = AsciiLoad(fp);break;case R_MAGIC_BINARY_VERSION16:ans = BinaryLoadOld(fp, 16);break;case R_MAGIC_ASCII_VERSION16:ans = AsciiLoadOld(fp, 16);break;default:fclose(fp);error("restore file corrupted -- no data loaded\n");}return ans;}/***************************************//* *//* Interpreter Interface Functions *//* *//***************************************/SEXP do_save(SEXP call, SEXP op, SEXP args, SEXP env){SEXP s, t;int len, j;FILE *fp;checkArity(op, args);if (TYPEOF(CAR(args)) != STRSXP)errorcall(call, "first argument must be a character vector\n");if (TYPEOF(CADR(args)) != STRSXP)errorcall(call, "second argument must be a string\n");if (TYPEOF(CADDR(args)) != LGLSXP)errorcall(call, "third argument must be a logical vector\n");fp = R_fopen(CHAR(STRING(CADR(args))[0]), "wb");if (!fp)errorcall(call, "unable to open file\n");len = length(CAR(args));PROTECT(s = allocList(len));t = s;for (j = 0; j < len; j++, t = CDR(t)) {TAG(t) = install(CHAR(STRING(CAR(args))[j]));CAR(t) = findVar(TAG(t), R_GlobalContext->sysparent);}R_SaveToFile(s, fp, INTEGER(CADDR(args))[0]);UNPROTECT(1);fclose(fp);return R_NilValue;}SEXP do_load(SEXP call, SEXP op, SEXP args, SEXP env){SEXP a, ans, e;int i;FILE *fp;checkArity(op, args);if (TYPEOF(CAR(args)) != STRSXP)errorcall(call, "first argument must be a string\n");i = INTEGER(CADR(args))[0];fp = R_fopen(CHAR(STRING(CAR(args))[0]), "rb");if (!fp)errorcall(call, "unable to open file\n");ans = R_LoadFromFile(fp);fclose(fp);/* store the components of the list in the Global Env */a = ans;while(a != R_NilValue) {for(e=FRAME(R_GlobalEnv) ; e!=R_NilValue ; e=CDR(e)) {if(TAG(e) == TAG(a)) {CAR(e) = CAR(a);a = CDR(a);goto NextItem;}}e = a;a = CDR(a);CDR(e) = FRAME(R_GlobalEnv);FRAME(R_GlobalEnv) = e;NextItem:;}return R_NilValue;}