<> <> <> <> <> DIRECTORY CD, CDCellsInteractions, CDEnvironment, CDDesignCache, CDDirectory, CDImports, CDInstances, CDIO, CDMenuSpecials, CDOps, CDProperties, CDSequencer, IO, Process USING [PauseMsec], RefTab, Rope, SymTab, TerminalIO, TokenIO; CDImportCommands: CEDAR PROGRAM IMPORTS CD, CDCellsInteractions, CDDesignCache, CDDirectory, CDEnvironment, CDImports, CDInstances, CDIO, CDMenuSpecials, CDOps, CDProperties, CDSequencer, IO, Process, RefTab, Rope, SymTab, TerminalIO SHARES CDDirectory, CDImports = BEGIN ROPE: TYPE = Rope.ROPE; ImportSpecific: TYPE = CDImports.ImportSpecific; ImportRep: TYPE = CDImports.ImportRep; CacheListRec: TYPE = CDImports.CacheListRec; Cache: TYPE = CDImports.Cache; CacheList: TYPE = CDImports.CacheList; HasCachedImports: PROC [into: CD.Design] RETURNS [BOOL] = INLINE --gfi-- { cacheL: CDImports.CacheList _ CDImports.GetCacheList[into]; RETURN [cacheL#NIL AND cacheL^#NIL] }; SymTabToKeyList: PROC [ref: SymTab.Ref] RETURNS [list: LIST OF ROPE_NIL] = INLINE --gfi-- { Each: SymTab.EachPairAction = {list _ CONS[key, list]}; [] _ SymTab.Pairs[ref, Each]; }; RequestImporteeName: PROC [into: CD.Design, restrictedToCaches: BOOL_TRUE, fastIfNoChoice: BOOL_FALSE, offerAll: ROPE_NIL] RETURNS [importeeName: ROPE_NIL] = { <<--requests a design name for imports into "into">> <<--restrictedToCaches: >> <<-- FALSE => user may type any name; the name of the selected design is included in list>> <<-- TRUE => only designs having a cache entry in into are allowed>> <<--fastIfNoChoice: >> <<-- FALSE => user sees always an interactive selection querry>> <<-- TRUE => if only a single option exists it is returned without bothering user>> <<--offerAll: offers to say offerAll if there is more than one cached import>> optionsList: LIST OF ROPE; options: SymTab.Ref _ FindAllImportCaches[into]; <<--deal with selected design>> IF ~restrictedToCaches THEN { name: ROPE _ NIL; d: CD.Design _ SelectedDesign[]; IF d#NIL THEN name _ d.name; IF ~Rope.IsEmpty[name] AND ~Rope.Equal[name, into.name] THEN [] _ SymTab.Insert[options, name, name] }; optionsList _ SymTabToKeyList[options]; IF ~Rope.IsEmpty[offerAll] AND optionsList#NIL THEN { optionsList _ CONS[offerAll, optionsList]; }; IF fastIfNoChoice AND restrictedToCaches AND SymTab.GetSize[options]=1 THEN { IF ~Rope.IsEmpty[importeeName] THEN RETURN [importeeName]; }; importeeName _ CDMenuSpecials.SelectOneOf[optionsList, "DESIGN name", ~restrictedToCaches]; }; LoadAndGetCache: PROC [into: CD.Design, importeeName: ROPE_NIL, allwaysNewFile: BOOL_FALSE, forceBind: BOOL _ FALSE, offerAll: BOOL _ FALSE] RETURNS [cache: Cache_NIL, done: BOOL_FALSE] = { checkCalled: BOOL _ FALSE; r, fn: ROPE; design: CD.Design_NIL; loaded: BOOL_FALSE; IF Rope.IsEmpty[importeeName] THEN importeeName _ RequestImporteeName[into: into, restrictedToCaches: FALSE, fastIfNoChoice: FALSE, offerAll: IF offerAll THEN "" ELSE NIL]; IF Rope.IsEmpty[importeeName] THEN { TerminalIO.PutRopes["no design name specified\n"]; RETURN }; IF Rope.Equal[importeeName, ""] THEN { BindAll[into, interactive]; TerminalIO.PutRope[" --\n"]; RETURN [NIL, TRUE]; }; IF Rope.Equal[importeeName, into.name] THEN { TerminalIO.PutRopes["a design can't import itself\n"]; RETURN }; cache _ CDImports.GetCache[into: into, importeeName: importeeName]; IF cache=NIL OR cache.importee=NIL OR allwaysNewFile THEN { menuHeader: ROPE _ Rope.Cat["FILE name for ", importeeName]; menuChoice: LIST OF ROPE _ LIST[importeeName]; IF cache#NIL AND cache.importee#NIL THEN TerminalIO.PutRopes["reload and cache design ", importeeName, "\n"]; fn _ CDDesignCache.MakeUpFile[into, importeeName]; IF ~Rope.IsEmpty[fn] THEN menuChoice _ CONS[fn, menuChoice]; r _ CDMenuSpecials.SelectOneOf[menuChoice, menuHeader, TRUE]; IF Rope.IsEmpty[r] THEN {TerminalIO.PutRope["discarded\n"]; RETURN}; fn _ CDEnvironment.FindFile[r, ".dale", into]; IF Rope.IsEmpty[fn] THEN TerminalIO.PutRopes["file ", r, " not found\n"] ELSE loaded _ CDImports.LoadAndBindDesign[into: into, importeeName: importeeName, forceBind: forceBind, allowConflicts: interactive, useCache: FALSE, fileName: fn, forceFile: TRUE]; IF loaded THEN cache _ CDImports.GetCache[into: into, importeeName: importeeName]; }; done _ cache#NIL; }; <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx binding>> <<>> BindAll: PROC [importerDesign: CD.Design, allowConflicts: CDImports.BoolOrInteractive_false] = { IF CDImports.LoadAndBindAll[into: importerDesign, allowConflicts: allowConflicts, forceBind: FALSE] THEN DescribeUnboundImport[CDImports.HasUnloadedImports[importerDesign].where] ELSE TerminalIO.PutRope[" failed binding all imports\n"]; }; BindAllComm: PROC [comm: CDSequencer.Command] = { <<--hack, called from io commands>> BindAll[comm.design, false]; }; <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx simple imports>> <<>> DrawImportByNameComm: PROC [comm: CDSequencer.Command] = { objectName: ROPE; referenceOb: CD.Object; cache: Cache; TerminalIO.PutRope["draw object of imported design; "]; cache _ LoadAndGetCache[comm.design].cache; IF cache=NIL OR cache.importee=NIL THEN RETURN; objectName _ TerminalIO.RequestRope["object > "]; referenceOb _ CDImports.CreateImportFromCache[into: comm.design, objectName: objectName, importeeName: cache.importeeName]; IF referenceOb=NIL THEN { TerminalIO.PutF[" %g not found in design %g; not done\n", [rope[objectName]], [rope[cache.importeeName]] ]; RETURN }; [] _ CDOps.IncludeObjectI[design: comm.design, ob: referenceOb, location: comm.pos]; }; ImportReadCommand: PROC [comm: CDSequencer.Command] = { cache: Cache; done: BOOL; TerminalIO.PutRope["load (or reload) a design into the import cache\n"]; [cache, done] _ LoadAndGetCache[into: comm.design, importeeName: NIL, allwaysNewFile: TRUE, offerAll: TRUE, forceBind: TRUE]; TerminalIO.PutRope[IF ~done OR (cache#NIL AND cache.importee=NIL) THEN "not done\n" ELSE "done\n"]; }; <<>> <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx default files [hint files] offered to be used>> GetImportFileHints: PROC [for: CD.Design] RETURNS [LIST OF ROPE_NIL] = { IF for#NIL THEN WITH CDProperties.GetDesignProp[for, $ImportHints] SELECT FROM rL: LIST OF ROPE => RETURN [rL]; ENDCASE => NULL; }; ChangeImportFileHint: PROC [for: CD.Design, imp, file: ROPE] = { <<--A future import of design imp into for offers the use of file file >> RemKey: PROC [rl: LIST OF ROPE, key: ROPE] RETURNS [x: LIST OF ROPE_NIL] = { 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; }; rl: LIST OF ROPE _ GetImportFileHints[for]; rl _ RemKey[rl, imp]; file _ CDEnvironment.RemoveSpaces[file]; IF file#NIL THEN rl _ CONS[Rope.Cat[imp, ": ", file], rl]; CDProperties.PutDesignProp[for, $ImportHints, rl]; }; ChangeImportFileHintComm: PROC [comm: CDSequencer.Command] = { importeeName, fileName: ROPE; TerminalIO.PutRope["specify a default file name for a particular import\n"]; importeeName _ RequestImporteeName[into: comm.design, restrictedToCaches: FALSE, fastIfNoChoice: FALSE, offerAll: NIL]; IF Rope.IsEmpty[importeeName] THEN TerminalIO.PutRope["no input design\n"] ELSE { fileName _ TerminalIO.RequestRope["FILE name > "]; ChangeImportFileHint[comm.design, importeeName, fileName]; TerminalIO.PutRope[" ok\n"]; } }; <<>> <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx lists for feedback>> FindAllImportCaches: PROC [design: CD.Design] RETURNS [dList: SymTab.Ref] = { <<--returns SymTab with names of imported designs as keys>> <<--recursively because of indirect imports>> CheckOne: PROC [d: CD.Design] = { IF RefTab.Insert[checked, d, d] THEN { FOR l: LIST OF CDImports.Cache _ CDImports.GetCacheList[d]^, l.rest WHILE l#NIL DO this: CDImports.Cache _ l.first; [] _ SymTab.Insert[dList, this.importeeName, $ok]; IF this.importee#NIL THEN [] _ SymTab.Store[dList, this.importeeName, $notLoaded] ELSE { dd: CD.Design _ CDDesignCache.Fetch[design, this.importeeName]; IF dd=NIL THEN [] _ SymTab.Store[dList, this.importeeName, $notLoaded] ELSE CheckOne[dd]; }; ENDLOOP; }; }; checked: RefTab.Ref _ RefTab.Create[]; dList _ SymTab.Create[]; CheckOne[design]; }; ListUnboundsIndirect: PROC [design: CD.Design] = { where: LIST OF CD.Object _ CDImports.HasUnloadedImports[design].where; IF where#NIL THEN DescribeUnboundImport[where] ELSE TerminalIO.PutRope[" has no [indirect] unbound imported object\n"] }; DisplayCachedDesigns: PROC [comm: CDSequencer.Command] = { ListEach: SymTab.EachPairAction = { cache: CDImports.Cache _ CDImports.GetCache[design, key]; loaded: BOOL _ cache#NIL AND cache.importee#NIL; hasImpDesign _ TRUE; IF ~loaded THEN hasUnloadedDesign _ TRUE; TerminalIO.PutRopes[" ", key, (IF loaded THEN " (cached)\n" ELSE " (not cached)\n")]; RETURN [FALSE] }; DisplayImportFileHints: PROC [for: CD.Design] = { rl: LIST OF ROPE _ GetImportFileHints[for]; IF rl#NIL THEN { key, rest: ROPE _ NIL; TerminalIO.PutRopes["file name hints 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 _ CDEnvironment.RemoveSpaces[rest]; TerminalIO.PutRopes[" design: ", key]; TerminalIO.PutRopes[" file: ", rest, "\n"]; ENDLOOP; }; }; design: CD.Design _ comm.design; hasUnloadedDesign: BOOL _ FALSE; hasImpDesign: BOOL _ FALSE; TerminalIO.PutRopes[CD.DesignName[design], "'s import cache: \n"]; [] _ SymTab.Pairs[FindAllImportCaches[design], ListEach]; IF ~hasImpDesign THEN TerminalIO.PutRope[" has no imported designs in cache\n"]; IF ~hasUnloadedDesign THEN ListUnboundsIndirect[design]; DisplayImportFileHints[design]; TerminalIO.PutRope[" --\n"]; }; DescribeUnboundImport: PROC [where: LIST OF CD.Object, design: CD.Design_NIL] = { Desc1: PROC [lst: LIST OF CD.Object] RETURNS [ROPE] = { RETURN [CD.Describe[lst.first, NIL, IF lst.rest=NIL THEN design ELSE NIL]] }; IF where=NIL THEN RETURN; TerminalIO.PutRopes[" **some imported object is not bound: ", Desc1[where]]; FOR lst: LIST OF CD.Object _ where.rest, lst.rest WHILE lst#NIL DO TerminalIO.PutRopes[" accessed through ", Desc1[lst]]; ENDLOOP; TerminalIO.PutRope["\n"]; }; <<>> DisplayImportsComm: PROC [comm: CDSequencer.Command] = { CheckObject: CDDirectory.EachObjectProc = { WITH me.specific SELECT FROM ip: CDImports.ImportSpecific => IF cache=NIL OR Rope.Equal[ip.designName, cache.importeeName] THEN { totalCount _ totalCount+1; IF cache#NIL THEN TerminalIO.PutF[" %g ", IO.rope[CD.Describe[me, NIL, design]]]; IF ip.boundOb=NIL THEN { unboundCount _ unboundCount+1; TerminalIO.PutRope[" not bound"]; }; TerminalIO.PutRope["\n"]; }; ENDCASE => NULL }; design: CD.Design _ comm.design; totalCount, unboundCount: INT _ 0; importeeName: ROPE; cache: Cache_NIL; cl: CacheList _ CDImports.GetCacheList[design]; IF cl=NIL OR cl.list=NIL THEN { [] _ CDDirectory.EnumerateDesign[design, CheckObject]; IF totalCount=0 THEN TerminalIO.PutRope["design does not have any imported objects\n"] ELSE { TerminalIO.PutF["design has %g imported objects; ", [integer[totalCount]]]; IF unboundCount#0 THEN TerminalIO.PutF["%g not bound\n", [integer[unboundCount]]] ELSE ListUnboundsIndirect[design] }; RETURN; }; importeeName _ RequestImporteeName[into: design, fastIfNoChoice: TRUE, offerAll: ""]; IF Rope.IsEmpty[importeeName] THEN { TerminalIO.PutRope["no design selected\n"]; RETURN; }; IF Rope.Equal[importeeName, ""] THEN { DisplayCachedDesigns[comm]; RETURN }; cache _ CDImports.GetCache[design, importeeName, false]; TerminalIO.PutRopes["design ", importeeName]; IF cache=NIL THEN {TerminalIO.PutRope[" not cached\n"]; RETURN}; IF cache.importee#NIL THEN TerminalIO.PutRope[" cached\n"] ELSE TerminalIO.PutRope[" not cached\n"]; [] _ CDDirectory.EnumerateDesign[design, CheckObject]; IF totalCount=0 THEN TerminalIO.PutRope[" no objects really used\n"] ELSE { TerminalIO.PutF[" %g objects imported from %g\n", [integer[totalCount]], [rope[importeeName]]]; IF unboundCount#0 THEN TerminalIO.PutF[" %g objects not bound\n", [integer[unboundCount]]] ELSE TerminalIO.PutRope[" (all bound, but indirect imports are not checked)\n"] }; }; <<>> <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx inter design copies>> <<>> SelectedDesign: PROC [] RETURNS [CD.Design] = { WITH CDProperties.GetProp[$SelectedDesign, $SelectedDesign] SELECT FROM d: CD.Design => RETURN [d]; ENDCASE => RETURN [NIL]; }; SelectADesign: PROC [comm: CDSequencer.Command] = { TerminalIO.PutRopes["select ", CD.DesignName[comm.design], " as source-design for the command [drawing imports]\n"]; IF Rope.IsEmpty[comm.design.name] THEN TerminalIO.PutRope[" design has no name; not done\n"] ELSE CDProperties.PutProp[$SelectedDesign, $SelectedDesign, comm.design]; }; <<>> InterDesignCopyComm: PROC [comm: CDSequencer.Command] = { inst: CD.Instance; --copy of sourceInst Fail: PROC [r1, r2, r3: ROPE_NIL] = { TerminalIO.PutRope[Rope.Cat[" failed: ", r1, r2, r3, "\n"]]; }; ForwardNormalCopy: PROC [comm: CDSequencer.Command] = { p: CDSequencer.CommandProc _ CDSequencer.FetchCommand[$CopyS].proc; comm.data _ NIL; IF p=NIL THEN Fail["command not available"] ELSE { TerminalIO.PutRope[" forward as simple copy\n"]; CDSequencer.ExecuteProc[p, comm.design, dontQueue, comm]; }; }; IncludeOb: PROC [ob: CD.Object] = { IF ob=NIL THEN Fail["NIL object"] ELSE { [] _ CDOps.IncludeObjectI[design, ob, comm.pos, inst.trans.orient]; TerminalIO.PutRopes[" ", CD.Describe[ob, NIL, design], " included\n"]; }; }; multiple, forceBind: BOOL _ FALSE; design: CD.Design _ comm.design; obName: ROPE; ob: CD.Object; sourceDesign: CD.Design _ NIL; sdName: ROPE; sourceInst: CD.Instance; cache: Cache; TerminalIO.PutRope["interdesign copy\n"]; WITH comm.data SELECT FROM d: CD.Design => sourceDesign _ d; ENDCASE => sourceDesign _ NIL; IF sourceDesign=design THEN {ForwardNormalCopy[comm]; RETURN}; IF sourceDesign=NIL THEN {Fail["source design not found"]; RETURN}; IF sourceDesign.technology#design.technology THEN {Fail["technology missmatch"]; RETURN}; [sourceInst, multiple] _ CDOps.SelectedInstance[sourceDesign]; --asynchronous for source !! IF multiple THEN {Fail["multiple selection in source design"]; RETURN}; IF sourceInst=NIL THEN {Fail["no selection in source design"]; RETURN}; inst _ CDInstances.Copy[sourceInst]; --because of asynchronity problem IF inst.ob=NIL THEN {Fail["asynchronity problem"]; RETURN}; <<--Try atomic objects>> IF ~inst.ob.class.composed OR inst.ob.immutable THEN {IncludeOb[inst.ob]; RETURN}; <<--Object is mutable>> IF ~CDDirectory.IsIncluded[sourceDesign, inst.ob] THEN { ob _ CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign]; IF ob#NIL THEN IncludeOb[ob] ELSE Fail["object is not included in directory"]; RETURN; }; <<--Object is in directory>> obName _ CDDirectory.Name[inst.ob, sourceDesign]; sdName _ sourceDesign.name; IF Rope.IsEmpty[obName] THEN {Fail["object not named"]; RETURN}; IF Rope.IsEmpty[sdName] THEN {Fail["can not cache from un-named design"]; RETURN}; IF Rope.Equal[sdName, design.name] THEN { <<--Designs have equal names; try matching objects from directory first>> ob _ CDDirectory.Fetch[design, obName].object; IF ob#NIL THEN TerminalIO.PutRope[" design names match; use object with same name\n"] ELSE ob _ CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign]; IF ob#NIL THEN IncludeOb[ob] ELSE Fail["object ", obName, " not found in directory"]; RETURN }; <<--Designs have different names; try imports>> IF CDImports.IsImport[inst.ob] THEN { --don't make indirect imports ip: CDImports.ImportSpecific _ NARROW[inst.ob.specific]; ob _ CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign]; IF ob#NIL THEN {IncludeOb[ob]; RETURN} }; cache _ CDImports.GetCache[into: design, importeeName: sdName]; IF cache#NIL AND cache.importee#NIL THEN { <<--already imported design >> IF sourceDesign.edited THEN TerminalIO.PutRope[" use already imported design; ignores edits\n"] ELSE TerminalIO.PutRope[" use already imported design\n"] } ELSE { question: ROPE _ Rope.Concat["import design ", sdName]; Process.PauseMsec[300]; <<--wow!, here 2 design viewers, the terminal and pop up menus will be involved...>> <<--this pause might help to prevent some kind of viewer wedges >> IF sourceDesign.edited THEN question _ Rope.Concat[question, " (edits are ignored)"]; IF ~TerminalIO.Confirm[question] THEN {Fail["gives up"]; RETURN}; }; cache _ LoadAndGetCache[into: design, importeeName: sdName, allwaysNewFile: FALSE, forceBind: forceBind].cache; IF cache=NIL OR cache.importee=NIL THEN {Fail[sdName, " not loaded"]; RETURN}; ob _ CDImports.CreateImportFromCache[into: design, objectName: obName, importeeName: sdName]; IF ob=NIL THEN Fail[obName, " not found"] ELSE IncludeOb[ob]; }; <<>> <<>> <> <> <<>> <> <<--never returns with both foundNamed and foundWithoutChildren set to true>> <<--if not found then message to TerminalIO>> <<--if foundNamed then both, moduleName, objectName # NIL>> <> <> <<};>> <> <> <> <> <> <> <> <> <> <> <<[inst, multiple] _ CDOps.SelectedInstance[from];>> <> <> <> <> <> <> <> <<}>> <> <> <> <> <> <> <> <<}>> <<}>> <<}>> <<}>> <<}>> <<};>> <<>> <> <> <> <> <> <<[foundNamed: foundNamed, foundWithoutChildren: foundWithoutChildren, moduleName: moduleName, objectName: objectName, object: referedOb, orient: orient] _ GlobalSelection[comm.design.technology];>> <> <> <> <> <> <<}>> <> <> <> <> <> <<}>> <<}>> <<};>> <> <> <<[] _ CDOps.IncludeObjectI[comm.design, referenceOb, comm.pos, orient];>> <> <<}>> <<};>> <<>> <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> <<--xx Merge and Un-Merge>> MerginImportCommand: PROC [comm: CDSequencer.Command] = { importeeName: ROPE; cache: Cache; TerminalIO.PutRope["make imports resident [merge in]\n"]; IF ~HasCachedImports[comm.design] THEN { TerminalIO.PutRope["design has no cached imports\n"]; }; Process.PauseMsec[200]; --flush for sure!? importeeName _ RequestImporteeName[into: comm.design, fastIfNoChoice: TRUE]; IF Rope.IsEmpty[importeeName] THEN { TerminalIO.PutRope["no imported design specified\n"]; RETURN }; cache _ CDImports.GetCache[comm.design, importeeName, false]; IF cache=NIL THEN { TerminalIO.PutRopes[importeeName, " not cached; not done\n"]; RETURN } ELSE IF cache.importee=NIL THEN { TerminalIO.PutRopes[importeeName, " no design in cache yet\n"]; IF LoadAndGetCache[comm.design, importeeName].cache=NIL THEN RETURN; IF cache.importee=NIL THEN RETURN; }; CDImports.MergeInImports[into: comm.design, importeeName: importeeName]; TerminalIO.PutRope["end merge\n"]; }; UndoMergeInComm: PROC [comm: CDSequencer.Command] = { replaceList: RefTab.Ref _ RefTab.Create[]; FindObjects: CDDirectory.EachObjectProc = { <<--uses global replaceList>> WITH CDProperties.GetObjectProp[me, $CameFrom] SELECT FROM <<--putting the objectnames in the RefTab keeps them even if replacement is in wrong order>> r: ROPE => [] _ RefTab.Insert[replaceList, me, CDProperties.GetObjectProp[me, $OriginalName]]; ENDCASE => NULL }; ReplaceObjects: RefTab.EachPairAction = { <<--uses globals cache>> quit _ FALSE; WITH val SELECT FROM r: ROPE => { ob: CD.Object _ NARROW[key]; oldName: ROPE _ CDDirectory.Name[ob, design]; new: CD.Object _ CDImports.CreateImportFromCache[into: design, objectName: r, importeeName: cache.importeeName]; IF new#NIL THEN { msg: ROPE; oldRope: ROPE _ CD.Describe[ob, NIL, design, 0]; CDDirectory.ReplaceObject[design, ob, new]; IF oldName#NIL THEN [] _ CDDirectory.Remove[design, oldName, ob]; msg _ IF new.bbox=ob.bbox AND CD.InterestRect[new]=CD.InterestRect[ob] THEN "replaced" ELSE "replaced (size conflict)"; TerminalIO.PutF[" for %g: %g %g by %g\n", IO.rope[r], IO.rope[msg], IO.rope[oldRope], IO.rope[CD.Describe[new, NIL, design, 0]] ]; }; CDSequencer.CheckAborted[design]; }; ENDCASE => NULL }; cache: Cache; design: CD.Design _ comm.design; TerminalIO.PutRope["replace resident objects by imports where possible\n"]; cache _ LoadAndGetCache[comm.design].cache; IF cache=NIL THEN {TerminalIO.PutRope[" not loaded\n"]; RETURN}; [] _ CDDirectory.EnumerateDesign[design, FindObjects]; [] _ RefTab.Pairs[replaceList, ReplaceObjects]; TerminalIO.PutRope[" --\n"]; }; IncludeComm: PROC [comm: CDSequencer.Command] = { MergeIn: PROC [design: CD.Design, from: CD.Design, name: Rope.ROPE_NIL] RETURNS [dummyOb: CD.Object_NIL] = { <<--DANGEROUS PROC>> <<--"from" is transfered to an object, and is included (transitive) to "design"'s directory>> <<--Warning: This procedure destroys "from" >> <<--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>> <<--dummyOb gets nil if "from" 's top level is empty>> <<--technologies must be compatible>> recursiveImports: LIST OF CD.Object _ NIL; 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: "@"]]] }; ChangeOwnerShip: CDDirectory.EachObjectProc = { CDDirectory.SetOwner[design, me, FALSE]; CDProperties.PutObjectProp[me, $CameFrom, from.name]; WITH me.specific SELECT FROM ip: CDImports.ImportSpecific => IF Rope.Equal[ip.designName, design.name] THEN recursiveImports _ CONS[me, recursiveImports]; ENDCASE => NULL; }; IncludeOneEntry: CDDirectory.EachEntryAction = { name _ SkipAt[name]; [] _ CDDirectory.Include[design: design, object: ob, name: name]; CDProperties.PutObjectProp[ob, $OriginalName, name]; }; ReplaceRecursiveImports: PROC [] = { FOR obl: LIST OF CD.Object _ recursiveImports, obl.rest WHILE obl#NIL DO WITH obl.first.specific SELECT FROM ip: CDImports.ImportSpecific => { original: CD.Object _ CDDirectory.Fetch[design, ip.objectName]; IF original#NIL THEN CDDirectory.ReplaceObject[design: design, old: obl.first, new: original]; }; ENDCASE => NULL; ENDLOOP; }; inst: CD.Instance; IF design=from THEN RETURN; IF design.technology#from.technology THEN RETURN WITH ERROR CD.Error[calling, "technology missmatch"]; IF from.mutability#findOut THEN RETURN WITH ERROR CD.Error[calling, "wrong mutability"]; CDSequencer.MarkChangedIOOnly[design]; inst _ CDCellsInteractions.MakeTopInstance[from]; IF inst#NIL THEN dummyOb _ inst.ob; [] _ CDDirectory.EnumerateDesign[design: from, proc: ChangeOwnerShip, dir: TRUE, top: TRUE, recurse: TRUE, dummy: TRUE]; [] _ CDDirectory.Enumerate[design: from, action: IncludeOneEntry]; ReplaceRecursiveImports[]; CDOps.ResetDesign[from]; from.mutability _ inaccessible; }; 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: BOOL _ FALSE; design: CD.Design; ob: CD.Object; srcDesign: Rope.ROPE _ WITH comm.data SELECT FROM r: Rope.ROPE => r, ENDCASE => NIL; TerminalIO.PutRope["include resident copy of input design; \n"]; design _ CDIO.ReadDesign [srcDesign, 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"]; }; [] _ CDProperties.RegisterProperty[$SelectedDesign, $chj]; [] _ CDProperties.RegisterProperty[$ImportHints, $chj]; CDSequencer.ImplementCommand[$DrawImported, DrawImportByNameComm]; CDSequencer.ImplementCommand[$DisplayImportedEntries, DisplayImportsComm,, doQueue]; CDSequencer.ImplementCommand[$ImportADesign, ImportReadCommand]; CDSequencer.ImplementCommand[$SelectADesign, SelectADesign,, doQueue]; CDSequencer.ImplementCommand[$MerginImport, MerginImportCommand]; CDSequencer.ImplementCommand[$UnqueuedLoadAllImps, BindAllComm,, dontQueue]; CDSequencer.ImplementCommand[$ReplaceByImp, UndoMergeInComm]; CDSequencer.ImplementCommand[$ImportDefaultName, ChangeImportFileHintComm]; CDSequencer.ImplementCommand[$UnqueuedCopyInterDesign, InterDesignCopyComm]; CDSequencer.ImplementCommand[$IncludeADesign, IncludeComm,, doQueueAndMark]; END.