-- PutInterFileImpl.Mesa
-- written by Paxton. May 1981
-- last written by McGregor. September 10, 1982 1:17 pm
Last Edited by: Maxwell, January 5, 1983 12:59 pm
DIRECTORY
InterFile,
FileWriter,
TextNode,
OtherNode,
TextLooks,
NodeProps,
RopeEdit,
RopeReader,
RunReader,
File,
FileIO,
Rope,
NameSymbolTable,
Atom,
IO;
PutInterFileImpl: CEDAR PROGRAM
IMPORTS TextNode, npI:NodeProps, FileWriter, IO, FileIO, Rope, RopeEdit, RopeReader, RunReader, TextLooks, NameSymbolTable, OtherNode, Atom
EXPORTS InterFile
SHARES Rope =
BEGIN OPEN InterFile, TextNode;
ToRope: PUBLIC PROC [node: Ref, flatten: BOOLEANTRUE]
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.Handle, node: Ref, flatten: BOOLEANTRUE]
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: BOOLEANTRUE]
RETURNS [count: Offset] = {
stream: IO.Handle ← FileIO.Open[fileName,overwrite];
capability: File.Capability ← FileIO.CapabilityFromStream[stream];
data: FileWriter.Ref ← FileWriter.OpenC[capability,start,FALSE].data;
Header[data];
Finish[data,node,flatten];
Trailer[data];
count ← FileWriter.Close[NIL,NIL,data,FALSE].count;
IO.Close[stream] };
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: CHARACTER, data: FileWriter.Ref] = { FileWriter.WriteChar[c,data] };
Finish: PROC [data: FileWriter.Ref, root: Ref, flatten: BOOLEAN,
runReader: RunReader.Ref ← NIL, ropeReader: RopeReader.Ref ← NIL,
nameText: REF TEXTNIL, indent: NAT ← 0] = {
WriteChar: PROC [c: CHARACTER] = { 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: CHARACTER;
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: CHARACTER;
SELECT char ← RopeReader.Get[ropeReader] FROM
'>, '# => WriteInt[char];
ENDCASE => FileWriter.WriteChar[char,data];
ENDLOOP };
WriteInt: PROC [c: CHARACTER] = {
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 [BOOLEAN] = {
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: BOOLEAN;
node,nodeChild: Ref;
freeRunReader, freeRopeReader: BOOLEANTRUE;
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𡤌nt+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𡤏irstChild[node])=NIL;
IF ~terminal THEN { node ← nodeChild; indent ← indent+nesting }
ELSE { -- node has no children
WriteChar['}];
DOIF 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.