CDImportCommands.mesa (part of ChipNDale)
Copyright © 1984, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, March 20, 1984 5:50:51 pm PST
Last edited by: Christian Jacobi, September 2, 1986 5:20:58 pm PDT
DIRECTORY
CD,
CDEnvironment,
CDDirectory,
CDGenerate,
CDGenerateImports,
CDImports,
CDIO,
CDOps,
CDProperties,
CDRemote,
CDSequencer,
IO,
RefTab,
Rope,
RopeList,
SymTab,
TerminalIO,
UserProfile;
CDImportCommands: CEDAR PROGRAM
IMPORTS CD, CDDirectory, CDEnvironment, CDGenerate, CDGenerateImports, CDImports, CDIO, CDOps, CDProperties, CDRemote, CDSequencer, IO, RefTab, Rope, RopeList, SymTab, TerminalIO, UserProfile
SHARES CDRemote =
BEGIN
ROPE: TYPE = Rope.ROPE;
ImportPtr: TYPE = CDImports.ImportPtr;
ImportRep: TYPE = CDImports.ImportRep;
ImportList: TYPE = CDImports.ImportList;
ImportDesign: TYPE = CDImports.ImportDesign;
RequestImporteeName: PROC [into: CD.Design] RETURNS [importeeName: ROPE] = {
cnt, i: INT ← 0;
rl: LIST OF ROPENIL;
il: LIST OF REF ImportDesign ← CDImports.GetImportList[into]^;
FOR list: LIST OF REF ImportDesign ← il, list.rest WHILE list#NIL AND cnt<20 DO
cnt ← cnt+1;
rl ← CONS[list.first.importeeName, rl];
ENDLOOP;
FOR list: LIST OF ROPE ← GetHintList[into], list.rest WHILE list#NIL AND cnt<20 DO
dname: ROPE ← CDEnvironment.SplitLine[list.first].key;
IF ~RopeList.Memb[rl, dname] THEN {
cnt ← cnt+1;
rl ← CONS[dname, rl];
}
ENDLOOP;
IF rl=NIL THEN i ← 1
ELSE i ← TerminalIO.RequestSelection[choice: CONS["<type name>", rl], label: "DESIGN name"];
IF i=1 THEN importeeName ← TerminalIO.RequestRope["DESIGN name > "]
ELSE IF i>1 AND i<=cnt+1 THEN {
FOR cnt IN [3..i] DO rl ← rl.rest ENDLOOP;
importeeName ← rl.first;
TerminalIO.WriteRopes[" select ", importeeName, "\n"];
}
ELSE ERROR TerminalIO.UserAbort
};
OptionalLoad: PROC [into: CD.Design, importeeName: ROPENIL, allways: BOOLFALSE] RETURNS [import: REF ImportDesign←NIL] = {
checkCalled: BOOLFALSE;
Check: PROC [design: CD.Design] RETURNS [ok: BOOL] = {
n: ROPE;
checkCalled ← TRUE;
IF NOT design.technology=into.technology THEN {
TerminalIO.WriteRopes["technology missmatch: includee is ", design.technology.name, "\n"];
RETURN [ok←FALSE]
};
n ← CDIO.DesignInReadOperation[].name;
IF Rope.IsEmpty[n] THEN {
TerminalIO.WriteRope["design has no name\n"];
RETURN [ok←FALSE]
};
IF Rope.Equal[into.name, n] THEN {
TerminalIO.WriteRope["design can not be imported, it has same name\n"];
RETURN [ok←FALSE]
};
IF ~Rope.Equal[importeeName, n] THEN {
TerminalIO.WriteRopes["file has wrong design: name = ", n, "\n"];
RETURN [ok←FALSE]
};
RETURN [ok←TRUE]
};
nameX, name1, name2: ROPE;
design: CD.Design←NIL;
n: INT; loaded: BOOLFALSE;
IF Rope.IsEmpty[importeeName] THEN {
importeeName ← RequestImporteeName[into];
};
IF Rope.IsEmpty[importeeName] THEN {
TerminalIO.WriteRopes["empty name\n"];
RETURN
};
import ← CDImports.GetImportEntry[into: into, importeeName: importeeName];
IF import=NIL OR ~import.loaded OR allways THEN {
IF Rope.Equal[into.name, importeeName] AND ~Rope.IsEmpty[importeeName] THEN {
TerminalIO.WriteRopes["design ", into.name, " can not be imported, it has same name\n"];
RETURN [NIL]
};
IF import#NIL AND import.loaded THEN TerminalIO.WriteRopes["overload design ", importeeName, "\n"];
nameX ← UseFile[into, importeeName];
IF Rope.IsEmpty[nameX] AND ~Rope.Equal[importeeName, nameX, FALSE] THEN
n ← TerminalIO.RequestSelection[label: Rope.Cat["load design ", importeeName, "; file name->"], choice: LIST["type in", importeeName]]
ELSE
n ← TerminalIO.RequestSelection[label: Rope.Cat["load design ", importeeName, "; file name->"], choice: LIST["type in", importeeName, nameX]];
SELECT n FROM
1 => design ← CDIO.ReadDesign[NIL, Check, CDIO.GetWorkingDirectory[into]];
2 => {
name1 ← CDIO.MakeName[base: importeeName, wDir: CDIO.GetWorkingDirectory[into]];
design ← CDIO.ReadDesign[name1, Check];
IF design=NIL THEN {
name2 ← CDIO.MakeName[base: importeeName, wDir: CDIO.GetWorkingDirectory[NIL]];
IF ~Rope.Equal[name1, name2, FALSE] AND ~checkCalled THEN
design ← CDIO.ReadDesign[name2, Check];
};
};
3 => {
name1 ← CDIO.MakeName[base: nameX, wDir: CDIO.GetWorkingDirectory[into]];
design ← CDIO.ReadDesign[name1, Check];
IF design=NIL THEN {
name2 ← CDIO.MakeName[base: nameX, wDir: CDIO.GetWorkingDirectory[NIL]];
IF ~Rope.Equal[name1, name2, FALSE] AND ~checkCalled THEN
design ← CDIO.ReadDesign[name2, Check];
};
};
ENDCASE => RETURN;
IF design=NIL THEN RETURN;
CDRemote.CacheDesign[into, design];
loaded ← CDImports.Load[into: into, importeeName: importeeName, overload: interactive, allowConflicts: interactive];
IF loaded THEN
RETURN [CDImports.GetImportEntry[into: into, importeeName: importeeName]]
};
};
GetImportedEntryCommand: PROC [comm: CDSequencer.Command] = {
objectName: ROPE;
referenceOb: CD.Object;
import: REF ImportDesign;
TerminalIO.WriteRope["draw object of imported design; "];
import ← OptionalLoad[comm.design];
IF import=NIL OR ~import.loaded THEN RETURN;
objectName ← TerminalIO.RequestRope["entry > "];
referenceOb ← CDImports.CreateImport[into: comm.design, objectName: objectName, importeeName: import.importeeName];
IF referenceOb=NIL THEN {
TerminalIO.WriteRopes[objectName, " not found in design ", import.importeeName];
TerminalIO.WriteRope["; not done\n"];
RETURN
};
CDOps.IncludeObjectI[design: comm.design, ob: referenceOb, location: comm.pos];
};
--============================================================
GetHintList: PROC [for: CD.Design] RETURNS [LIST OF ROPENIL] = {
IF for#NIL THEN
WITH CDProperties.GetDesignProp[for, $ImportHints] SELECT FROM
rL: LIST OF ROPE => RETURN [rL];
ENDCASE => NULL;
};
RemSpaces: PROC [r: ROPE] RETURNS [ROPENIL] = {
leng: INT ← Rope.Length[r];
start: INT ← 0;
WHILE start<leng AND Rope.Fetch[r, start]=' DO start ← start+1 ENDLOOP;
WHILE leng>start AND Rope.Fetch[r, leng-1]=' DO leng ← leng-1 ENDLOOP;
IF leng>start THEN RETURN [Rope.Substr[r, start, leng-start]];
};
DisplayFiles: PROC [for: CD.Design] = {
rl: LIST OF ROPE ← GetHintList[for];
IF rl#NIL THEN {
key, rest: ROPENIL;
TerminalIO.WriteRopes["file names to be used on imports:\n"];
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
[key, rest] ← CDEnvironment.SplitLine[list.first];
rest ← RemSpaces[rest];
TerminalIO.WriteRopes[" design: ", key];
TerminalIO.WriteRopes[" file: ", rest, "\n"];
ENDLOOP;
TerminalIO.WriteRope[" --\n"];
};
};
UseFile: PROC [into: CD.Design, importeeName: ROPE] RETURNS [f: ROPENIL] = {
rl: LIST OF ROPE ← GetHintList[into];
key, rest: ROPENIL;
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
[key, rest] ← CDEnvironment.SplitLine[list.first];
IF Rope.Equal[importeeName, key] THEN RETURN [RemSpaces[rest]];
ENDLOOP;
f ← UserProfile.Token[Rope.Cat["ChipNDale.ImportFor.", importeeName], NIL];
};
RemKey: PROC [rl: LIST OF ROPE, key: ROPE] RETURNS [x: LIST OF ROPENIL] = {
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
IF ~Rope.Equal[CDEnvironment.SplitLine[list.first].key, key] THEN x ← CONS[list.first, x]
ENDLOOP;
};
ChangeDefaultFileName: PROC [for: CD.Design, imp, file: ROPE] = {
rl: LIST OF ROPE ← GetHintList[for];
rl ← RemKey[rl, imp];
file ← RemSpaces[file];
IF file#NIL THEN rl ← CONS[Rope.Cat[imp, ": ", file], rl];
CDProperties.PutDesignProp[for, $ImportHints, rl];
};
ChangeDefaultFileNameComm: PROC [comm: CDSequencer.Command] = {
importeeName, fileName: ROPE;
TerminalIO.WriteRope["set default file for import\n"];
importeeName ← RequestImporteeName[comm.design];
fileName ← TerminalIO.RequestRope["FILE name > "];
ChangeDefaultFileName[comm.design, importeeName, fileName];
TerminalIO.WriteRope[" ok\n"];
};
--============================================================
DisplayImports: PROC [comm: CDSequencer.Command] = {
design: CD.Design ← comm.design;
dList: SymTab.Ref ← SymTab.Create[];
Check: PROC [d: CD.Design] = {
FOR l: LIST OF REF CDImports.ImportDesign ← CDImports.GetImportList[d]^, l.rest WHILE l#NIL DO
[] ← SymTab.Insert[dList, l.first.importeeName, $not];
IF l.first.loaded THEN {
dd: CD.Design ← CDRemote.FetchDesign[design, l.first.importeeName];
IF dd#NIL THEN {
[] ← SymTab.Store[dList, l.first.importeeName, $loaded];
Check[dd];
}
};
ENDLOOP;
};
Each: SymTab.EachPairAction = {
TerminalIO.WriteRopes[" ", key, (IF val=$loaded THEN " +\n" ELSE " -\n")];
RETURN [FALSE]
};
TerminalIO.WriteRopes[comm.design.name, "'s import list: \n"];
Check[comm.design];
[] ← SymTab.Pairs[dList, Each];
TerminalIO.WriteRope[" --\n"];
DisplayFiles[comm.design];
};
DisplayImportedEntries: PROC [comm: CDSequencer.Command] = {
totalCount, unboundCount: INT ← 0;
importeeName: ROPE;
mdata: REF ImportDesign;
TerminalIO.WriteRope["display used entries of imported design\n"];
importeeName ← RequestImporteeName[comm.design];
mdata ← CDImports.GetImportEntry[comm.design, importeeName, false];
TerminalIO.WriteRope[importeeName];
IF mdata=NIL THEN CDSequencer.Quit[" not imported"]
ELSE {
EachObject: CDDirectory.EachEntryAction = {
WITH ob.specificRef SELECT FROM
ip: CDImports.ImportPtr => IF Rope.Equal[ip.designName, mdata.importeeName] THEN {
totalCount ← totalCount+1;
TerminalIO.WriteF[" %g (%g)", IO.rope[name], IO.rope[ip.objectName]];
IF ip.boundInstance=NIL THEN {
unboundCount ← unboundCount+1;
TerminalIO.WriteRope[" not loaded"];
};
TerminalIO.WriteRope["\n"];
};
ENDCASE => NULL
};
IF mdata.loaded THEN TerminalIO.WriteRope[" loaded\n"]
ELSE TerminalIO.WriteRope[" not yet loaded\n"];
[] ← CDDirectory.Enumerate[comm.design, EachObject];
IF totalCount=0 THEN TerminalIO.WriteRope["--- \n import not used anymore\n"]
ELSE {
TerminalIO.WriteF["--- %g objects imported from %g\n", [integer[totalCount]], [rope[importeeName]]];
IF unboundCount#0 THEN TerminalIO.WriteF["=== %g imported objects not loaded\n", [integer[unboundCount]]];
};
};
};
ImportReadCommand: PROC [comm: CDSequencer.Command] = {
import: REF ImportDesign;
TerminalIO.WriteRope["load (or reload) a design for import\n"];
import ← OptionalLoad[comm.design, NIL, TRUE];
TerminalIO.WriteRope[IF import#NIL AND import.loaded THEN "done\n" ELSE "not done\n"];
};
MerginImportCommand: PROC [comm: CDSequencer.Command] = {
importeeName: ROPE;
mdata: REF ImportDesign;
TerminalIO.WriteRope["merge imports into the design\n"];
importeeName ← RequestImporteeName[comm.design];
mdata ← CDImports.GetImportEntry[comm.design, importeeName, false];
IF mdata=NIL THEN {
TerminalIO.WriteRopes[importeeName, " not imported; not done\n"];
RETURN
}
ELSE IF ~mdata.loaded THEN {
TerminalIO.WriteRopes[importeeName, " is not yet loaded\n"];
[] ← OptionalLoad[comm.design, importeeName];
IF ~mdata.loaded THEN RETURN
};
CDImports.MergeInImports[into: comm.design, importeeName: importeeName];
TerminalIO.WriteRope["end merge\n"];
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--multi-design-copy feature
SelectADesign: PROC [comm: CDSequencer.Command] = {
TerminalIO.WriteRopes["select ", comm.design.name, " for inter-design source\n"];
IF Rope.IsEmpty[comm.design.name] THEN
TerminalIO.WriteRopes[" selected design has no name; not done\n"]
ELSE
CDProperties.PutProp[$SelectedDesign, $SelectedDesign, comm.design];
};
SelectedDesign: PROC [] RETURNS [CD.Design] = {
WITH CDProperties.GetProp[$SelectedDesign, $SelectedDesign] SELECT FROM
d: CD.Design => RETURN [d];
ENDCASE => RETURN [NIL];
};
DrawImportedCopy: PROC [comm: CDSequencer.Command] = {
GlobalSelection: PROC [expectedTechnology: CD.Technology] RETURNS [foundNamed: BOOLFALSE, foundWithoutChildren: BOOLFALSE, moduleName: ROPENIL, objectName: ROPENIL, object: CD.Object←NIL, orient: CD.Orientation←CD.original] = {
--never returns with both foundNamed and foundWithoutChildren set to true
--if not found then message to TerminalIO
--if foundNamed then both, moduleName, objectName # NIL
Out: PROC [t: ROPE] = {
TerminalIO.WriteRope[t]
};
from: CD.Design = SelectedDesign[]; -- so it does not change
IF from=NIL THEN Out[" no selected design"]
ELSE {
fromName: ROPE = from.name; -- so it does not change
IF Rope.IsEmpty[fromName] THEN Out[" selected design has no name"]
ELSE IF expectedTechnology#from.technology AND expectedTechnology#NIL THEN
Out[" different technologies"]
ELSE {
ap: CD.Instance; -- the referred application to support the name
multiple: BOOL;
[ap, multiple] ← CDOps.SelectedInstance[from];
IF multiple THEN Out[" multiple selection"]
ELSE IF ap=NIL THEN Out[" no selection"]
ELSE {
orient ← ap.orientation;
IF NOT ap.ob.class.inDirectory THEN {
object ← ap.ob;
foundWithoutChildren ← TRUE;
}
ELSE {
entryName: ROPE = CDDirectory.Name[ap.ob];
IF Rope.IsEmpty[entryName] THEN Out[" object has no name"]
ELSE {
moduleName ← fromName;
objectName ← entryName;
foundNamed ← TRUE;
}
}
}
}
}
};
foundNamed, foundWithoutChildren: BOOL;
moduleName, objectName: ROPE;
referenceOb, referedOb: CD.Object ← NIL;
orient: CD.Orientation;
TerminalIO.WriteRope["draw corresponding object (import); "];
[foundNamed: foundNamed, foundWithoutChildren: foundWithoutChildren, moduleName: moduleName, objectName: objectName, object: referedOb, orient: orient] ← GlobalSelection[comm.design.technology];
IF foundWithoutChildren THEN referenceOb ← referedOb
ELSE IF foundNamed THEN {
IF Rope.Equal[moduleName, comm.design.name] THEN {
TerminalIO.WriteRopes[moduleName, " is selected design; simply copy object\n"];
referenceOb ← CDDirectory.Fetch[comm.design, objectName].object;
}
ELSE {
import: REF ImportDesign ← OptionalLoad[comm.design, moduleName];
IF import#NIL AND import.loaded THEN {
referenceOb ← CDImports.CreateImport[into: comm.design, objectName: objectName, importeeName: moduleName];
IF referenceOb=NIL THEN TerminalIO.WriteF[" %g not found in imported design %g; ", IO.rope[objectName], IO.rope[moduleName]];
}
}
};
IF referenceOb=NIL THEN TerminalIO.WriteRope[" not done\n"]
ELSE {
CDOps.IncludeObjectI[comm.design, referenceOb, comm.pos, orient];
TerminalIO.WriteRopes[CDOps.ObjectInfo[referenceOb], " included\n"];
}
};
LoadAllImps: PROC [importerDesign: CD.Design, allowConflicts: CDImports.BoolOrInteractive�lse] = {
--Tries to import all designs which are used for importerDesign;
--Does not overloade.
--Quite talky on TerminalIO, but not interactive unless parameter specifies
dList: SymTab.Ref ← SymTab.Create[];
Load: PROC [name: ROPE] = {
done: BOOLFALSE;
fileName: ROPE ← UseFile[importerDesign, name];
IF Rope.IsEmpty[fileName] THEN fileName ← name;
CDSequencer.CheckAborted[importerDesign];
[] ← CDRemote.GetTableUsingFile[importerDesign, name, fileName];
CDSequencer.CheckAborted[importerDesign];
done ← CDImports.Load[into: importerDesign, importeeName: name, overload: false, allowConflicts: allowConflicts];
IF done THEN
TerminalIO.WriteRope[" imported"] ELSE TerminalIO.WriteRope[" not imported"];
};
Check: PROC [d: CD.Design] = {
FOR l: LIST OF REF CDImports.ImportDesign ← CDImports.GetImportList[d]^, l.rest WHILE l#NIL DO
[] ← SymTab.Insert[dList, l.first.importeeName, $found]
ENDLOOP;
};
Each: SymTab.EachPairAction = {
IF val=$found THEN {
ie: REF CDImports.ImportDesign ← CDImports.GetImportEntry[importerDesign, key, true];
IF ~ie.loaded THEN Load[key];
[] ← SymTab.Store[dList, key, $loaded];
RETURN [TRUE]
};
IF val=$loaded THEN {
d: CD.Design ← CDRemote.FetchDesign[importerDesign, key];
IF d#NIL THEN Check[d];
[] ← SymTab.Store[dList, key, $finished];
RETURN [TRUE]
};
RETURN [FALSE]
};
enumeration of imports and indirect imports
Check inserts recursive imports to be checked by using the key $found
the enumeration will load imports having a $found key; then the key is changed to $loaded
$loaded imports are recursively checked and changed to $finished
this is repeated until all imports have key $finished
Check[importerDesign];
WHILE SymTab.Pairs[dList, Each] DO ENDLOOP;
};
LoadAllImpsCommand: PROC [comm: CDSequencer.Command] = {
--Load all imports
--Checks first for an userprofile entry;
--checks then for filename=designname
TerminalIO.WriteRope["load all imported designs\n"];
LoadAllImps[comm.design, interactive];
TerminalIO.WriteRope[" --\n"];
};
ReplaceIncludesByImportsComm: PROC [comm: CDSequencer.Command] = {
FindObjects: CDDirectory.EachEntryAction = {
--uses global replaceList
WITH CDProperties.GetObjectProp[ob, $CameFrom] SELECT FROM
--putting the objectnames in the RefTab keeps them even if replacement is in wrong order
r: ROPE => [] ← RefTab.Insert[x: replaceList, key: ob, val: CDProperties.GetObjectProp[ob, $OriginalName]];
ENDCASE => NULL
};
ReplaceObjects: RefTab.EachPairAction = {
--uses globals table and design
quit ← FALSE;
WITH val SELECT FROM
r: ROPE => {
ob: CD.Object ← NARROW[key];
oldName: ROPE ← CDDirectory.Name[ob];
new: CD.Object ← CDGenerate.FetchNCall[table, design, r];
IF new#NIL THEN {
msg: ROPE;
CDDirectory.ReplaceObject[design, ob, new];
IF ~CDDirectory.Remove[design, oldName, ob] THEN [] ← CDDirectory.Rename[design, ob, Rope.Cat["old-", CDDirectory.Name[ob]], TRUE];
msg ← IF new.size=ob.size AND CD.InterestRect[new]=CD.InterestRect[ob]
THEN " replaced" ELSE " replaced (size conflict)";
TerminalIO.WriteF["%g %g by %g\n",
IO.rope[msg],
IO.rope[oldName],
IO.rope[CDDirectory.Name[new]]
];
};
CDSequencer.CheckAborted[design];
};
ENDCASE => NULL
};
replaceList: RefTab.Ref ← RefTab.Create[];
import: REF ImportDesign;
table: CDGenerate.Table;
design: CD.Design ← comm.design;
TerminalIO.WriteRope["replace included objects by imports\n"];
import ← OptionalLoad[comm.design];
IF import=NIL THEN {TerminalIO.WriteRope[" not loded\n"]; RETURN};
table ← CDGenerateImports.GetImportTable[import.importeeName];
[] ← CDDirectory.Enumerate[comm.design, FindObjects];
[] ← RefTab.Pairs[replaceList, ReplaceObjects];
TerminalIO.WriteRope[" --\n"];
};
[] ← CDProperties.RegisterProperty[$SelectedDesign, $chj];
[] ← CDProperties.RegisterProperty[$ImportHints, $chj];
CDSequencer.ImplementCommand[$DrawImported, GetImportedEntryCommand];
CDSequencer.ImplementCommand[$DisplayImports, DisplayImports,, doQueue];
CDSequencer.ImplementCommand[$DisplayImportedEntries, DisplayImportedEntries,, doQueue];
CDSequencer.ImplementCommand[$ImportADesign, ImportReadCommand];
CDSequencer.ImplementCommand[$SelectADesign, SelectADesign,, doQueue];
CDSequencer.ImplementCommand[$DrawCorrespondingObject, DrawImportedCopy];
CDSequencer.ImplementCommand[$MerginImport, MerginImportCommand];
CDSequencer.ImplementCommand[$LoadAllImps, LoadAllImpsCommand,, doQueue];
CDSequencer.ImplementCommand[$ReplaceByImp, ReplaceIncludesByImportsComm];
CDSequencer.ImplementCommand[$ImportDefaultName, ChangeDefaultFileNameComm];
END.