CDIOCommands.mesa
Copyright (C) 1984, 1986 Xerox Corporation. All rights reserved.
Created by: Christian Jacobi, February 8, 1984 9:41 am
Last Edited by: Christian Jacobi, December 19, 1986 11:15:27 am PST
DIRECTORY
CD,
CDEnvironment,
CDCellsInteractions,
CDIO,
CDOps,
CDDirectory,
CDPanel,
CDProperties,
CDSequencer,
CDSimpleRules,
CDValue,
CDViewer USING [CreateViewer],
Commander USING [CommandProc, Register],
CommandTool,
Rope,
TerminalIO,
TokenIO,
UserProfile;
CDIOCommands: CEDAR PROGRAM
IMPORTS CDDirectory, CD, CDCellsInteractions, CDEnvironment, CDIO, CDOps, CDPanel, CDProperties, CDSequencer, CDSimpleRules, CDValue, CDViewer, Commander, CommandTool, Rope, TerminalIO, UserProfile =
BEGIN
IncludeComm: PROC [comm: CDSequencer.Command] = {
Forward: PROC [key: ATOM] = INLINE {
CDSequencer.ExecuteCommand[comm: comm, key: key, queue: dontQueue];
};
yes: BOOL;
TerminalIO.PutRope["include an input design\n"];
TerminalIO.PutRope[" (but usually people want to import other designs)\n"];
yes ← TerminalIO.Confirm[text: "really include!", help: "normally people want to import"];
Forward[IF yes THEN $ReallyIncludeADesign ELSE $Import]
};
MergeIn: PROC [design: CD.Design, from: CD.Design, name: Rope.ROPENIL] RETURNS [ob: CD.Object←NIL] = {
--DANGEROUS PROC
--"from" is transfered to an object, and is included (transitive) to "design"'s directory
--"from" then may be resetted (preserving the rule: any object is in at most one directory)
--the caller is assumed to have the locks of both designs
--if "from" is pushed in, it's merged copy will be popped out, either by flushing,
--replacing or creating new cells
--"name" replaces "from"'s design name for the new created object, but it is a hint only
--the "from"'s object's may change name to avoid conflicts with "design"'s directory
--ob gets nil if "from" 's top level is empty
--technologies must be compatible
SkipAt: PROC [n: Rope.ROPE] RETURNS [Rope.ROPE] = {
--skip everything after and inclusive first "@"
RETURN [Rope.Substr[base: n, len: Rope.SkipTo[s: n, skip: "@"]]]
};
IncludeOneEntry: CDDirectory.EachEntryAction = {
--[name: Rope.ROPE, ob: CD.Object] RETURNS [quit: BOOL�LSE]--
IF NOT CDDirectory.Remove[design: from, name: name, expectObject: ob] THEN ERROR;
[] ← CDDirectory.Include[design: design, object: ob, alternateName: SkipAt[name]];
CDProperties.PutObjectProp[ob, $CameFrom, from.name];
CDProperties.PutObjectProp[ob, $OriginalName, SkipAt[name]];
};
inst: CD.Instance;
IF design=from THEN RETURN;
IF design.technology#from.technology THEN
RETURN WITH ERROR CD.Error[callingError, "MergIn design has different technology"];
inst ← CDCellsInteractions.MakeTopInstance[from];
IF inst#NIL THEN ob ← inst.ob;
[] ← CDDirectory.Enumerate[design: from, action: IncludeOneEntry];
CDOps.ResetDesign[from];
};
ReallyIncludeComm: PROC [comm: CDSequencer.Command] = {
Check: PROC [h: TokenIO.Handle] RETURNS [ok: BOOL] = {
design: CD.Design ← CDIO.DesignInReadOperation[h];
ok ← design.technology=comm.design.technology;
IF NOT ok THEN
TerminalIO.PutRopes["technology miss-match: includee is ", design.technology.name, "\n"];
};
done: BOOLFALSE;
design: CD.Design;
ob: CD.Object;
TerminalIO.PutRope["include input design\n"];
design ← CDIO.ReadDesign[NIL, Check, CDEnvironment.GetWorkingDirectory[comm.design]];
IF design#NIL THEN {
[ob] ← MergeIn[design: comm.design, from: design];
IF ob#NIL THEN {
[] ← CDOps.PlaceInst[comm.design, ob, comm];
done ← TRUE;
};
};
IF done THEN TerminalIO.PutRope["include done\n"]
ELSE TerminalIO.PutRope["include not done\n"];
};
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.ROPENIL; char: CHAR;
loadImports: BOOL ← UserProfile.Boolean["ChipnDale.AutoLoadImports", TRUE];
panelOn, panelOff: BOOLFALSE;
saveOn, saveOff: BOOLFALSE;
alreadyTried: BOOLFALSE;
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;
ENDCASE => {msg ← Rope.Cat["unknown switch ", list.first]; RETURN};
};
char='^ => {--a technology
n: Rope.ROPE ← Rope.Substr[list.first, 1, Rope.Length[list.first]];
tech ← CDSimpleRules.GetTechnology[n];
IF list.rest#NIL OR name#NIL THEN {msg ← "unknown option(s)"; RETURN};
IF tech=NIL THEN 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;
[] ← CDViewer.CreateViewer[design, TRUE, panel];
result ← design;
msg ← Rope.Concat["design ", (IF Rope.IsEmpty[design.name] THEN "no name" ELSE design.name)];
IF saveOff THEN CDProperties.PutDesignProp[design, $CDxDontBackgroundSave, $TRUE];
IF saveOn THEN CDProperties.PutDesignProp[design, $CDxDontBackgroundSave, NIL];
IF 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"};
};
WriteComm: PROC [comm: CDSequencer.Command] = {
done: BOOL;
to: REFNIL;
TerminalIO.PutRope["write design to a file\n"];
IF comm.key=$SaveDesign THEN
to ← CDValue.Fetch[comm.design, $CDxLastFile];
done ← CDIO.WriteDesign[design: comm.design, to: to];
IF done THEN {
CDSequencer.SetEdited[comm.design, FALSE];
TerminalIO.PutRope["done\n"]
}
ELSE {
WITH to SELECT FROM
r: Rope.ROPE => TerminalIO.PutRopes["write to ", r, " "];
ENDCASE => NULL;
TerminalIO.PutRope["not done\n"];
};
IF ~done AND to#NIL AND comm.key=$SaveDesign THEN {
comm.key ← $OutputDesign;
WriteComm[comm];
};
};
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";
Commander.Register[key: "///Commands/CDRead", proc: ReadCommand, doc: doc];
Commander.Register[key: "///Commands/CDOpen", proc: ReadCommand, doc: doc];
CDSequencer.ImplementCommand[$ReallyIncludeADesign, ReallyIncludeComm,, doQueue];
CDSequencer.ImplementCommand[$IncludeADesign, IncludeComm,, doQueue];
CDSequencer.ImplementCommand[$OutputDesign, WriteComm,, doQueue];
CDSequencer.ImplementCommand[$SaveDesign, WriteComm,, doQueue];
CDPanel.DefineButton[tech: NIL, name: "save", command: $SaveDesign, topLine: TRUE];
END.