CDOut.mesa
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
by Ch. Jacobi, December 12, 1983 2:02 pm
some code from Kim Rachmeler
Last Edited by: Jacobi, August 28, 1985 4:25:01 pm PDT
DIRECTORY
BasicTime,
CDIO,
CD,
CDBasics,
CDDirectory,
CDEvents,
CDExtras,
CDOrient,
CDPrivate,
CDProperties,
CDValue,
Convert,
FileNames,
FS,
IO,
Process,
Rope,
TerminalIO,
TokenIO;
CDOut: CEDAR PROGRAM --monitored by TokenIO
IMPORTS BasicTime, CD, CDBasics, CDIO, CDDirectory, CDEvents, CDExtras, CDOrient, CDProperties, CDValue, Convert, FileNames, FS, IO, Process, Rope, TerminalIO, TokenIO
EXPORTS CDIO
SHARES CDProperties =
BEGIN
xChipndaleFile: INT = 12121983;
xVersion: INT = 9;
-- global variables; are protected by the requirement of attaching Tokenio
designToWrite: CD.Design;
directoryNum: INT;
directoryMark: TokenIO.Mark;
outputKey: REFNEW[INT];
thisTime: REF;
lastTime: REF;
isQuiet: BOOL;
WriteRope: PROC [r: Rope.ROPE] =
BEGIN
IF ~isQuiet THEN TerminalIO.WriteRope[r]
END;
WriteLayer: PUBLIC PROC [l: CD.Layer] =
BEGIN
TokenIO.WriteAtom[CD.LayerKey[l]];
END;
WriteProperties: PUBLIC PROC [props: CD.Properties] =
BEGIN
FOR l: CD.Properties ← props, l.rest WHILE l#NIL DO
pp: CDProperties.PropertyProcs;
IF NOT ISTYPE[l.first.key, ATOM] THEN LOOP;
pp ← CDProperties.FetchProcs[l.first.key];
IF pp#NIL AND pp.internalWrite#NIL THEN {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
pp.internalWrite[l.first.key, l.first.val];
TokenIO.WritePopFlag[];
}
ELSE
WITH l.first.val SELECT FROM
r: Rope.ROPE => {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
TokenIO.WriteRope[r];
TokenIO.WritePopFlag[];
};
at: ATOM => {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
TokenIO.WriteAtom[at];
TokenIO.WritePopFlag[];
};
ri: REF INT => {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
TokenIO.WriteInt[ri^];
TokenIO.WritePopFlag[];
};
pl: CD.Properties => {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
TokenIO.WritePushFlag[NIL]; -- now comes a property list
WriteProperties[pl];
TokenIO.WritePopFlag[]; -- end of property list
TokenIO.WritePopFlag[]; -- end of this property
};
pl: CDPrivate.LayerRef => {
TokenIO.WriteAtom[$Property];
TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]];
TokenIO.WritePushFlag[$layer]; -- now comes a property list
WriteLayer[pl.number];
TokenIO.WritePopFlag[]; -- undoes pushflag layer
TokenIO.WritePopFlag[]; -- end of this property
};
ENDCASE => NULL;
ENDLOOP;
END;
ARectIX: PROC [inst: CD.Instance] RETURNS [CD.Rect] =
--old compatibility stuff
BEGIN
RETURN [
CDOrient.MapRect[
itemInCell: inst.ob.class.oldInsideRect[inst.ob],
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location
]
]
END;
WriteInstance: PUBLIC PROC [ap: CD.Instance] =
BEGIN
loc: CD.Position;
IF xVersion<=7 AND xVersion>2 THEN
loc ← CDBasics.BaseOfRect[ARectIX[ap]]
ELSE loc ← ap.location;
TokenIO.WriteInt[loc.x];
TokenIO.WriteInt[loc.y];
CDIO.WriteOrientation[ap.orientation];
WriteProperties[ap.properties];
WriteObject[ap.ob];
END;
WriteInstanceList: PUBLIC PROC [list: CD.InstanceList] =
BEGIN
count: INT ← 0;
FOR l: CD.InstanceList ← list, l.rest WHILE l#NIL DO
count ← count+1;
ENDLOOP;
TokenIO.WriteInt[count];
FOR l: CD.InstanceList ← list, l.rest WHILE l#NIL DO
WriteInstance[l.first];
ENDLOOP;
END;
WriteObject: PUBLIC PROC [ob: CD.Object] =
BEGIN
xx: REF = CDProperties.GetPropFromObject[from: ob, prop: thisTime];
IF xx#NIL AND ISTYPE[xx, REF INT] THEN {
WriteRope["."];
TokenIO.WriteInt[NARROW[xx, REF INT]^];
RETURN
};
WriteRope["x"];
DoWriteObject[ob]
END;
DoWriteObject: PROC [ob: CD.Object] =
BEGIN
IF ob.class.internalWrite=NIL THEN {
ob1: CD.Object ← CDDirectory.ExpandHard[ob, designToWrite, NIL];
IF ob1#NIL THEN {
WriteRope["*"];
WriteObject[ob1];
}
ELSE {
TokenIO.WritePushFlag[$Unknown];
TokenIO.WritePopFlag[];
WriteRope["*object not written\n"];
};
RETURN
};
TokenIO.WritePushFlag[NARROW[ob.class.objectType, ATOM]];
ob.class.internalWrite[ob];
IF ob.class.inDirectory THEN {
TokenIO.WriteRope[CDDirectory.Name[ob]];
};
WriteProperties[ob.properties];
CDProperties.PutPropOnObject[onto: ob, prop: lastTime, val: NIL];
TokenIO.WritePopFlag[];
END;
WritePushLayer: PROC [pl: LIST OF CD.PushRec] =
BEGIN
IF pl=NIL THEN RETURN;
IF pl.rest#NIL THEN WritePushLayer[pl.rest];
TokenIO.WriteAtom[$Push];
IF pl.first.mightReplace#NIL THEN WriteInstance[pl.first.mightReplace]
ELSE TokenIO.WriteAtom[$Nil];
WriteObject[pl.first.dummyCell.ob]
END;
EachChildren: CDDirectory.EnumerateObjectsProc --PROC [me: Object, x: REF]-- =
BEGIN
xx: REF = CDProperties.GetPropFromObject[from: me, prop: thisTime];
IF xx#NIL THEN RETURN; -- it and its children are already out
IF me.class.inDirectory THEN
CDDirectory.EnumerateChildObjects[me: me, p: EachChildren, x: x];
directoryNum ← directoryNum+1;
TokenIO.WriteInt[directoryNum];
DoWriteObject[me];
CDProperties.PutPropOnObject[onto: me, prop: thisTime, val: NEW[INT𡤍irectoryNum]];
END;
EachDirectoryEntry: CDDirectory.EachEntryAction --[name: Rope.ROPE, ob: CD.Object] RETURNS [quit: BOOL�LSE]-- =
BEGIN
EachChildren[ob, NIL];
END;
DoWriteDesign: PROC [] =
BEGIN
ENABLE TokenIO.WritingStopped => {
RemoveOldProperties[designToWrite, lastTime];
REJECT
};
WriteVersionKeys: PROC [design: CD.Design] =
BEGIN
TokenIO.WriteRope[Convert.RopeFromTime[from: BasicTime.Now[], end: seconds]];
END;
thisTime ← NEW[INT];
lastTime ← CDValue.Fetch[boundTo: designToWrite, key: outputKey, propagation: design];
IF lastTime=NIL THEN {lastTime←NEW[INT]};
CDValue.Store[boundTo: designToWrite, key: outputKey, value: thisTime];
directoryNum𡤀
IF Rope.Length[designToWrite.name]<=0
OR Rope.Fetch[designToWrite.name]='/
OR Rope.Fetch[designToWrite.name]='[ THEN TokenIO.WriteRope[NIL]
ELSE TokenIO.WriteRope[designToWrite.name];
WriteVersionKeys[designToWrite];
directoryMark ← TokenIO.MarkAndWriteInt[directoryNum]; -- number of entries in directory
[] ← CDDirectory.Enumerate[design: designToWrite, action: EachDirectoryEntry];
WriteProperties[designToWrite.properties];
WritePushLayer[designToWrite.actual];
TokenIO.UpdateMark[mark: directoryMark, value: directoryNum];
TokenIO.WriteAtom[$EndOfDesign];
END;
RemoveOldProperties: PROC[design: CD.Design, key: REF] =
BEGIN
--at this place we know that CDExtras will fork and will set the priority down
CDExtras.RemoveProperties[design, key]
END;
DontOverWrite: ERROR = CODE;
CanNotAttach: SIGNAL = CODE;
WriteDesign: PUBLIC PROC [design: CD.Design, to: REFNIL, quiet: BOOL, emergency: BOOL] RETURNS [done: BOOLFALSE] =
--to is either a IO.STREAM, a Rope.ROPE, or NIL
--if emergency, some locks are ignored, interactive input is skipped; you better
--roll back after an emergency write is done
BEGIN
ENABLE DontOverWrite => GOTO NotOpened;
DoAttach: PROC [] RETURNS [done: BOOL] =
BEGIN
DoRealAttach: PROC [] RETURNS [done: BOOLFALSE] =
BEGIN
TokenIO.AttachWriter[binFile ! TokenIO.Error => GOTO AttachProblem];
done ← TRUE;
EXITS
AttachProblem => RETURN
END;
count: NAT ← 0;
done ← DoRealAttach[];
WHILE NOT done AND emergency DO
TokenIO.StopWriting[];
Process.Pause[Process.SecondsToTicks[1]];
TokenIO.StopWriting[];
Process.Pause[Process.SecondsToTicks[2]];
count ← count+1;
IO.Reset[binFile];
TerminalIO.WriteRope["TRIES TO BREAK THE LOCK\n"];
TokenIO.ReleaseWriter[]; -- XXXXXXX DANGEROUS
Process.Pause[Process.SecondsToTicks[1]];
done ← DoRealAttach[];
IF NOT done AND count>5 THEN {
count ← 0;
SIGNAL CanNotAttach;
};
ENDLOOP
END;
InName: PROC [wDir: Rope.ROPENIL] RETURNS [name: Rope.ROPE] =
BEGIN
CheckExistance: PROC [name: Rope.ROPE] =
--Errors DontOverWrite if necessary
BEGIN
temfile: IO.STREAMFS.StreamOpen[name ! FS.Error => IF error.group#bug THEN GOTO NotFound];
--file exists already
TerminalIO.WriteRope["File "];
TerminalIO.WriteRope[name];
TerminalIO.WriteRope[" exists already; "];
IF ~TerminalIO.UserSaysYes[label: "overwrite? ", text: "overwrite?", default: FALSE] THEN ERROR DontOverWrite;
TerminalIO.WriteRope[" yes\n"];
EXITS
NotFound => { --this is the "normal" case of an not yet existing file
NULL
}
END;
IF Rope.IsEmpty[wDir] THEN wDir ← FileNames.CurrentWorkingDirectory[];
IF emergency THEN name ← "///temp/ChipNDale/emergency/emergency.dale"
ELSE {
TerminalIO.WriteRope["file name:"];
IF ~Rope.IsEmpty[wDir] THEN {
TerminalIO.WriteRope[" ("];
TerminalIO.WriteRope[wDir];
TerminalIO.WriteRope[")"];
};
name ← TerminalIO.RequestRope[" > "];
name ← CDIO.MakeName[name, "dale", wDir];
CheckExistance[name];
}
END;
Help: PROC [] =
BEGIN
Write: PROC [r: Rope.ROPE] = {
TerminalIO.WriteRope[r];
TerminalIO.WriteLn[];
};
Write["****************************************"];
Write["Help for saving a design:"];
Write["wait until the background saving is done and make a copy of it! (but don't rely on background saving alone; background saving is done WITHOUT requiring monitor locks, for obvious reasons.)"];
Write["then, try regular output again, before you proceed to any of the more drastic methods following:\n"];
Write["SHIFT-SHIFT-SWAT (>2 seconds) should save all designs"];
Write["or use a command tool: (the command tool commands require you to bringover the necesarry sources and bcd's first)"];
Write[" ""← CDSequencerImpl.savePeriod ← -1"" "];
Write[" prevents any further un-monitored automatic saving in parallel with your other command tool commands."];
Write[" ""← CDEmergencyHandling.SaveAll[]"" "];
Write[" or"];
Write[" ""← TokenIO.ReleaseWriter[]"" "];
Write[" to release the locks; after this try a regular output command"];
Write["****************************************"];
END;
--WriteDesign
iMadeTheOpen: BOOL�LSE;
binFile: IO.STREAM;
sealMark: TokenIO.Mark;
name, fileName: Rope.ROPE;
wDir: Rope.ROPE ← CDIO.GetWorkingDirectory[design];
IF to#NIL AND ISTYPE[to, IO.STREAM] THEN {
binFile ← NARROW[to, IO.STREAM]
}
ELSE {
IF to=NIL THEN {
name ← InName[wDir];
}
ELSE IF ISTYPE[to, Rope.ROPE] THEN {
name ← NARROW[to, Rope.ROPE];
IF Rope.IsEmpty[name] THEN name ← InName[wDir];
}
ELSE {
TerminalIO.WriteRope["WriteDesign does not support type of 'to' parameter\n"];
GOTO NotOpened;
};
fileName ← CDIO.MakeName[name, "dale", wDir];
binFile ← FS.StreamOpen[fileName: fileName, accessOptions: $create, keep: 2 !
FS.Error => IF error.group#bug THEN {
binFile←NIL;
GOTO NotOpened
}
];
iMadeTheOpen ← TRUE;
};
IF NOT DoAttach[] THEN {
IF ~quiet THEN WriteRope["not attached, locks are hold\n"];
IF ~quiet THEN Help[];
RETURN
};
isQuiet ← quiet;
designToWrite ← design;
TokenIO.WriteInt[xChipndaleFile];
TokenIO.WriteInt[xVersion];
sealMark ← TokenIO.MarkAndWriteInt[0]; -- this is a bad seal
TokenIO.WriteAtom[designToWrite.technology.key];
TokenIO.WriteRope[designToWrite.technology.name];
IF CDEvents.ProcessEvent[ev: writeEvent, design: designToWrite, x: NIL, listenToDont: TRUE].dont THEN {
WriteRope["write not done\n"];
TokenIO.ReleaseWriter[];
IO.Close[binFile];
RETURN
};
DoWriteDesign[];
TokenIO.UpdateMark[sealMark, -1]; -- validate seal
TokenIO.ReleaseWriter[];
IF iMadeTheOpen THEN IO.Close[binFile];
WriteRope["\n"];
TerminalIO.WriteRope["design "];
TerminalIO.WriteRope[designToWrite.name];
TerminalIO.WriteRope[" written on file "];
IF iMadeTheOpen THEN TerminalIO.WriteRope[fileName];
TerminalIO.WriteLn[];
done ← TRUE;
EXITS
NotOpened => {
IF ~quiet THEN TerminalIO.WriteRope["File not created\n"];
};
END;
-- Module initialization
writeEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$WriteTechnologyPrivate];
END.