YggStabilizeImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Bob Hagmann May 26, 1988 3:25:49 pm PDT
Take a volatile form of a document, and write it onto some files.
DIRECTORY
Basics USING [charsPerWord, RawBytes, UnsafeBlock],
IO USING [PutChar, PutRope, STREAM, UnsafePutBlock],
Rope USING [Length, ROPE],
YggDID USING [DID],
YggFile USING [FileHandle, StreamFromOpenFile],
YggRep USING [AccurateGMT, AccurateGMTRep, AccurateGMTRepByteSize, Attribute, AttributePreamble, AttributeValue, BitsRep, date, DocType, float, int, rope, shortRope, TypedPrimitiveElement, unknown, uninterpretedBytes, VDoc],
YggEnvironment USING [TransID],
YggVolatileObjectCache USING [InvalidateDID, ReserveDIDInCache];
YggStabilizeImpl: CEDAR PROGRAM
IMPORTS IO, Rope, YggFile, YggVolatileObjectCache
EXPORTS YggRep
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
AllNulls: PACKED ARRAY [0..Basics.charsPerWord) OF CHARALL[0C];
Exported conversion procedures
StabilizeToFiles: PUBLIC PROC [transID: YggEnvironment.TransID, did: YggDID.DID, document: YggRep.VDoc, contents, attributes, links: YggFile.FileHandle] ~ {
Given a document, write it out to the files.
writeAttribute: PROC [attribute: YggRep.Attribute] = {
Given an attribute, write it out to the stream. See YggRep.mesa for a description of what the format is.
writeBits: PROC [tpe: YggRep.TypedPrimitiveElement] = {
Write the contents of a TypedPrimitiveElement. The type has already been writen.
SELECT tpe.docType FROM
YggRep.unknown => ERROR;
YggRep.int => {
ri: REF INT32;
ri ← NARROW[tpe.bits];
writeInt[ri^];
};
YggRep.shortRope => {
rRope: ROPE;
rRope ← NARROW[tpe.bits];
writeString[rRope, 0];
};
YggRep.rope => {
len: INT;
rRope: ROPE;
rRope ← NARROW[tpe.bits];
len ← Rope.Length[rRope];
writeInt[len];
writeString[rRope, 0];
};
YggRep.float => {
rReal: REF REAL32;
rReal ← NARROW[tpe.bits];
TRUSTED {
ptReal: POINTER TO REAL32;
ptReal ← LOOPHOLE[rReal];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptReal], 0, Basics.charsPerWord]];
};
};
YggRep.date => {
rAccurateGMT: YggRep.AccurateGMT;
rAccurateGMT ← NARROW[tpe.bits];
TRUSTED {
ptAGMT: POINTER TO YggRep.AccurateGMTRep;
ptAGMT ← LOOPHOLE[rAccurateGMT];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptAGMT], 0, YggRep.AccurateGMTRepByteSize]];
};
};
ENDCASE => {
nullsToWrite: INT;
rBits: REF YggRep.BitsRep;
rBits ← NARROW[tpe.bits];
writeInt[rBits.length];
TRUSTED {
ptBits: POINTER TO YggRep.BitsRep;
ptBits ← LOOPHOLE[rBits];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptBits, POINTER TO Basics.RawBytes] + SIZE[YggRep.BitsRep[0]], 0, rBits.length]];
};
nullsToWrite ← Basics.charsPerWord - (rBits.length) MOD Basics.charsPerWord;
IF nullsToWrite > 0 THEN TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[@AllNulls], 0 , nullsToWrite]];};
};
};
writeString: PROC [string: ROPE, extraChars: INT] = {
len: INT;
nullsToWrite: INT;
len ← Rope.Length[string];
IF len > 0 THEN IO.PutRope[attributesStream, string];
nullsToWrite ← Basics.charsPerWord - (len+extraChars) MOD Basics.charsPerWord;
TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[@AllNulls], 0 , nullsToWrite]];};
};
writeInt: PROC [int: INT] = {
TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[@int], 0, Basics.charsPerWord]];};
};
nullFieldNames: BOOLTRUE;
singletonFieldValues: BOOLTRUE;
numberOfAttributeValues: INT ← 0;
primitiveType: YggRep.DocType ← YggRep.unknown;
preample: YggRep.AttributePreamble;
FOR rv: LIST OF YggRep.AttributeValue ← attribute.value, rv.rest UNTIL rv = NIL DO
numberOfAttributeValues ← numberOfAttributeValues + 1;
IF rv.first.fieldName # NIL THEN nullFieldNames ← FALSE;
IF rv.first.valueSet.rest # NIL THEN singletonFieldValues ← FALSE;
FOR avl: LIST OF YggRep.TypedPrimitiveElement ← rv.first.valueSet, avl.rest UNTIL avl = NIL DO
tpe: YggRep.TypedPrimitiveElement = avl.first;
IF tpe.docType < YggRep.date AND (primitiveType = YggRep.unknown OR primitiveType = tpe.docType) THEN primitiveType ← tpe.docType ELSE primitiveType ← 10000;
ENDLOOP;
ENDLOOP;
preample[0].ordered ← attribute.ordered;
preample[0].noFieldNames ← ~nullFieldNames;
preample[0].singletonAttribute ← (numberOfAttributeValues = 1);
preample[0].singletonField ← singletonFieldValues;
preample[0].typeCode ← SELECT primitiveType FROM
YggRep.int => integer,
YggRep.rope => ropeLarge,
YggRep.shortRope => ropeShort,
YggRep.float => float,
YggRep.date => date,
YggRep.uninterpretedBytes => uninterpretedBytes,
ENDCASE => separate;
IF numberOfAttributeValues <= 0 THEN RETURN;
writeInt[document.contents.docType];
TRUSTED {IO.PutChar[attributesStream, LOOPHOLE[@preample]];}; -- @preample points to preample[0]
writeString[attribute.attributeName, 1]; -- write attribute name
IF numberOfAttributeValues # 1 THEN writeInt[numberOfAttributeValues]; -- write number of attribute values;
FOR rv: LIST OF YggRep.AttributeValue ← attribute.value, rv.rest UNTIL rv = NIL DO
IF ~nullFieldNames THEN writeString[rv.first.fieldName, 0]; -- write field name
FOR avl: LIST OF YggRep.TypedPrimitiveElement ← rv.first.valueSet, avl.rest UNTIL avl = NIL DO
tpe: YggRep.TypedPrimitiveElement = avl.first;
IF preample[0].typeCode = separate THEN writeInt[tpe.docType];
writeBits[tpe];
ENDLOOP;
IF ~preample[0].singletonField THEN writeInt[YggRep.unknown];
ENDLOOP;
};
setContentsAsAttribute: BOOLTRUE;
attributesStream: IO.STREAMNIL;
YggVolatileObjectCache.ReserveDIDInCache[did];
IF contents # NIL THEN {
SELECT document.contents.docType FROM
YggRep.unknown => ERROR;
YggRep.int, YggRep.shortRope, YggRep.float, YggRep.date => {};
YggRep.rope => {
contentsStream: IO.STREAMNIL;
rRope: ROPE;
rRope ← NARROW[document.contents.bits];
contentsStream ← YggFile.StreamFromOpenFile[contents];
IO.PutRope[contentsStream, rRope];
setContentsAsAttribute ← FALSE;
};
ENDCASE => {
contentsStream: IO.STREAMNIL;
rBits: REF YggRep.BitsRep;
rBits ← NARROW[document.contents.bits];
IF rBits.length > 1024 THEN {
contentsStream ← YggFile.StreamFromOpenFile[contents];
TRUSTED {
ptBits: POINTER TO YggRep.BitsRep;
unsafeBlock: Basics.UnsafeBlock;
ptBits ← LOOPHOLE[rBits];
unsafeBlock ← [LOOPHOLE[ptBits, POINTER TO Basics.RawBytes] + SIZE[YggRep.BitsRep[0]], 0, rBits.length];
IO.UnsafePutBlock [self: contentsStream, block: unsafeBlock];
};
setContentsAsAttribute ← FALSE;
};
};
};
attributesStream ← YggFile.StreamFromOpenFile[attributes];
FOR restOfAttributes: LIST OF YggRep.Attribute ← document.attributes, restOfAttributes.rest UNTIL restOfAttributes = NIL DO
writeAttribute[restOfAttributes.first];
ENDLOOP;
IF setContentsAsAttribute THEN writeAttribute[["$contents", FALSE, LIST[[NIL, LIST[document.contents]]]]];
YggVolatileObjectCache.InvalidateDID[did];
};
END.