/* xlimage - xlisp memory image save/restore functions */
/* Copyright (c) 1989, by David Michael Betz. */
/* You may give out copies of this software; for conditions see the file */
/* COPYING included with this distribution. */
/* modified so that offset is in sizeof(node) units */
#include "xlisp.h"
#ifdef XLISP_STAT
#include "xlstat.h"
#include "version.h"
#endif /* XLISP_STAT */
#ifdef SAVERESTORE
#ifdef NEWGC
#define NUM_OFFSETS 6
#else
#define NUM_OFFSETS 0
#endif /* NEWGC */
#define FILENIL ((OFFTYPE)0) /* value of NIL in a file */
/* external variables from xldmem.c */
extern struct segment *segs,*lastseg,*fixseg,*charseg;
extern int anodes,nsegs;
extern long nnodes;
#ifdef NEWGC
extern struct segment *lastpermseg;
#else
extern LVAL fnodes;
#endif /* NEWGC */
/* local variables */
static OFFTYPE off,foff;
static FILEP fp;
/* forward declarations */
LOCAL OFFTYPE readptr(V);
LOCAL OFFTYPE cvoptr P1H(LVAL);
LOCAL LVAL cviptr P1H(OFFTYPE);
LOCAL VOID freeimage(V);
LOCAL VOID setoffset(V);
LOCAL VOID writenode P1H(LVAL);
LOCAL VOID writeptr P1H(OFFTYPE);
LOCAL VOID readnode P2H(int, LVAL);
/* macro to convert between size in bytes and vector size */
#define btow_size(n) (((unsigned)(n)+(sizeof(LVAL)-1))/(unsigned)sizeof(LVAL))
/* xlisave - save the memory image */
int xlisave P1C(char *, fname)
{
SEGMENT *seg;
int n,i,max;
LVAL p;
#ifndef MACINTOSH
char fullname[STRMAX+1];
/* default the extension */
if (needsextension(fname)) {
strcpy(fullname,fname);
strcat(fullname,".wks");
fname = fullname;
}
#endif /* MACINTOSH */
/* open the output file */
if ((fp = OSBOPEN(fname,CREATE_WR)) == CLOSED)
return (FALSE);
disable_interrupts();
/* first call the garbage collector to clean up memory */
gc();
#ifdef NEWGC
sweep_free_nodes();
#endif /* NEWGC */
#ifdef XLISP_STAT
/* write out file type and version numbers as a validity check */
OSWRITE("X1Ws",1,4,fp);
writeptr((OFFTYPE) XLS_MAJOR_RELEASE);
writeptr((OFFTYPE) XLS_MINOR_RELEASE);
writeptr((OFFTYPE) XLS_SUBMINOR_RELEASE);
#ifdef _Windows
#ifdef WIN32
writeptr((OFFTYPE) TRUE);
#else
writeptr((OFFTYPE) FALSE);
#endif /* WIN32 */
#endif /* _Windows */
#else
/* write out size of ftab (used as validity check) TAA MOD */
writeptr((OFFTYPE)ftabsize);
#endif /* XLISP_STAT */
/* write out the pointer to the unbound marker TAA MOD 1/93 */
writeptr(cvoptr(s_unbound));
/* write out the pointer to the *obarray* symbol */
writeptr(cvoptr(obarray));
/* write out components of NIL other than value, which must be NIL */
writeptr(cvoptr(getfunction(NIL)));
writeptr(cvoptr(getplist(NIL)));
writeptr(cvoptr(getpname(NIL)));
#ifdef PACKAGES
writeptr(cvoptr(getpackage(NIL)));
#endif
/* write out the weak box list head */
writeptr(cvoptr(xlweakboxes));
/* setup the initial file offsets */
off = foff = (OFFTYPE)2;
/* write out all nodes that are still in use */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
p = &seg->sg_nodes[0] + NUM_OFFSETS;
for (n = seg->sg_size - NUM_OFFSETS; --n >= 0; ++p, off++)
switch (ntype(p)) {
case FREE:
break;
#ifdef BIGNUMS
case RATIO:
#endif
case COMPLEX:
case CONS:
case USTREAM:
case RNDSTATE:
#ifdef BYTECODE
case BCCLOSURE:
#endif /* BYTECODE */
case DARRAY:
case NATPTR:
case WEAKBOX:
setoffset();
OSPUTC(ntype(p),fp);
if (ntype(p) != NATPTR)
writeptr(cvoptr(car(p)));
writeptr(cvoptr(cdr(p)));
#ifdef NEWGC
OSPUTC(p->n_flags,fp);
#endif /* NEWGC */
foff++;
break;
default:
setoffset();
writenode(p);
break;
}
}
/* write the terminator */
OSPUTC(FREE,fp);
writeptr((OFFTYPE)0);
/* write out data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
p = &seg->sg_nodes[0] + NUM_OFFSETS;
for (n = seg->sg_size - NUM_OFFSETS; --n >= 0; ++p)
switch (ntype(p)) {
/* $putpatch.c$: "MODULE_XLIMAGE_C_XLISAVE" */
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
#ifdef BYTECODE
case CPSNODE:
case BCODE:
#endif /* BYTECODE */
#ifdef PACKAGES
case PACKAGE:
#endif /* PACKAGES */
max = getsize(p);
for (i = 0; i < max; ++i)
writeptr(cvoptr(getelement(p,i)));
break;
#ifdef BIGNUMS
case BIGNUM:
max = (getbignumsize(p)+1)*sizeof(BIGNUMDATA);
OSWRITE(getbignumarray(p),1,max,fp);
break;
#endif
case STRING:
case TVEC:
max = getslength(p)+1;
OSWRITE(getstring(p),1,max,fp);
break;
#ifdef XLISP_STAT
case ADATA:
max = getadsize(p);
OSWRITE(getadaddr(p),1,max,fp);
break;
#endif /* XLISP_STAT */
#ifdef FILETABLE
case STREAM:
if (getfile(p) > CONSOLE ) {
long offset;
strcpy(buf, filetab[getfile(p)].tname);
OSWRITE(buf,1,FNAMEMAX,fp);
offset = OSTELL(getfile(p));
OSWRITE(&offset,1,sizeof(long),fp);
}
break;
#endif
}
}
/* close the output file */
OSCLOSE(fp);
#ifdef MACINTOSH
fsetfileinfo (fname, 'X1St', 'X1Ws');
#endif /* MACINTOSH */
enable_interrupts();
/* return successfully */
return (TRUE);
}
/* xlirestore - restore a saved memory image */
int xlirestore P1C(char *, fname)
{
int n,i,max,type,size;
SEGMENT *seg;
LVAL p;
#ifndef MACINTOSH
char fullname[STRMAX+1];
/* default the extension */
if (needsextension(fname)) {
strncpy(fullname,fname,STRMAX-4);
strcat(fullname,".wks");
fname = fullname;
}
#endif /* MACINTOSH */
/* open the file */
#ifdef PATHNAMES
if ((fp = ospopen(fname,FALSE)) == CLOSED)
#else
if ((fp = OSBOPEN(fname,OPEN_RO)) == CLOSED)
#endif
return (FALSE);
#ifdef XLISP_STAT
/* Check for file and version validity */
if (OSREAD(buf, 1, 4, fp) != 4 || strncmp(buf, "X1Ws", 4) != 0)
xlfatal("bad image file");
if (readptr() != (OFFTYPE) XLS_MAJOR_RELEASE ||
readptr() != (OFFTYPE) XLS_MINOR_RELEASE ||
readptr() != (OFFTYPE) XLS_SUBMINOR_RELEASE)
xlfatal("image file version does not match system version");
#ifdef _Windows
#ifdef WIN32
if (readptr() != (OFFTYPE) TRUE)
xlfatal("not a Win32 image file");
#else
if (readptr() != (OFFTYPE) FALSE)
xlfatal("not a Win16 image file");
#endif /* WIN32 */
#endif /* _Windows */
#else
/* Check for file validity TAA MOD */
if (readptr() != (OFFTYPE) ftabsize) {
OSCLOSE(fp); /* close it -- we failed */
return (FALSE);
}
#endif /* XLISP_STAT */
disable_interrupts();
/* free the old memory image */
freeimage();
/* initialize */
off = (OFFTYPE)2;
total = nnodes = nfree = 0L;
#ifndef NEWGC
fnodes = NIL;
#endif /* NEWGC */
segs = lastseg = NULL;
nsegs = gccalls = 0;
#ifdef BIGNUMS
n_bigzero=n_bigmone=NULL; /* TAA fix 3/13/96 -- added */
#endif
xlenv = xlfenv = xldenv = s_gchook = s_gcflag = NIL;
xlstack = xlstkbase + EDEPTH;
xlfp = xlsp = xlargstkbase;
*xlsp++ = NIL;
xlcontext = NULL;
#ifdef MULVALS /* TAA BUG FIX 01/94 */
xlnumresults = 0;
#endif
/* create the fixnum segment */
if ((fixseg = newsegment(SFIXSIZE)) == NULL)
xlfatal("insufficient memory - fixnum segment");
/* create the character segment */
if ((charseg = newsegment(CHARSIZE)) == NULL)
xlfatal("insufficient memory - character segment");
#ifdef NEWGC
/* set pointer to last permanent segment */
lastpermseg = lastseg;
#endif /* NEWGC */
/* read in the pointer to the unbound marker TAA MOD 1/93 */
s_unbound = cviptr(readptr());
/* read the pointer to the *obarray* symbol */
obarray = cviptr(readptr());
/* read components of NIL other than value, which must be NIL */
setvalue(NIL, NIL);
setfunction(NIL, cviptr(readptr()));
setplist(NIL, cviptr(readptr()));
setpname(NIL, cviptr(readptr()));
#ifdef PACKAGES
setpackage(NIL, cviptr(readptr()));
#endif
/* read in the weak box list head */
xlweakboxes = cviptr(readptr());
/* read each node */
while ((type = OSGETC(fp)) >= 0) {
switch (type) {
case FREE:
if ((off = readptr()) == (OFFTYPE)0)
goto done;
break;
#ifdef BIGNUMS
case RATIO:
#endif
case COMPLEX:
case CONS:
case USTREAM:
case RNDSTATE:
#ifdef BYTECODE
case BCCLOSURE:
#endif /* BYTECODE */
case DARRAY:
case NATPTR:
case WEAKBOX:
p = cviptr(off);
setntype(p, type);
rplaca(p,type==NATPTR ? NULL : cviptr(readptr()));
rplacd(p,cviptr(readptr()));
#ifdef NEWGC
p->n_flags = OSGETC(fp);
initialize_node(p);
#endif /* NEWGC */
off++;
break;
default:
readnode(type,cviptr(off));
off++;
break;
}
}
done:
/* read the data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
p = &seg->sg_nodes[0] + NUM_OFFSETS;
for (n = seg->sg_size - NUM_OFFSETS; --n >= 0; ++p)
switch (ntype(p)) {
/* $putpatch.c$: "MODULE_XLIMAGE_C_XLIRESTORE" */
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
#ifdef BYTECODE
case CPSNODE:
case BCODE:
#endif /* BYTECODE */
#ifdef PACKAGES
case PACKAGE:
#endif /* PACKAGES */
max = getsize(p);
if (max != 0 && (p->n_vdata = (LVAL *)VALLOC(max)) == NULL)
xlfatal("insufficient memory - vector");
total += (long)(max * sizeof(LVAL));
for (i = 0; i < max; ++i)
setelement(p,i,cviptr(readptr()));
break;
case STRING:
case TVEC:
max = getslength(p) + 1;
size = btow_size(max);
if ((p->n_string = (char *)VALLOC(size)) == NULL)
xlfatal("insufficient memory - string");
total += (long)max;
if (OSREAD(getstring(p),1,max,fp) != max)
xlfatal("image file corrupted");
break;
#ifdef XLISP_STAT
case ADATA:
max = getadsize(p);
p->n_adaddr = (getadreloc(p)) ? StRCalloc(1, max)
: StCalloc(1, max);
if (p->n_adaddr == NULL)
xlfatal("insufficient memory - string");
total += (long)max;
if (OSREAD(getadaddr(p),1,max,fp) != max)
xlfatal("image file corrupted");
break;
#endif /* XLISP_STAT */
#ifdef BIGNUMS
case BIGNUM:
max = (getbignumsize(p) + 1) * sizeof(BIGNUMDATA);
size = btow_size(max);
if ((p->n_string = (char *)VALLOC(size)) == NULL)
xlfatal("insufficient memory - bignum");
total += (long)max;
if (OSREAD(getbignumarray(p),1,max,fp)!=max)
xlfatal("image file corrupted");
break;
#endif
case STREAM:
#ifdef FILETABLE
if (getfile(p) > CONSOLE) { /* actual file to modify */
unsigned long fpos;
FILEP f;
if (OSREAD(buf, 1, FNAMEMAX, fp) != FNAMEMAX ||
OSREAD(&fpos, 1, sizeof(long), fp) != sizeof(long))
xlfatal("image file corrupted");
/* open file in same type, file must exist to succeed */
f = ((p->n_sflags & S_BINARY)? OSBOPEN : OSAOPEN)
(buf, (p->n_sflags&S_FORWRITING)? OPEN_UPDATE: OPEN_RO);
setfile(p, f);
if (f != CLOSED) {/* position to same point,
or end if file too short */
OSSEEKEND(f);
if (OSTELL(f) > fpos) OSSEEK(f, fpos);
}
}
break;
#else
setfile(p, CLOSED);
break;
#endif
case SUBR:
case FSUBR:
p->n_subr = funtab[getoffset(p)].fd_subr;
break;
}
}
/* close the input file */
OSCLOSE(fp);
/* collect to initialize the free space */
gc();
/* lookup all of the symbols the interpreter uses */
xlsymbols();
enable_interrupts();
/* return successfully */
return (TRUE);
}
/* freeimage - free the current memory image */
LOCAL VOID freeimage(V)
{
SEGMENT *seg,*next;
FILEP fp;
LVAL p;
int n;
/* free the data portion of SYMBOL/VECTOR/OBJECT/STRING nodes */
for (seg = segs; seg != NULL; seg = next) {
p = &seg->sg_nodes[0] + NUM_OFFSETS;
for (n = seg->sg_size - NUM_OFFSETS; --n >= 0; ++p)
switch (ntype(p)) {
/* $putpatch.c$: "MODULE_XLIMAGE_C_FREEIMAGE" */
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
#ifdef BYTECODE
case CPSNODE:
case BCODE:
#endif /* BYTECODE */
#ifdef PACKAGES
case PACKAGE:
#endif /* PACKAGES */
if (p->n_vsize)
VRELEASE((ALLOCTYPE *)p->n_vdata, p->n_vsize);
break;
case STRING:
case TVEC:
if (getstring(p)!=NULL)
VRELEASE(getstring(p),btow_size(getslength(p) + 1));
break;
#ifdef BIGNUMS
case BIGNUM:
if (getbignumarray(p)!=NULL)
VRELEASE(getbignumarray(p),
btow_size((getbignumsize(p)+1)*sizeof(BIGNUMDATA)));
break;
#endif
#ifdef XLISP_STAT
case ADATA:
if (getadaddr(p) != NULL)
if (getadreloc(p)) StRFree(getadaddr(p));
else StFree(getadaddr(p));
break;
#endif /* XLISP_STAT */
case STREAM:
if (((fp = getfile(p)) != CLOSED) &&
(fp != STDIN && fp != STDOUT && fp != CONSOLE)) /* TAA BUG FIX */
OSCLOSE(fp);
break;
}
next = seg->sg_next;
MFREE(seg);
}
}
/* setoffset - output a positioning command if nodes have been skipped */
LOCAL VOID setoffset(V)
{
if (off != foff) {
OSPUTC(FREE,fp);
writeptr(off);
foff = off;
}
}
/* writenode - write a node to a file */
LOCAL VOID writenode P1C(LVAL, node)
{
OSPUTC(ntype(node),fp);
OSWRITE(&node->n_info, sizeof(union ninfo), 1, fp);
#ifdef NEWGC
OSPUTC(node->n_flags,fp);
#else
#ifdef MULVALS
OSPUTC(node->n_flags,fp);
#else
if (ntype(node) == SYMBOL) OSPUTC(node->n_flags,fp);
#endif /* MULVALS */
#endif /* NEWGC */
foff++;
}
/* writeptr - write a pointer to a file */
LOCAL VOID writeptr P1C(OFFTYPE, off)
{
OSWRITE(&off, sizeof(OFFTYPE), 1, fp);
}
/* readnode - read a node */
LOCAL VOID readnode P2C(int, type, LVAL, node)
{
setntype(node, type);
if (OSREAD(&node->n_info, sizeof(union ninfo), 1, fp) != 1)
xlfatal("image file corrupted");
#ifdef NEWGC
node->n_flags = OSGETC(fp);
initialize_node(node);
#else
#ifdef MULVALS
node->n_flags = OSGETC(fp);
#else
if (type == SYMBOL) node->n_flags = OSGETC(fp);
#endif /* MULVALS */
#endif /* NEWGC */
#ifdef HASHFCNS
/* to get hash tables rehashed */
if (type == STRUCT) setnuflags(node, TRUE);
#endif /* HASHFCNS */
}
/* readptr - read a pointer */
LOCAL OFFTYPE readptr(V)
{
OFFTYPE off;
if (OSREAD(&off, sizeof(OFFTYPE), 1, fp) != 1)
xlfatal("image file corrupted");
return (off);
}
/* cviptr - convert a pointer on input */
LOCAL LVAL cviptr P1C(OFFTYPE, o)
{
OFFTYPE off = (OFFTYPE)2;
SEGMENT *seg;
/* check for nil */
if (o == FILENIL)
return (NIL);
/* compute a pointer for this offset */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
if (o < off + (OFFTYPE)seg->sg_size - NUM_OFFSETS)
return (seg->sg_nodes + NUM_OFFSETS + (unsigned int)(o - off));
off += (OFFTYPE)seg->sg_size - NUM_OFFSETS;
}
/* create new segments if necessary */
for (;;) {
/* create the next segment */
if ((seg = newsegment(anodes)) == NULL)
xlfatal("insufficient memory - segment");
/* check to see if the offset is in this segment */
if (o < off + (OFFTYPE)seg->sg_size - NUM_OFFSETS)
return (seg->sg_nodes + NUM_OFFSETS + (unsigned int)(o - off));
off += (OFFTYPE)seg->sg_size - NUM_OFFSETS;
}
}
/* cvoptr - convert a pointer on output */
LOCAL OFFTYPE cvoptr P1C(LVAL, p)
{
OFFTYPE off = (OFFTYPE)2;
SEGMENT *seg;
OFFTYPE np = CVPTR(p);
/* check for nil */
if (null(p))
return (FILENIL);
/* compute an offset for this pointer */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
if (np >= CVPTR(&seg->sg_nodes[NUM_OFFSETS]) &&
np < CVPTR(&seg->sg_nodes[seg->sg_size]))
return (off + (p-(seg->sg_nodes+NUM_OFFSETS)));
off += (OFFTYPE)seg->sg_size - NUM_OFFSETS;
}
/* pointer not within any segment */
xlerror("bad pointer found during image save",p);
return (0); /* fake out compiler warning */
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1