<> <> <> <<>> DIRECTORY Directory USING [GetProperty], File USING [Capability], FileIO USING [CapabilityFromStream, Open, StreamFromCapability], FileWriter USING [Close, OpenC, Ref, ToRope, ToStream], IO USING [Close, CreateOutputStreamToRope, Error, GetIndex, GetOutputStreamRope, Handle, PutChar, PutRope, SetLength], NodeProps USING [GetProp, HasWriter, PutProp, MapProps], OutputStructure USING [Output], Process USING [GetPriority, Priority, priorityBackground, SetPriority], PropertyTypes USING [tCreateDate], PutGet, Rope USING [Fetch, ROPE], RopeEdit USING [BlankChar, Size], RopeIO USING [PutRope, ToFileC], System USING [GreenwichMeanTime], T2FileOps, TiogaLooks USING [Look, Looks, noLooks, Runs], TiogaItemClass USING [ItemClass], TiogaNode USING [Name, nullName, Offset, Path, Ref, RefBranchNode, RefItemNode, RefTextNode], TiogaNodeOps USING [FetchItemClass, NarrowToBranchNode, NarrowToTextNode], TiogaPathOps USING [Contents, Equal, Forward, LastWithin, StepForwardNode]; PutFileImpl: CEDAR PROGRAM IMPORTS Directory, FileIO, FileWriter, IO, NodeProps, OutputStructure, Process, Rope, RopeEdit, RopeIO, TiogaNodeOps, TiogaPathOps EXPORTS PutGet SHARES TiogaNode = BEGIN OPEN PutGet; ToRope: PUBLIC PROC [node: Ref, textOnly: BOOLEAN _ FALSE] RETURNS [dataLen, count: Offset, output: ROPE] = { ctrl, data: FileWriter.Ref; simple: BOOLEAN; flags: CHAR; [output, simple] _ SimpleFile[node]; IF simple THEN { dataLen _ count _ RopeEdit.Size[output]; RETURN }; [ctrl, data] _ FileWriter.ToRope[]; flags _ OutputStructure.Output[ctrl, data, node]; [dataLen, count, output] _ FileWriter.Close[ctrl, data, textOnly, flags] }; ToStream: PUBLIC PROC [ stream: IO.Handle, node: Ref, textOnly: BOOL _ FALSE] RETURNS [dataLen, count: Offset] = { ctrl, data: FileWriter.Ref; rope: ROPE; simple: BOOLEAN; flags: CHAR; [rope, simple] _ SimpleFile[node]; IF simple THEN { RopeIO.PutRope[stream, rope]; dataLen _ count _ RopeEdit.Size[rope]; RETURN }; [ctrl, data] _ FileWriter.ToStream[stream]; flags _ OutputStructure.Output[ctrl, data, node]; [dataLen, count, ] _ FileWriter.Close[ctrl, data, textOnly, flags] }; ToFile: PUBLIC PROC [ fileName: ROPE, node: Ref, start: Offset _ 0, textOnly: BOOLEAN _ FALSE] RETURNS [dataLen, count: Offset] = { stream: IO.Handle _ FileIO.Open[fileName, overwrite]; capability: File.Capability _ FileIO.CapabilityFromStream[stream]; IO.Close[stream]; -- need to close first or get 0 length file! [dataLen, count] _ ToFileC[capability, node, start, textOnly] }; ToFileC: PUBLIC PROC [ file: File.Capability, node: Ref, start: Offset _ 0, textOnly: BOOLEAN _ FALSE] RETURNS [dataLen, count: Offset] = { ropeToFile: PROC [rope: ROPE] = { RopeIO.ToFileC[file, rope, start] }; opener: PROC RETURNS [ctrl, data: FileWriter.Ref] = { [ctrl, data] _ FileWriter.OpenC[file, start] }; [dataLen, count] _ FileIt[ropeToFile, opener, node, textOnly] ; UpdateCreateDate[node, file] }; UpdateCreateDate: PROC [node: Ref, file: File.Capability] = TRUSTED { createDate: System.GreenwichMeanTime; prop: REF System.GreenwichMeanTime; Directory.GetProperty[file: file, property: PropertyTypes.tCreateDate, propertyValue: DESCRIPTOR[@createDate, SIZE[System.GreenwichMeanTime]]]; IF (prop _ NARROW[NodeProps.GetProp[node, $FileCreateDate]]) # NIL THEN prop^ _ createDate ELSE NodeProps.PutProp[node, $FileCreateDate, NEW[System.GreenwichMeanTime _ createDate]] }; FileIt: PROC [ ropeToFile: PROC [ROPE], opener: PROC RETURNS [ctrl, data: FileWriter.Ref], node: Ref, textOnly: BOOL] RETURNS [dataLen, count: Offset] = TRUSTED { ctrl, data: FileWriter.Ref; rope: ROPE; simple: BOOLEAN; priority: Process.Priority = Process.GetPriority[]; Process.SetPriority[Process.priorityBackground]; [rope, simple] _ SimpleFile[node]; IF simple THEN { ropeToFile[rope]; dataLen _ count _ RopeEdit.Size[rope] } ELSE { flags: CHAR; [ctrl, data] _ opener[]; flags _ OutputStructure.Output[ctrl, data, node]; [dataLen, count, ] _ FileWriter.Close[ctrl, data, textOnly, flags] }; Process.SetPriority[priority] }; SimpleFile: PROC [n: TiogaNode.Ref] RETURNS [rope: ROPE, simple: BOOLEAN] = { SimpleNode: PROC [node: TiogaNode.RefBranchNode] RETURNS [ROPE, BOOLEAN] = TRUSTED { HasInterestingProp: PROC [n: Ref] RETURNS [BOOL] = TRUSTED { Check: PROC [name: ATOM, value: REF] RETURNS [BOOL] = TRUSTED { RETURN [NodeProps.HasWriter[name]] }; RETURN [NodeProps.MapProps[n, Check, FALSE, FALSE]] }; IF node.format=TiogaNode.nullName AND ~node.comment AND node.templateInfo=normal AND ~HasInterestingProp[node] THEN IF node.contents = NIL THEN RETURN [NIL, TRUE]; WITH node.contents SELECT FROM -- must have simple text node for contents t: TiogaNode.RefTextNode => { classInfo: TiogaItemClass.ItemClass; IF ~t.last OR ~t.format=TiogaNode.nullName OR t.comment OR t.templateInfo # normal OR classInfo.flavor # $Text OR HasInterestingProp[t] THEN RETURN [NIL, FALSE]; classInfo _ TiogaNodeOps.FetchItemClass[t.class]; IF classInfo.flavor # $Text OR HasInterestingProp[t] THEN RETURN [NIL, FALSE]; IF t.runs=NIL THEN RETURN [t.rope, TRUE]; WITH r: t.runs SELECT FROM base => IF r.length=1 AND r[0].looks=TiogaLooks.noLooks THEN RETURN [t.rope, TRUE]; ENDCASE }; ENDCASE; RETURN [NIL, FALSE] }; root: TiogaNode.RefBranchNode; IF n=NIL THEN RETURN [NIL, TRUE]; IF (root _ TiogaNodeOps.NarrowToBranchNode[n])=NIL THEN RETURN [NIL, FALSE]; [rope, simple] _ SimpleNode[root]; IF ~simple OR root.contents#NIL THEN RETURN[NIL, FALSE]; -- root must not have contents IF root.child=NIL THEN RETURN [NIL, TRUE]; -- simple root and no child IF ~root.child.last OR root.child.child # NIL THEN RETURN [NIL, FALSE]; -- more than one child, so not simple [rope, simple] _ SimpleNode[root.child] }; WriteMesaFilePlain: PUBLIC PROC [fileName: ROPE, root: TiogaNode.RefBranchNode]={ h: IO.Handle _ FileIO.Open[fileName: fileName, accessOptions: overwrite]; WritePlain[h, root, TRUE]; IO.Close[h] }; WriteFilePlain: PUBLIC PROC [fileName: ROPE, root: TiogaNode.RefBranchNode] = { h: IO.Handle _ FileIO.Open[fileName: fileName, accessOptions: overwrite]; WritePlain[h, root]; IO.Close[h] }; WriteFileCPlain: PUBLIC PROC [file: File.Capability, root: TiogaNode.RefBranchNode] = { h: IO.Handle _ FileIO.StreamFromCapability[file]; WritePlain[h, root]; IO.Close[h] }; WriteRopePlain: PUBLIC PROC [root: TiogaNode.RefBranchNode] RETURNS [output: ROPE] = { h: IO.Handle _ IO.CreateOutputStreamToRope[]; WritePlain[h, root]; RETURN [IO.GetOutputStreamRope[h]] }; WritePlain: PROC [h: IO.Handle, root: TiogaNode.RefBranchNode, restoreDashes: BOOL _ FALSE] = { HasInitialDashes: PROC [r: ROPE] RETURNS [BOOL] = { loc: INT _ 0; size: INT = RopeEdit.Size[r]; c: CHAR; WHILE loc < size AND RopeEdit.BlankChar[c _ Rope.Fetch[r, loc]] DO loc _ loc+1; ENDLOOP; IF loc > size OR c # '- OR Rope.Fetch[r, loc+1] # '- THEN RETURN [FALSE]; RETURN [TRUE] }; br: TiogaNode.RefBranchNode _ root; path: TiogaNode.Path _ [br, NIL]; contents, lastWithin: TiogaNode.Path; level: INTEGER _ 0; levelDelta: INTEGER; first: BOOL _ TRUE; DO firstItem: BOOL _ TRUE; [path, levelDelta] _ TiogaPathOps.Forward[path]; IF path.node=NIL THEN EXIT; IF first THEN first _ FALSE ELSE IO.PutChar[h, '\n]; -- carriage returns between nodes level _ level+levelDelta; IF (contents _ TiogaPathOps.Contents[path]).node=NIL THEN LOOP; THROUGH [1..level) DO IO.PutChar[h, '\t]; ENDLOOP; -- output level-1 tabs lastWithin _ TiogaPathOps.LastWithin[contents]; DO -- output the contents of the node text: TiogaNode.RefTextNode; IF (text _ TiogaNodeOps.NarrowToTextNode[contents.node]) # NIL THEN { IF firstItem AND restoreDashes AND text.comment AND ~HasInitialDashes[text.rope] THEN IO.PutRope[h, "-- "]; -- restore the leading dashes for Mesa comments IO.PutRope[h, text.rope] }; firstItem _ FALSE; IF TiogaPathOps.Equal[contents, lastWithin] THEN EXIT; -- finished contents _ TiogaPathOps.StepForwardNode[contents]; ENDLOOP; ENDLOOP; { ENABLE IO.Error => IF ec = NotImplementedForThisStream THEN GOTO Exit; IO.SetLength[h, IO.GetIndex[h]] } EXITS Exit => RETURN }; END.