<> <> <> <> <> <<>> DIRECTORY Atom, FileWriter, FS, InterFile, IO, NameSymbolTable, NodeProps, OtherNode, Rope, RopeEdit, RopeReader, RunReader, TextLooks, TextNode; PutInterFileImpl: CEDAR PROGRAM IMPORTS Atom, FileWriter, FS, NameSymbolTable, npI:NodeProps, OtherNode, Rope, RopeEdit, RopeReader, RunReader, TextLooks, TextNode EXPORTS InterFile SHARES Rope = BEGIN OPEN InterFile, TextNode; ToRope: PUBLIC PROC [node: Ref, flatten: BOOL _ TRUE] RETURNS [output: ROPE] = { data: FileWriter.Ref = FileWriter.ToRope[FALSE].data; Header[data]; Finish[data,node,flatten]; Trailer[data]; output _ FileWriter.Close[NIL,NIL,data,FALSE].output }; ToStream: PUBLIC PROC [stream: IO.STREAM, node: Ref, flatten: BOOL _ TRUE] RETURNS [count: Offset] = { data: FileWriter.Ref = FileWriter.ToStream[stream,FALSE].data; Header[data]; Finish[data,node,flatten]; Trailer[data]; count _ FileWriter.Close[NIL,NIL,data,FALSE].count; }; ToFile: PUBLIC PROC [fileName: ROPE, node: Ref, start: Offset _ 0, flatten: BOOL _ TRUE] RETURNS [count: Offset] = { file: FS.OpenFile = FS.Open[fileName, write]; data: FileWriter.Ref = FileWriter.OpenC[file,start,FALSE].data; Header[data]; Finish[data,node,flatten]; Trailer[data]; count _ FileWriter.Close[NIL,NIL,data,FALSE].count; FS.Close[file]; }; Header: PROC [data: FileWriter.Ref] = { WC['{,data]; FileWriter.WriteText["Interdoc/Interchange/0.0",data]; WC[15C,data]; }; Trailer: PROC [data: FileWriter.Ref] = { WC['},data] }; WC: PROC [c: CHAR, data: FileWriter.Ref] = { FileWriter.WriteChar[c,data] }; Finish: PROC [data: FileWriter.Ref, root: Ref, flatten: BOOL, runReader: RunReader.Ref _ NIL, ropeReader: RopeReader.Ref _ NIL, nameText: REF TEXT _ NIL, indent: NAT _ 0] = { WriteChar: PROC [c: CHAR] = { FileWriter.WriteChar[c,data] }; WriteAtom: PROC [atom: ATOM] = { WriteRope[Atom.GetPName[atom]] }; WriteText: PROC [txt: REF READONLY TEXT] = { FOR i: NAT IN [0..txt.length) DO char: CHAR; SELECT char _ txt[i] FROM '>, '# => WriteInt[char]; ENDCASE => FileWriter.WriteChar[char,data]; ENDLOOP }; WriteRope: PROC [r: ROPE] = { WriteChar['<]; WriteSimpleRope[r]; WriteChar['>] }; WriteSimpleRope: PROC [r: ROPE] = { size: Offset _ RopeEdit.Size[r]; RopeReader.SetPosition[ropeReader,r]; FOR i: Offset IN [0..size) DO char: CHAR; SELECT char _ RopeReader.Get[ropeReader] FROM '>, '# => WriteInt[char]; ENDCASE => FileWriter.WriteChar[char,data]; ENDLOOP }; WriteInt: PROC [c: CHAR] = { i: [0..255] _ LOOPHOLE[c]; WriteChar['#]; WriteChar['A + i/16]; WriteChar['A + i MOD 16]; WriteChar['#] }; NameText: PROC [name: NameSymbolTable.Name] = { OPEN NameSymbolTable; FromName[name,nameText ! TextOverflow => { nameText _ pZone.NEW[TEXT[nameText.length*2]]; RETRY } ]}; WriteLooks: PROC [lks: TextLooks.Looks] = { Look: TYPE = TextLooks.Look; WriteText["looks=<"]; FOR c:Look IN Look DO IF lks[c] THEN WriteChar[c]; ENDLOOP; WriteChar['>] }; WriteProp: PROC [name: ATOM, value: REF] RETURNS [BOOL] = { WritePropName: PROC = { WriteAtom[name]; WriteChar['=] }; WITH value SELECT FROM x:Ref => { -- prop value is a node WritePropName; Finish[data,x,flatten, runReader,ropeReader,nameText,indent+nesting]; LineBreak }; ENDCASE => { -- write specs as a rope specs: ROPE _ npI.GetSpecs[name,value]; IF specs # NIL THEN { WritePropName; WriteRope[specs]; LineBreak }}; RETURN [FALSE] }; LineBreak: PROC = { WriteChar[15C]; FOR i: NAT IN [0..indent) DO WriteChar[' ]; ENDLOOP }; nesting: NAT = 4; -- number of spaces per level of nesting typename: TypeName; terminal: BOOL; node,nodeChild: Ref; freeRunReader, freeRopeReader: BOOL _ TRUE; RopeRep: TYPE = Rope.RopeRep; substr: REF substr node RopeRep; IF runReader=NIL THEN runReader _ RunReader.GetRunReader[] ELSE freeRunReader _ FALSE; IF ropeReader=NIL THEN ropeReader _ RopeReader.GetRopeReader[] ELSE freeRopeReader _ FALSE; IF nameText=NIL THEN nameText _ pZone.NEW[TEXT[32]]; node _ root; DO -- start the node LineBreak; WriteChar['{]; <<-- write type>> IF (typename _ node.typename) # nullTypeName THEN { NameText[typename]; WriteText[nameText]; LineBreak }; <<-- write node props>> IF node.props # NIL THEN [] _ npI.MapProps[node,WriteProp]; <<-- now write contents>> TRUSTED {WITH n:node SELECT FROM text => { -- write the text rope: ROPE; size: Offset; runs: TextLooks.Runs; IF flatten THEN { -- flatten rope and runs n.rope _ RopeEdit.Flatten[n.rope]; n.runs _ TextLooks.Flatten[n.runs] }; rope _ n.rope; size _ Rope.Size[rope]; IF (runs _ n.runs) = NIL THEN WriteRope[rope] ELSE { -- write each run separately loc, cnt, numRuns: Offset _ 0; [numRuns,,] _ TextLooks.CountRuns[runs,0,size]; RunReader.SetPosition[runReader,runs,0]; IF substr = NIL THEN substr _ pZone.NEW[substr node RopeRep _ [node[substr[0,NIL,0,0]]]]; substr.base _ rope; substr.depth _ 1+RopeEdit.Depth[rope]; WHILE (cnt_cnt+1) <= numRuns DO looks: TextLooks.Looks; len: Offset; [len,looks] _ RunReader.MergedGet[runReader]; substr.size _ len; substr.start _ loc; IF looks = TextLooks.noLooks THEN WriteRope[substr] ELSE { WriteChar['{]; WriteLooks[looks]; WriteRope[substr]; WriteChar['}] }; loc _ loc+len; ENDLOOP; IF loc # size THEN ERROR }}; other => { WriteAtom[n.variety]; WriteChar['[]; WriteRope[OtherNode.GetSpecs[@n]]; WriteChar[']] }; ENDCASE => ERROR}; <<-- move to the next node>> terminal _ (nodeChild_FirstChild[node])=NIL; IF ~terminal THEN { node _ nodeChild; indent _ indent+nesting } ELSE { -- node has no children WriteChar['}]; DO IF node=root THEN GOTO Finis; IF ~IsLastSibling[node] THEN { node _ Next[node]; EXIT }; node _ Parent[node]; WriteChar['}]; indent _ indent-nesting; ENDLOOP }; REPEAT Finis => { IF freeRunReader THEN RunReader.FreeRunReader[runReader]; IF freeRopeReader THEN RopeReader.FreeRopeReader[ropeReader] }; ENDLOOP }; <<-- ***** Initialization>> StartPutFile: PUBLIC PROC = { }; END.