PutFileImpl.Mesa
written by Paxton. August 1983
Last Edited by: Paxton, August 16, 1983 7:50 pm
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: BOOLEANFALSE]
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: BOOLFALSE]
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: BOOLEANFALSE]
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: BOOLEANFALSE]
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: BOOLFALSE] = {
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: BOOLTRUE;
DO
firstItem: BOOLTRUE;
[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.