DIRECTORY Atom USING [GetPName], CedarProcess USING [Priority, DoWithPriority], FS USING [Create, OpenFile, StreamFromOpenFile], IO USING [Close, Error, GetIndex, noWhereStream, PutChar, PutRope, RopeFromROS, ROS, SetIndex, SetLength, STREAM], PGSupport, Rope USING [Balance, Fetch, Flatten, ROPE, Size, SkipTo], RopeEdit USING [BlankChar], RopeReader USING [FreeRopeReader, GetRopeReader, Ref], RunReader USING [FreeRunReader, GetRunReader, MergedGet, Ref, SetPosition], TextLooks USING [CountRuns, Flatten, Look, Looks, LooksBytes, noLooks, Runs], Tioga USING [FirstChild, Forward, GetFormat, IsLastSibling, MapProps, Next, Node, Parent, Size, WriteProp], TiogaFile USING [comment, commentHeaderId, controlHeaderId, controlTrailerId, endNode, endOfFile, endSize, FileId, fileIdSize, FormatIndex, look1, look2, look3, looks, looksFirst, LooksIndex, prop, PropIndex, propShort, rope, runs, startNode, startNodeFirst, terminalTextNode, terminalTextNodeFirst, trailerLengthSize], UserProfile USING [Number]; PutFileImpl: CEDAR PROGRAM IMPORTS Atom, CedarProcess, FS, IO, PGSupport, Rope, RopeEdit, RopeReader, RunReader, TextLooks, Tioga, UserProfile EXPORTS Tioga = BEGIN ROPE: TYPE = Rope.ROPE; Runs: TYPE = TextLooks.Runs; Node: TYPE = Tioga.Node; SimpleDoc: PROC [root: Node] RETURNS [simple: BOOL _ FALSE, rope: ROPE _ NIL] = { HasInterestingProp: PROC [node: Node] RETURNS [BOOL] = { interestingProp: PROC [name: ATOM, value: REF] RETURNS [BOOL] = { RETURN [SELECT name FROM $Viewer, $LockedViewer, $FromTiogaFile, $DocumentLock, $FileCreateDate, $FileExtension => FALSE, ENDCASE => TRUE]; }; RETURN [Tioga.MapProps[node, interestingProp, FALSE, FALSE]]; }; NoLooks: PROC [node: Node] RETURNS [BOOL] = { RETURN[TextLooks.CountRuns[runs: node.runs, start: 0, len: Tioga.Size[node], merge: TRUE, firstLooks: TextLooks.noLooks].count=0]; }; SimpleNode: PROC [node: Node] RETURNS [simple: BOOL _ FALSE, rope: ROPE _ NIL] = { IF (node.formatName=NIL) AND (NOT node.comment) AND (NOT HasInterestingProp[node]) AND (node.runs=NIL OR NoLooks[node]) THEN RETURN [TRUE, node.rope]; }; IF root=NIL THEN RETURN [TRUE, NIL]; [simple, rope] _ SimpleNode[root]; IF NOT simple THEN RETURN; -- not a simple root node IF root.child=NIL THEN RETURN; -- simple root and no child IF rope#NIL THEN RETURN [FALSE, NIL]; -- root has child and text, so not simple IF root.child.last AND root.child.child=NIL THEN [simple, rope] _ SimpleNode[root.child] ELSE RETURN [FALSE, NIL]; -- more than one child, so not simple }; PutDoc: PROC [data, comment, control: IO.STREAM, root: Node, flatten: BOOL] = { WriteControlChar: PROC [c: CHAR] ~ { IO.PutChar[control, c] }; WriteLen: PROC [len: INT] ~ INLINE { PGSupport.PutLength[WriteControlChar, len] }; WriteControlRope: PROC [r: ROPE] ~ { WriteLen[Rope.Size[r]]; IO.PutRope[control, r]; }; WriteRope: PROC [r: ROPE, stream: IO.STREAM] = { WriteLen[Rope.Size[r]]; IO.PutRope[stream, r]; IO.PutChar[stream, 15C]; }; CountLookBits: PROC [lks: TextLooks.Looks] RETURNS [cnt: NAT _ 0] = { FOR c: TextLooks.Look IN TextLooks.Look DO IF lks[c] THEN cnt _ cnt+1; ENDLOOP; }; WriteLookChars: PROC [lks: TextLooks.Looks] = { FOR c: TextLooks.Look IN TextLooks.Look DO IF lks[c] THEN WriteControlChar[c]; ENDLOOP; }; WriteLookBits: PROC [lks: TextLooks.Looks] = { bytes: TextLooks.LooksBytes ~ LOOPHOLE[lks]; WriteControlChar[LOOPHOLE[bytes.byte0]]; WriteControlChar[LOOPHOLE[bytes.byte1]]; WriteControlChar[LOOPHOLE[bytes.byte2]]; WriteControlChar[LOOPHOLE[bytes.byte3]]; }; pgf: PGSupport.PGF ~ PGSupport.CreatePGF[]; runReader: RunReader.Ref ~ RunReader.GetRunReader[]; ropeReader: RopeReader.Ref ~ RopeReader.GetRopeReader[]; node: Node _ root; DO child: Node ~ Tioga.FirstChild[node]; terminal: BOOL ~ (child=NIL); { -- write format formatName: ATOM ~ Tioga.GetFormat[node]; ok: BOOL; formatindex: TiogaFile.FormatIndex; [ok, formatindex] _ PGSupport.EnterFormatName[formatName, pgf]; IF ok THEN { WriteControlChar[(IF terminal THEN TiogaFile.terminalTextNodeFirst ELSE TiogaFile.startNodeFirst)+formatindex]; } ELSE { WriteControlChar[IF terminal THEN TiogaFile.terminalTextNode ELSE TiogaFile.startNode]; WriteControlRope[IF formatName=NIL THEN NIL ELSE Atom.GetPName[formatName]]; }; }; { -- write node props writeProp: PROC [name: ATOM, value: REF] RETURNS [quit: BOOL _ FALSE] = { specs: ROPE ~ Tioga.WriteProp[name, value]; -- write specs as a rope IF specs#NIL THEN { ok: BOOL; propindex: TiogaFile.PropIndex; [ok, propindex] _ PGSupport.EnterProp[name, pgf]; IF ok THEN { -- can use short form WriteControlChar[TiogaFile.propShort]; WriteControlChar[VAL[propindex]]; } ELSE { -- must write full prop name WriteControlChar[TiogaFile.prop]; WriteControlRope[Atom.GetPName[name]]; }; WriteControlRope[specs]; }; }; IF node.props#NIL THEN [] _ Tioga.MapProps[node, writeProp, FALSE, FALSE]; }; { -- now write contents size: INT ~ Tioga.Size[node]; rope: ROPE ~ node.rope; runs: TextLooks.Runs ~ node.runs; IF flatten THEN { -- flatten rope and runs node.rope _ Rope.Balance[rope]; node.runs _ TextLooks.Flatten[runs]; }; IF runs#NIL THEN { -- write looks, if any loc, numRuns: INT _ 0; [numRuns, , ] _ TextLooks.CountRuns[runs, 0, size]; WriteControlChar[TiogaFile.runs]; WriteLen[numRuns]; RunReader.SetPosition[runReader, runs, 0]; THROUGH [0..numRuns) DO len: INT; looks: TextLooks.Looks; ok: BOOL; looksindex: TiogaFile.LooksIndex; [len, looks] _ RunReader.MergedGet[runReader]; [ok, looksindex] _ PGSupport.EnterLooks[looks, pgf]; IF ok THEN WriteControlChar[TiogaFile.looksFirst+looksindex] ELSE { -- must write out the looks SELECT CountLookBits[looks] FROM 1 => { WriteControlChar[TiogaFile.look1]; WriteLookChars[looks] }; 2 => { WriteControlChar[TiogaFile.look2]; WriteLookChars[looks] }; 3 => { WriteControlChar[TiogaFile.look3]; WriteLookChars[looks] }; ENDCASE => { WriteControlChar[TiogaFile.looks]; WriteLookBits[looks] }; }; WriteLen[len]; loc _ loc+len; ENDLOOP; IF loc#size THEN ERROR; }; IF node.comment THEN { -- put text in comment area of file WriteControlChar[TiogaFile.comment]; WriteRope[rope, comment]; } ELSE { -- put text in data area of file WriteControlChar[TiogaFile.rope]; WriteRope[rope, data]; }; }; IF NOT terminal THEN node _ child ELSE DO -- node has no children IF node=root THEN GOTO Finis; IF NOT Tioga.IsLastSibling[node] THEN { node _ Tioga.Next[node]; EXIT } ELSE { node _ Tioga.Parent[node]; WriteControlChar[TiogaFile.endNode] }; ENDLOOP; REPEAT Finis => { WriteControlChar[TiogaFile.endOfFile]; RunReader.FreeRunReader[runReader]; RopeReader.FreeRopeReader[ropeReader]; PGSupport.FreePGF[pgf] }; ENDLOOP; }; ToStream: PUBLIC PROC [stream: IO.STREAM, node: Node, flatten, textOnly: BOOL _ FALSE] RETURNS [dataLen, count: INT] = { simple: BOOL; rope: ROPE; [simple, rope] _ SimpleDoc[node]; IF simple THEN { IO.PutRope[stream, rope]; dataLen _ count _ Rope.Size[rope] } ELSE { dataStart: INT ~ IO.GetIndex[stream]; comment, control: IO.STREAM _ NIL; IF textOnly THEN comment _ control _ IO.noWhereStream ELSE { comment _ IO.ROS[]; control _ IO.ROS[] }; PutDoc[data: stream, comment: comment, control: control, root: node, flatten: flatten]; dataLen _ IO.GetIndex[stream]-dataStart; IF textOnly THEN count _ dataLen ELSE { PutChar: PROC [c: CHAR] ~ { IO.PutChar[stream, c] }; PutId: PROC [id: TiogaFile.FileId] ~ INLINE { PGSupport.PutFileId[PutChar, id] }; PutLen: PROC [len: INT] ~ INLINE { PGSupport.PutTrailerLength[PutChar, len] }; PutRope: PROC [rope: ROPE] ~ INLINE { IO.PutRope[stream, rope] }; commentRope: ROPE ~ IO.RopeFromROS[comment]; controlRope: ROPE ~ IO.RopeFromROS[control]; commentLen: INT ~ TiogaFile.fileIdSize+TiogaFile.trailerLengthSize+ Rope.Size[commentRope]; controlLen: INT ~ TiogaFile.fileIdSize+TiogaFile.trailerLengthSize+ Rope.Size[controlRope]+TiogaFile.endSize; count _ dataLen+commentLen+controlLen; PutId[TiogaFile.commentHeaderId]; PutLen[commentLen]; PutRope[commentRope]; PutId[TiogaFile.controlHeaderId]; PutLen[controlLen]; PutRope[controlRope]; PutId[TiogaFile.controlTrailerId]; PutLen[0]; PutLen[dataLen]; PutLen[count]; IF (IO.GetIndex[stream]-dataStart)#count THEN ERROR; }; }; }; ToRope: PUBLIC PROC [node: Node, flatten, textOnly: BOOL _ FALSE] RETURNS [dataLen, count: INT, output: ROPE] = { simple: BOOL; [simple, output] _ SimpleDoc[node]; IF simple THEN { dataLen _ count _ Rope.Size[output] } ELSE { stream: IO.STREAM ~ IO.ROS[]; [dataLen, count] _ ToStream[stream, node, flatten, textOnly]; output _ IO.RopeFromROS[stream]; }; }; CreateFile: PROC [fileName: ROPE] RETURNS [FS.OpenFile] ~ { keep: INT ~ UserProfile.Number["Tioga.defaultKeep", 2]; RETURN[FS.Create[name: fileName, keep: keep]]; }; ToFile: PUBLIC PROC [fileName: ROPE, node: Node, start: INT _ 0, flatten, textOnly: BOOL _ FALSE] RETURNS [dataLen, count: INT] = { createName: ROPE ~ fileName.Flatten[0, fileName.SkipTo[0, "!"]]; -- strip version, if any file: FS.OpenFile ~ CreateFile[createName]; [dataLen, count] _ ToFileC[file, node, start, flatten, textOnly]; }; ToFileC: PUBLIC PROC [file: FS.OpenFile, node: Node, start: INT _ 0, flatten, textOnly: BOOL _ FALSE] RETURNS [dataLen, count: INT] = { innerFileIt: PROC ~ { stream: IO.STREAM ~ FS.StreamFromOpenFile[file, $write]; IF start#0 THEN IO.SetIndex[stream, start]; [dataLen, count] _ ToStream[stream, node, flatten, textOnly]; }; CedarProcess.DoWithPriority[savePriority, innerFileIt]; }; savePriority: CedarProcess.Priority _ normal; WritePlain: PUBLIC PROC [h: IO.STREAM, root: Node, restoreDashes: BOOL _ FALSE] = { HasInitialDashes: PROC [r: ROPE] RETURNS [BOOL] = { loc: INT _ 0; size: INT = Rope.Size[r]; c: CHAR; WHILE loc < size AND RopeEdit.BlankChar[c _ Rope.Fetch[r, loc]] DO loc _ loc+1; ENDLOOP; IF loc > size-2 OR c # '- OR Rope.Fetch[r, loc+1] # '- THEN RETURN [FALSE]; RETURN [TRUE] }; node: Node _ root; level: INTEGER _ 0; levelDelta: INTEGER; first: BOOL _ TRUE; DO [node, levelDelta] _ Tioga.Forward[node]; IF node=NIL THEN EXIT; IF first THEN first _ FALSE ELSE IO.PutChar[h, '\n]; -- carriage returns between nodes level _ level+levelDelta; THROUGH [1..level) DO IO.PutChar[h, '\t]; ENDLOOP; -- output level-1 tabs IF restoreDashes AND node.comment AND NOT HasInitialDashes[node.rope] THEN IO.PutRope[h, "-- "]; -- restore the leading dashes for Mesa comments IO.PutRope[h, node.rope]; ENDLOOP; { ENABLE IO.Error => IF ec=NotImplementedForThisStream THEN CONTINUE; IO.SetLength[h, IO.GetIndex[h]] }; }; WriteFilePlain: PUBLIC PROC [fileName: ROPE, root: Node] = { h: IO.STREAM ~ FS.StreamFromOpenFile[CreateFile[fileName], $write]; WritePlain[h, root]; IO.Close[h]; }; WriteFileCPlain: PUBLIC PROC [file: FS.OpenFile, root: Node] = { h: IO.STREAM ~ FS.StreamFromOpenFile[file, $write]; WritePlain[h, root]; IO.Close[h]; }; WriteMesaFilePlain: PUBLIC PROC [fileName: ROPE, root: Node] = { h: IO.STREAM ~ FS.StreamFromOpenFile[CreateFile[fileName], $write]; WritePlain[h, root, TRUE]; IO.Close[h]; }; WriteRopePlain: PUBLIC PROC [root: Node, restoreDashes: BOOL _ FALSE] RETURNS [output: ROPE] = { h: IO.STREAM = IO.ROS[]; WritePlain[h, root, restoreDashes]; RETURN [IO.RopeFromROS[h]] }; END. ΎPutFileImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Michael Plass, October 31, 1985 10:52:43 am PST Rick Beach, March 27, 1985 1:04:56 pm PST Russ Atkinson (RRA) August 7, 1985 12:49:05 pm PDT Doug Wyatt, September 22, 1986 1:27:09 pm PDT When add a new "system" property that should not go on files, add registration at end of TEditDocuments2Impl so will not copy/write the property. move to the next node Κ u˜codešœ™Kšœ Οmœ7™BK™/K™)K™2Kšœ-™-K˜—šΟk ˜ Kšœžœ ˜Kšœ žœ˜/Kšžœžœ)˜1KšžœžœHžœžœ˜sKšœ ˜ Kšœžœžœ˜:Kšœ žœ˜Kšœ žœ'˜7Kšœ žœ=˜LKšœ žœ?˜NKšœžœ`˜kKšœ žœ°˜ΏKšœ žœ ˜—K˜KšΠbl œžœž˜KšžœžœžœQ˜sKšžœ˜ Kšœž˜K˜Kšžœžœžœ˜Kšœžœ˜Kšœžœ˜K˜šΟn œžœžœ žœžœžœžœ˜Qš œžœžœžœ˜8š œžœžœ žœžœžœ˜Ašžœžœž˜KšœZžœ˜aKšœ‘™‘Kšžœžœ˜—K˜—Kšžœ(žœžœ˜=K˜—š œžœžœžœ˜-KšžœNžœ*˜‚K˜—š  œžœžœ žœžœžœžœ˜RKšžœžœžœžœžœžœžœ žœžœžœžœžœ ˜–K˜—Kš žœžœžœžœžœžœ˜$K˜"Kš žœžœžœžœΟc˜4Kš žœ žœžœžœ‘˜:Kš žœžœžœžœžœžœ‘)˜OKšžœžœžœžœ(˜XKš žœžœžœžœ‘%˜?K˜K˜—š  œžœžœžœžœ˜OKš œžœžœžœ˜>Kš œžœžœžœ0˜Rš œžœžœ˜$Kšœ˜Kšžœ˜Kšœ˜—š   œžœžœ žœžœ˜0Kšœ˜Kšžœžœ˜/K˜—š  œžœžœžœ ˜Ešžœžœž˜*Kšžœžœ ˜Kšžœ˜—K˜—š œžœ˜/šžœžœž˜*Kšžœžœ˜#Kšžœ˜—K˜—š  œžœ˜.Kšœžœ˜,Kšœžœ˜(Kšœžœ˜(Kšœžœ˜(Kšœžœ˜(K˜—Kšœžœ˜+K˜4K˜8Kšœ˜šž˜Kšœ%˜%Kšœ žœ žœ˜šœ‘˜Kšœ žœ˜)Kšœžœ%˜-Kšœ?˜?šžœžœ˜ Kšœžœ žœ!žœ(˜oKšœ˜—šžœ˜Kšœžœ žœžœ˜WKš œžœ žœžœžœžœ˜LK˜—K˜—šœ‘˜š œ žœžœ žœžœžœžœ˜IKšœžœ!‘˜Dšžœžœžœ˜Kšœžœ!˜)K˜1šžœžœ‘˜"Kšœ&˜&Kšœžœ ˜!K˜—šžœ‘˜#Kšœ!˜!Kšœ&˜&K˜—K˜K˜—K˜—Kš žœ žœžœ&žœžœ˜JK˜—šœ‘˜Kšœžœ˜Kšœžœ ˜K˜!šžœ žœ‘˜*K˜K˜$K˜—šžœžœžœ‘˜)Kšœžœ˜K˜3K˜!K˜K˜*šžœž˜Kšœžœ˜!Kšœžœ#˜+K˜.K˜4Kšžœžœ2˜<šžœ‘˜"šžœž˜ K˜BK˜BK˜BKšžœ@˜G—K˜—K˜K˜Kšžœ˜—Kšžœ žœžœ˜K˜—šžœžœ‘#˜:K˜$K˜K˜—šžœ‘ ˜'K˜!K˜K˜—K˜—K˜Kšœ™Kšžœžœ žœ ˜!šžœžœ‘˜Kšžœ žœžœ˜Kšžœžœžœžœ˜GKšžœD˜HKšžœ˜—šžœ ˜K˜&K˜#K˜&K˜K˜—Kšžœ˜—K˜K˜—K˜š œžœžœ žœžœ!žœžœžœžœ˜xKšœžœžœ˜K˜!Kšžœžœžœ;˜Nšžœ˜Kšœ žœžœ˜%Kšœžœžœžœ˜"Kšžœ žœžœ˜5Kš žœ žœžœžœžœ˜0K˜WKšœ žœ˜(Kšžœ žœ˜ šžœ˜Kš œžœžœžœ˜4Kš œžœžœ&˜QKš œžœžœžœ.˜NKš  œžœžœžœžœ˜AKšœ žœžœ˜,Kšœ žœžœ˜,Kšœ žœL˜[Kšœ žœ^˜mK˜&Kšœ!˜!Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜Kšœ˜Kšœ"˜"Kšœ ˜ Kšœ˜Kšœ˜Kšžœžœ#žœžœ˜4K˜—K˜—K˜K˜—š œžœžœ!žœžœžœžœ žœ˜qKšœžœ˜ K˜#Kšžœžœ(˜6šžœ˜Kš œžœžœžœžœ˜Kšœ=˜=Kšœ žœ˜ K˜—K˜K˜—š   œžœ žœžœžœ˜;Kšœžœ.˜7Kšžœžœ%˜.K˜K˜—š œžœžœ žœžœžœžœžœžœ˜ƒKšœ žœ1‘˜YKšœžœ#˜+K˜AK˜K˜—š œžœžœžœžœžœžœžœžœ˜‡šœ žœ˜Kšœžœžœžœ"˜8Kšžœ žœžœ˜+K˜=K˜—Kšœ7˜7K˜K˜—šœ-˜-K˜—K˜š  œžœžœžœžœžœžœ˜Sš  œžœžœžœžœ˜3Kšœžœ˜ Kšœžœ˜Kšœžœ˜šžœ žœ,ž˜BKšœ žœ˜—Kš žœžœžœžœžœžœ˜KKšžœžœ˜K˜—Kšœ˜Kšœžœ˜Kšœ žœ˜Kšœžœžœ˜šž˜K˜)Kšžœžœžœžœ˜šžœžœ ž˜Kšžœžœ‘!˜:—K˜Kš žœ žœžœžœ‘˜IKš žœžœžœžœž˜JKšžœ‘/˜EKšžœ˜Kšžœ˜—š œžœžœ žœ žœžœ˜EKšžœžœ˜ K˜—K˜K˜—š œžœžœ žœ˜