-- 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:
BOOLEAN ←
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.Handle, node: Ref, flatten:
BOOLEAN ←
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:
BOOLEAN ←
TRUE]
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 TEXT ← NIL, 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: BOOLEAN ← 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𡤌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['}];
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.