<> <> <> <<>> <> <<>> 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 CHAR _ ALL[0C]; <> StabilizeToFiles: PUBLIC PROC [transID: YggEnvironment.TransID, did: YggDID.DID, document: YggRep.VDoc, contents, attributes, links: YggFile.FileHandle] ~ { <> writeAttribute: PROC [attribute: YggRep.Attribute] = { <> writeBits: PROC [tpe: YggRep.TypedPrimitiveElement] = { <> 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: BOOL _ TRUE; singletonFieldValues: BOOL _ TRUE; 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: BOOL _ TRUE; attributesStream: IO.STREAM _ NIL; 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.STREAM _ NIL; rRope: ROPE; rRope _ NARROW[document.contents.bits]; contentsStream _ YggFile.StreamFromOpenFile[contents]; IO.PutRope[contentsStream, rRope]; setContentsAsAttribute _ FALSE; }; ENDCASE => { contentsStream: IO.STREAM _ NIL; 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.