CDIOCommands.mesa
Copyright (C) 1984, 1986, 1987 Xerox Corporation. All rights reserved.
Created by: Christian Jacobi, February 8, 1984 9:41 am
Last Edited by: Christian Jacobi, August 19, 1987 5:34:04 pm PDT
Don Curry January 26, 1989 2:48:22 pm PST
DIRECTORY
CD,
CDEnvironment,
CDIO,
CDOps,
CDDrawQueue,
CDPanel,
CDProperties,
CDSequencer,
CDValue,
CDVPrivate,
CDViewer,
CedarProcess,
Commander,
CommandTool,
FileNames,
InterminalBackdoor USING [terminal],
IO,
Process,
Rope,
RuntimeError USING [UNCAUGHT],
Terminal,
TerminalDefs,
TerminalIO,
TokenIO,
UserProfile,
ViewerClasses,
ViewerOps;
CDIOCommands:
CEDAR
MONITOR
IMPORTS CD, CDDrawQueue, CDEnvironment, CDIO, CDOps, CDPanel, CDProperties, CDSequencer, CDValue, CDViewer, CDVPrivate, CedarProcess, CommandTool, FileNames, InterminalBackdoor, IO, Process, Rope, RuntimeError, Terminal, TerminalIO, UserProfile, ViewerOps
SHARES CDSequencer =
BEGIN
OpenCommand: Commander.CommandProc = {
v: ViewerClasses.Viewer;
name: IO.ROPE ← CommandTool.ArgN[cmd, 1];
design: CD.Design ← GetDesign[name, cmd];
IF design=NIL THEN {cmd.out.PutRope[openDoc]; RETURN[$Failure]};
v ← CDViewer.ViewersOf[design].first;
IF v.iconic THEN ViewerOps.OpenIcon[v]};
GetDesign:
PUBLIC
PROC [name:
IO.
ROPE, cmd: Commander.Handle ← NIL]
RETURNS [design: CD.Design] = {
design ← CDViewer.FindDesign[name];
IF design#NIL OR name.Length[]=0 THEN RETURN[design];
[] ← CommandTool.DoCommandRope[IO.PutFR["CDRead %g",IO.rope[name]], NIL, cmd];
design ← CDViewer.FindDesign[name]};
ReadCommand: Commander.CommandProc = {
ENABLE TerminalIO.UserAbort => GOTO UserAbrt;
LoadAllImports:
PROC [design:
CD.Design] = {
--we dont want to import fancy imports; io is logically deeper in hierachy
p: CDSequencer.CommandProc ← CDSequencer.FetchCommand[$UnqueuedLoadAllImps].proc;
IF p#NIL THEN CDSequencer.ExecuteProc[p, design, dontQueue];
};
design: CD.Design; tech: CD.Technology←NIL;
name: Rope.ROPE ← NIL; char: CHAR;
loadImports: BOOL ← UserProfile.Boolean["ChipnDale.AutoLoadImports", TRUE];
panelOn, panelOff, saveOn, saveOff, alreadyTried, readonly: BOOL ← FALSE;
result ← $Failure;
--parse input
FOR list:
LIST
OF Rope.
ROPE ← CommandTool.ParseToList[cmd,
FALSE, ' ].list, list.rest
WHILE list#
NIL
DO
IF Rope.IsEmpty[list.first] THEN {msg ← "empty parameter"; RETURN};
char ← Rope.Fetch[list.first, 0];
SELECT
TRUE
FROM
char='-
OR char='+ => {
--a switch
SELECT
TRUE
FROM
Rope.Equal[list.first, "-X", FALSE] => loadImports ← FALSE;
Rope.Equal[list.first, "+X", FALSE] => loadImports ← TRUE;
Rope.Equal[list.first, "-P", FALSE] => panelOff ← TRUE;
Rope.Equal[list.first, "+P", FALSE] => panelOn ← TRUE;
Rope.Equal[list.first, "-S", FALSE] => saveOff ← TRUE;
Rope.Equal[list.first, "+S", FALSE] => saveOn ← TRUE;
Rope.Equal[list.first, "-R", FALSE] => readonly ← FALSE;
Rope.Equal[list.first, "+R", FALSE] => readonly ← TRUE;
ENDCASE => {msg ← Rope.Cat["unknown switch ", list.first]; RETURN};
};
char='^ => {
--a technology
n: Rope.ROPE ← Rope.Substr[list.first, 1, Rope.Length[list.first]];
IF list.rest#NIL OR name#NIL THEN {msg ← "unknown option(s)"; RETURN};
tech ← CDEnvironment.LoadTechnology[NIL, n];
IF tech=NIL THEN {msg ← "technology not loaded"; RETURN};
design ← CDOps.CreateDesign[tech];
alreadyTried ← TRUE
};
ENDCASE => {
--maybe a file name
IF name#NIL THEN {msg ← "too many names or options"; RETURN};
name ← list.first;
};
ENDLOOP;
--read design
IF ~alreadyTried THEN design ← CDIO.ReadDesign[name];
--fix up design
IF design=NIL THEN msg ← "read not done"
ELSE {
panel: BOOL ← UserProfile.Boolean["ChipNDale.OpenPanel", TRUE];
IF loadImports THEN LoadAllImports[design];
IF panelOff THEN panel ← FALSE;
IF panelOn THEN panel ← TRUE;
IF readonly
THEN {
ref: REF;
ref ← CDValue.Fetch[design, $CDxFromFile, design]; CDValue.Store[design, $CDxCachedFile, ref];
ref ← CDValue.Fetch[design, $CDxFileCreated, design]; CDValue.Store[design, $CDxCachedCreated, ref];
CDOps.SetMutability[design, readonly];
}
ELSE CDOps.SetMutability[design, editable];
[] ← CDViewer.CreateViewer[design, panel];
result ← design;
msg ← Rope.Concat["design ", CD.DesignName[design]];
IF saveOff THEN CDProperties.PutDesignProp[design, $CDxDontBackgroundSave, $TRUE];
IF saveOn THEN CDProperties.PutDesignProp[design, $CDxDontBackgroundSave, NIL];
IF ~readonly
AND CDProperties.GetDesignProp[design, $CDxDontBackgroundSave]=$TRUE
THEN
msg ← Rope.Concat[msg, " [background saving for this design is disabled]"]
};
TerminalIO.PutRopes[msg, "\n"];
EXITS UserAbrt => {result ← $Failure; msg ← "aborted"};
};
CacheWriteDesignComm:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["write cache design to a file; NOT the truth\n"];
IF
CDIO.WriteDesign[design: comm.design, truth:
FALSE]
THEN {CDSequencer.SetEdited[comm.design, FALSE]; TerminalIO.PutRope["done\n"]}
ELSE TerminalIO.PutRope["not done\n"];
};
TruthWriteDesignComm:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["write design to a file\n"];
IF
CDIO.WriteDesign[design: comm.design]
THEN {CDSequencer.SetEdited[comm.design, FALSE]; TerminalIO.PutRope["done\n"]}
ELSE TerminalIO.PutRope["not done\n"];
};
savedKey: REF Rope.ROPE ← NEW[Rope.ROPE ← "saved as"]; --unique, not saved on files
TruthSaveDesignComm:
PROC [comm: CDSequencer.Command] = {
from: REF ← CDValue.Fetch[comm.design, savedKey, design];
wDir: Rope.ROPE ← CDEnvironment.GetWorkingDirectory[comm.design];
name: Rope.ROPE ← CDEnvironment.MakeName[CDIO.MakeShortName[comm.design], "dale", wDir];
IF Rope.Match[pattern: "///temp/ChipNDale/*", object: wDir, case:
FALSE]
THEN {
TerminalIO.PutRope["design uses special working directory; "];
TerminalIO.PutRope["for your own protection: use general output instead of save\n"];
TruthWriteDesignComm[comm];
RETURN;
};
IF from=NIL THEN from ← CDValue.Fetch[comm.design, $CDxFromFile, design];
TerminalIO.PutRope["save design\n"];
WITH from
SELECT
FROM
r: Rope.
ROPE => {
nameFromFile: Rope.
ROPE ←
CDEnvironment.MakeName[FileNames.GetShortName[r], "dale", wDir];
IF ~Rope.Equal[name, nameFromFile,
FALSE]
THEN
SELECT
TerminalIO.RequestSelection[
header: "design name and file name differ !",
choice:
LIST[
Rope.Concat["use ", name],
Rope.Concat["use ", nameFromFile],
"get name interactively"]
] FROM
1 => {
IF ~Rope.IsEmpty[name] THEN CDValue.Store[comm.design, savedKey, name]
};
2 => name ← nameFromFile;
3 => name ← NIL;
ENDCASE => {TerminalIO.PutRope["not done\n"]; RETURN};
};
ENDCASE => NULL;
IF
CDIO.WriteDesign[design: comm.design, to: name]
THEN {CDSequencer.SetEdited[comm.design, FALSE]; TerminalIO.PutRope["done\n"]}
ELSE TerminalIO.PutRope["not done\n"];
};
EmergencySaveDesign:
ENTRY
PROC [design:
CD.Design, key:
REF] = {
ENABLE {
RuntimeError.UNCAUGHT => GOTO oops;
UNWIND => NULL;
};
IF ~design.edited
OR CDProperties.GetProp[design, $cdioPrivate]=key
THEN
IF ~design.changedSinceSaving THEN RETURN;
CDProperties.PutProp[design, $cdioPrivate, key];
Process.PauseMsec[100]; -- give detached Flush processes a chance
IF
CDIO.WriteDesign[design: design, emergency:
TRUE]
THEN
TerminalIO.PutF["%lWARNING: Saved without synchronisation;%l (an other process might have clobbered the IO). \nCopy the file and CHECK it.\n", [rope["b"]], [rope[" "]]];
EXITS oops => NULL;
};
EmergencySaveProcess:
PROC = {
--checks the magic keyboard commands which still work
--when the tip table processes are wedged.
unique: REF;
SaveAllViewers:
PROC [] = {
--This non standard enumeration is chosen so it won't wedge when the standard one would
SaveOneViewer: ViewerOps.EnumProc = {
design: CD.Design = CDViewer.DesignOf[v].design; -- is not monitored
IF design=NIL THEN RETURN;
IF v.newVersion
OR design.changedSinceSaving
THEN
TRUSTED {
Process.Detach[FORK EmergencySaveDesign[design, unique]]
}
};
--I checked the implementation: ViewerOps.EnumerateViewers was really not monitored
unique ← NEW[REF];
ViewerOps.EnumerateViewers[SaveOneViewer];
ViewerOps.EnumerateViewers[SaveOneViewer]; --a second try agains disk errors...
};
virtual: Terminal.Virtual ← InterminalBackdoor.terminal;
CedarProcess.SetPriority[CedarProcess.Priority[foreground]];
DO
-- for ever
Process.PauseMsec[1000];
IF Terminal.GetKeys[virtual][TerminalDefs.ESC]=down AND Terminal.GetKeys[virtual][TerminalDefs.LF]=down THEN StopAllDrawing[];
IF Terminal.GetKeys[virtual][TerminalDefs.Spare3]=down
AND Terminal.GetKeys[virtual][LeftShift]=down
THEN {
StopAllDrawing[];
IF Terminal.GetKeys[virtual][RightShift]=down
THEN {
SaveAllViewers[];
WHILE Terminal.GetKeys[virtual][TerminalDefs.Spare3]=down
OR Terminal.GetKeys[virtual][RightShift]=down
OR Terminal.GetKeys[virtual][LeftShift]=down
DO
Process.PauseMsec[100];
ENDLOOP;
}
}
ENDLOOP;
};
StopAllDrawing:
PROC [] = {
ENABLE RuntimeError.UNCAUGHT => GOTO exit;
FOR l:
LIST
OF CDVPrivate.VRef ← CDVPrivate.allVRefs, l.rest
WHILE l#
NIL
DO
IF l.first.ct#NIL THEN CDDrawQueue.Flush[l.first.ct]
ENDLOOP;
EXITS exit => NULL;
};
StopDrawingCommand:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["Stop drawing (better use <ESC-LF>)\n"];
StopAllDrawing[];
};
doc: Rope.ROPE = "Read a ChipNDale design; options: \n (—|name|^technology) interactive / file name / new design\n (+X|-X) load imports\n (+S|-S) background saving\n (+P|-P) control panel\n (+R|-R) read only design";
openDoc: Rope.ROPE = "Open a ChipNDale design; (read if not present)";
CDEnvironment.RegisterCommander[key: "CDRead", proc: ReadCommand, doc: doc];
CDEnvironment.RegisterCommander[key: "CDOpen", proc: OpenCommand, doc: openDoc];
CDSequencer.ImplementCommand[$OutputDesign, TruthWriteDesignComm,, doQueue];
CDSequencer.ImplementCommand[$CachedOutputDesign, CacheWriteDesignComm,, doQueue];
CDSequencer.ImplementCommand[$SaveDesign, TruthSaveDesignComm,, doQueue];
CDSequencer.ImplementCommand[$StopAllDrawing, StopDrawingCommand,, dontQueue];
CDPanel.Button[tech: NIL, button: [text: "save"], command: $SaveDesign, topLine: TRUE];
TRUSTED {Process.Detach[FORK EmergencySaveProcess[]]};
END.