DIRECTORY BasicTime, CD, CDBasics, CDDesignCache, CDDirectory, CDEvents, CDImports, CDIO, CDOps, CDProperties, CDSequencer, CDValue, CedarProcess, RefTab, Rope, SymTab, TerminalIO, TokenIO; CDImportsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDDirectory, CDDesignCache, CDEvents, CDImports, CDIO, CDOps, CDProperties, CDSequencer, CDValue, CedarProcess, RefTab, Rope, SymTab, TerminalIO, TokenIO EXPORTS CDImports SHARES CDDirectory = BEGIN OPEN CDImports; ROPE: TYPE = Rope.ROPE; Object: TYPE = CD.Object; Design: TYPE = CD.Design; cacheListKey: ATOM = $CacheList; -- a CDValue key importsClass: PUBLIC CD.ObjectClass = CD.RegisterObjectClass[$Import, [ drawMe: DrawForImport, quickDrawMe: QuickDrawReference, showMeSelected: DrawSelectionForImport, internalRead: ReadImportOb, internalWrite: WriteImportOb, describe: DescribeImport, interestRect: ImportIR, xDesign: TRUE ]]; CacheL: TYPE = LIST OF Cache; EnumerateItsObjects: PROC [me: Object, proc: CDDirectory.EachObjectProc, data: REF] RETURNS [quit: BOOL_FALSE] = { }; ReplaceDirectChild: CDDirectory.ReplaceDChildsProc = { }; FetchImport: PUBLIC PROC [into: Design, objectName, importeeName: ROPE] RETURNS [Object_NIL] = { cache: Cache _ GetCache[into, importeeName, false]; IF cache#NIL THEN { WITH SymTab.Fetch[cache.objects, objectName].val SELECT FROM ob1: Object => { IF CDDirectory.CompatibleOwner[into, ob1] THEN RETURN [ob1]; [] _ SymTab.Delete[cache.objects, objectName]; }; ENDCASE => NULL; }; }; CreateImportFromCache: PUBLIC PROC [into: Design, objectName, importeeName: ROPE, load: BOOL] RETURNS [ob: Object_NIL] = { cache: Cache _ GetCache[into, importeeName, IF load THEN true ELSE false]; ob _ FetchImport[into, objectName, importeeName]; IF ob#NIL THEN RETURN [ob]; IF cache#NIL AND cache.importee=NIL AND load THEN [] _ LoadAndBindDesign[into: into, importeeName: importeeName, forceBind: FALSE, allowConflicts: false]; IF cache#NIL AND cache.importee#NIL THEN ob _ CreateImportWithSource[into, objectName, cache.importee, FALSE]; }; CreateImport: PROC [into: Design, objectName, importeeName: ROPE, ir, bbox: CD.Rect, doCache: BOOL_TRUE] RETURNS [ob: Object] = { ob _ NEW[CD.ObjectRep_[ bbox: bbox, class: importsClass, specific: NEW[ImportRep _ [ir: ir, objectName: objectName, designName: importeeName ]] ]]; IF into#NIL THEN { IF doCache THEN { cache: Cache _ GetCache[into, importeeName, true]; IF cache#NIL THEN [] _ SymTab.Store[cache.objects, objectName, ob]; }; CDDirectory.SetOwner[into, ob]; } }; CreateImportWithoutSource: PUBLIC PROC [into: Design, objectName, importeeName: ROPE, ir, bbox: CD.Rect, exact: BoolOrInteractive] RETURNS [ob: Object] = { cache: Cache _ GetCache[into, importeeName, true]; IF ~CDBasics.NonEmpty[bbox] THEN bbox _ ir; IF ~CDBasics.NonEmpty[ir] THEN ir _ bbox; IF exact=true AND ~CDBasics.NonEmpty[ir] THEN RETURN [NIL]; bbox _ CDBasics.Surround[bbox, ir]; ob _ FetchImport[into, objectName, importeeName]; IF ob=NIL AND cache#NIL AND cache.importee#NIL THEN ob _ CreateImportWithSource[into, objectName, cache.importee, FALSE]; IF ob#NIL THEN { IF ob.bbox=bbox AND CD.InterestRect[ob]=ir THEN RETURN [ob]; IF exact=false THEN RETURN [ob]; IF exact#true THEN IF ~ToBool[exact, Rope.Cat["size missmatch for ", CD.Describe[ob], "enforce exact size"]] THEN RETURN [ob]; }; ob _ CreateImport[into, objectName, importeeName, ir, bbox, FALSE]; IF cache#NIL THEN [] _ SymTab.Store[cache.objects, objectName, ob]; }; CreateImportWithSource: PUBLIC PROC [into: Design, objectName: ROPE, source: Design, exact: BOOL] RETURNS [ob: Object] = { obx: Object; IF source.mutability#readonly THEN ERROR CD.Error[calling]; ob _ FetchImport[into, objectName, source.name]; IF ob#NIL THEN { IF ~exact THEN RETURN [ob]; IF NARROW[ob.specific, CDImports.ImportSpecific].boundDesign=source THEN RETURN [ob]; ob _ NIL; }; obx _ CDDirectory.Fetch[source, objectName]; IF obx#NIL THEN { ob _ NEW[CD.ObjectRep_[ class: importsClass, bbox: obx.bbox, specific: NEW[CDImports.ImportRep_[ boundOb: obx, boundDesign: source, ir: CD.InterestRect[obx], objectName: objectName, designName: source.name ]] ]]; IF into#NIL THEN { cache: Cache _ GetCache[into, source.name, true]; IF cache#NIL THEN { [] _ SymTab.Store[cache.objects, objectName, ob]; IF cache.importee=NIL THEN cache.importee _ source; }; CDDirectory.SetOwner[into, ob]; }; }; }; DescribeImport: CD.DescribeProc = { iPtr: ImportSpecific = NARROW[ob.specific]; RETURN [Rope.Cat["reference to ", iPtr.designName, ".", iPtr.objectName]]; }; DrawForImport: CD.DrawProc = { iPtr: ImportSpecific = NARROW[ob.specific]; IF iPtr.boundOb#NIL THEN pr.drawChild[pr, iPtr.boundOb, trans] ELSE { r: CD.Rect = CDBasics.MapRect[CD.InterestRect[ob], trans]; pr.drawRect[pr, r, CD.shadeLayer]; pr.drawComment[pr, r, iPtr.objectName]; } }; QuickDrawReference: CD.DrawProc = { iPtr: ImportSpecific = NARROW[ob.specific]; IF iPtr.boundOb#NIL THEN iPtr.boundOb.class.quickDrawMe[pr, iPtr.boundOb, trans] ELSE { r: CD.Rect = CDBasics.MapRect[CD.InterestRect[ob], trans]; pr.drawRect[pr, r, CD.shadeLayer]; pr.drawComment[pr, r, iPtr.objectName]; } }; DrawSelectionForImport: CD.DrawProc = { iPtr: ImportSpecific = NARROW[ob.specific]; IF iPtr.boundOb#NIL THEN iPtr.boundOb.class.showMeSelected[pr, iPtr.boundOb, trans] ELSE pr.drawOutLine[pr, CDBasics.MapRect[CD.InterestRect[ob], trans], CD.selectionLayer] }; ImportIR: PROC [ob: Object] RETURNS [CD.Rect] = { RETURN [NARROW[ob.specific, ImportSpecific].ir] }; WriteImportOb: CD.InternalWriteProc = { iPtr: ImportSpecific = NARROW[ob.specific]; CDIO.WriteRect[h, ob.bbox]; CDIO.WriteRect[h, iPtr.ir]; TokenIO.WriteRope[h, iPtr.objectName]; TokenIO.WriteRope[h, iPtr.designName]; }; ReadImportOb: CD.InternalReadProc = { bbox, ir: CD.Rect; objectName, importeeName: ROPE; ob: Object; IF CDIO.VersionKey[h] > 15 THEN { bbox _ CDIO.ReadRect[h]; ir _ CDIO.ReadRect[h]; } ELSE { bbox _ CDBasics.RectAt[[0,0], CDIO.ReadPos[h]]; IF CDIO.VersionKey[h] >= 8 THEN ir _ CDIO.ReadRect[h] ELSE ir _ bbox; }; objectName _ TokenIO.ReadRope[h]; importeeName _ TokenIO.ReadRope[h]; ob _ CreateImport[ into: CDIO.DesignInReadOperation[h], ir: ir, bbox: bbox, objectName: objectName, importeeName: importeeName, doCache: TRUE ]; IF ob=NIL THEN ERROR; RETURN [ob] }; GetCacheList: PUBLIC PROC [design: Design] RETURNS [cacheL: CacheList] = { WITH CDValue.Fetch[design, cacheListKey, design] SELECT FROM cacheL: CacheList => RETURN[cacheL]; ENDCASE => { cacheL _ NEW[CacheListRec _ [list: NIL]]; [] _ CDValue.StoreConditional[boundTo: design, key: cacheListKey, value: cacheL]; RETURN [GetCacheList[design]] }; }; NameTest: PROC [into: Design, importeeName: ROPE] RETURNS [fail: BOOL_FALSE] = { IF Rope.IsEmpty[importeeName] THEN { TerminalIO.PutRope["**can't import design with empty name\n"]; RETURN [fail_TRUE] }; IF Rope.Equal[importeeName, into.name] THEN { TerminalIO.PutRopes["**can't make circular imports for ", importeeName, "\n"]; RETURN [fail_TRUE] }; }; CheckNaming: PROC [into: Design, importeeName: ROPE] = INLINE { IF Rope.IsEmpty[importeeName] THEN ERROR CD.Error[ec: other, explanation: "can't import design with empty name"]; IF into#NIL AND Rope.Equal[into.name, importeeName] THEN ERROR CD.Error[ec: other, explanation: "can't import design with equal name"]; }; ToBool: PROC [b: BoolOrInteractive, r, r2: ROPE_NIL] RETURNS [BOOL] = { SELECT b FROM true => RETURN [TRUE]; false => RETURN [FALSE]; ENDCASE => { TerminalIO.PutRopes[r, r2]; RETURN [TerminalIO.Confirm[r]] } }; GetCache: PUBLIC PROC [into: Design, importeeName: ROPE_NIL, createIfNotFound: BoolOrInteractive _ true] RETURNS [cache: Cache_NIL] = { cacheL: CacheList; IF Rope.IsEmpty[importeeName] THEN RETURN [NIL]; IF into=NIL THEN RETURN [NIL]; IF Rope.Equal[into.name, importeeName] THEN RETURN [NIL]; cacheL _ GetCacheList[into]; IF cacheL#NIL THEN FOR l: CacheL _ cacheL.list, l.rest WHILE l#NIL DO IF l.first#NIL AND Rope.Equal[l.first.importeeName, importeeName] THEN RETURN [l.first] ENDLOOP; IF ToBool[createIfNotFound, "create an import", importeeName] THEN { cache _ NEW[CacheRec _ [ importeeName: importeeName, objects: SymTab.Create[] ]]; cacheL.list _ CONS[cache, cacheL.list]; --should be atomic-- }; }; DoCacheDesign: PUBLIC PROC [into: CD.Design, importee: CD.Design] = { cache: Cache _ GetCache[into, importee.name]; IF importee.mutability#readonly THEN ERROR; IF cache#NIL THEN cache.importee _ importee; }; BindDesign: PROC [importer, importee: Design, allowSizeConflicts: BoolOrInteractive _ true, forceBind: BOOL_FALSE] = { done: BOOL _ TRUE; EachObjectProc: CDDirectory.EachObjectProc = { IF CDImports.IsImport[me] THEN { imp: CDImports.ImportSpecific _ NARROW[me.specific]; IF Rope.Equal[imp.designName, importee.name] THEN IF forceBind OR imp.boundOb=NIL THEN IF ~ReBindObject[importer, me, importee, allowSizeConflicts].ok THEN done _ FALSE } }; CheckNaming[importer, importee.name]; IF importer=NIL OR importee=NIL THEN ERROR; IF importee.mutability#readonly THEN ERROR; [] _ CDDirectory.EnumerateDesign[design: importer, proc: EachObjectProc]; IF ~done THEN TerminalIO.PutRopes["some imported object from ", importee.name, " not bound\n"]; CDOps.Redraw[importer]; }; ReBindObject: PUBLIC PROC [design: Design, ob: Object, importee: Design, allowSizeConflicts: BoolOrInteractive _ true] RETURNS [ok: BOOL_FALSE] = { iPtr: ImportSpecific = NARROW[ob.specific, ImportSpecific]; oldIr, newIr, oldBb, newBb: CD.Rect; referedOb: Object _ CDDirectory.Fetch[importee, iPtr.objectName].object; IF referedOb=NIL THEN { TerminalIO.PutF["object %g not found in directory of %g\n", [rope[iPtr.objectName]], [rope[importee.name]] ]; RETURN }; IF ob.immutable THEN { TerminalIO.PutF["can not re-bind immutable object %g\n", [rope[CD.Describe[ob, NIL, design]]] ]; RETURN }; oldIr _ ImportIR[ob]; oldBb _ ob.bbox; newIr _ CD.InterestRect[referedOb]; newBb _ referedOb.bbox; IF newIr=oldIr AND newBb=oldBb THEN { iPtr.boundOb _ referedOb; iPtr.boundDesign _ importee; CDDirectory.PropagateChange[ob, design]; ok _ TRUE; } ELSE { r: ROPE _ IF newIr=oldIr THEN "bounding box miss-match for " ELSE IF newBb=oldBb THEN "interest rect miss-match for " ELSE "bounding box and interest rect miss-match for "; TerminalIO.PutRopes[r, iPtr.objectName, " "]; IF allowSizeConflicts=false THEN { TerminalIO.PutRope["not resolved\n"]; RETURN }; IF allowSizeConflicts=interactive AND ~TerminalIO.Confirm["size conflict; import anyway"] THEN { TerminalIO.PutRope["don't resolve\n"]; RETURN }; IF OccursInDrawing[ob, referedOb] THEN { TerminalIO.PutF["re-binding %g would cause circularity; object not bound\n", [rope[CD.Describe[ob]]] ]; RETURN }; iPtr.boundOb _ referedOb; iPtr.boundDesign _ importee; ob.bbox _ newBb; iPtr.ir _ newIr; IF newIr=oldIr THEN { trans: CD.Transformation _ [[oldIr.x1-newIr.x1, oldIr.y1-newIr.y1], original]; TerminalIO.PutRopes[" keep interest rect at constant position\n"]; CDDirectory.ReplaceObject[design, ob, ob, trans]; } ELSE { TerminalIO.PutRopes[" keep origin at constant position\n"]; CDDirectory.PropagateResize[design, ob]; }; CDDirectory.PropagateChange[ob, design]; ok _ TRUE; }; }; EnsureCacheing: PROC [into: Design] = { EachObjectProc: CDDirectory.EachObjectProc = { IF CDImports.IsImport[me] THEN { imp: CDImports.ImportSpecific _ NARROW[me.specific]; cache: Cache _ GetCache[into, imp.designName, true]; IF cache#NIL THEN [] _ SymTab.Insert[cache.objects, imp.objectName, me]; } }; [] _ CDDirectory.EnumerateDesign[design: into, proc: EachObjectProc]; }; LoadAndBindDesign: PUBLIC PROC [into: Design, importeeName: ROPE, allowConflicts: CDImports.BoolOrInteractive_true, forceBind: BOOL_FALSE, useCache: BOOL_FALSE, fileName: Rope.ROPE_NIL, forceFile: BOOL_FALSE] RETURNS [done: BOOL_FALSE] = { Check: CDDesignCache.CheckProc = { ok _ TRUE; -- ??? ~HasUnloadedImports[design].yes }; indirectCaches: CacheList; importee: Design; cache: Cache; time: BasicTime.GMT _ BasicTime.nullGMT; IF into=NIL OR NameTest[into, importeeName].fail THEN RETURN [done_FALSE]; IF ~forceFile THEN importee _ CDDesignCache.Fetch[into, importeeName]; IF importee=NIL OR ~useCache THEN { importee _ CDDesignCache.GetOrRead[for: into, remoteName: importeeName, remoteFile: fileName, reload: ~useCache, checkFile: TRUE, check: Check].remote; }; IF importee=NIL THEN { TerminalIO.PutRopes["load import ", importeeName, " not done\n"]; RETURN [FALSE] }; EnsureCacheing[importee]; EnsureCacheing[into]; indirectCaches _ GetCacheList[importee]; IF indirectCaches^.list#NIL THEN TerminalIO.PutRope["there are indirect imports\n"]; cache _ GetCache[into, importeeName, true]; IF cache=NIL THEN RETURN [done_FALSE]; cache.importee _ importee; BindDesign[importer: into, importee: importee, allowSizeConflicts: allowConflicts, forceBind: forceBind]; FOR list: CacheL _ GetCacheList[into]^, list.rest WHILE list#NIL DO IF ~Rope.Equal[list.first.importeeName, importeeName] AND list.first.importee#NIL THEN { cache: Cache _ GetCache[list.first.importee, importeeName, false]; IF cache#NIL THEN { IF cache.importee=NIL OR forceBind THEN cache.importee _ importee; }; BindDesign[importer: list.first.importee, importee: importee, allowSizeConflicts: false, forceBind: forceBind]; } ENDLOOP; FOR list: CacheL _ indirectCaches^, list.rest WHILE list#NIL DO iCache: Cache _ list.first; IF ~Rope.Equal[iCache.importeeName, into.name] THEN { originalCache: Cache _ GetCache[into, iCache.importeeName, true]; IF originalCache#NIL THEN iCache.importee _ originalCache.importee; IF iCache.importee#NIL THEN BindDesign[importer: importee, importee: iCache.importee, allowSizeConflicts: false]; } ENDLOOP; done _ TRUE; }; LoadAndBindAll: PUBLIC PROC [into: CD.Design, allowConflicts: BoolOrInteractive_true, forceBind: BOOL_FALSE] RETURNS [done: BOOL_FALSE] = { done1: BOOL_TRUE; CheckOne: PROC [d: CD.Design] = { IF d#NIL THEN FOR list: CacheL _ GetCacheList[d]^, list.rest WHILE list#NIL DO [] _ SymTab.Insert[toTreat, list.first.importeeName, $y]; ENDLOOP; }; TreatOne: SymTab.EachPairAction = { name: Rope.ROPE _ key; cache: Cache; IF SymTab.Fetch[treated, name].found THEN RETURN; CedarProcess.CheckAbort[NIL]; IF CDSequencer.Aborted[into] THEN { TerminalIO.PutRope["interrupted\n"]; done1 _ FALSE; [] _ SymTab.Erase[toTreat]; RETURN [quit _ TRUE]; }; IF ~LoadAndBindDesign[into: into, importeeName: name, allowConflicts: allowConflicts, forceBind: forceBind, useCache: TRUE] THEN { done1 _ FALSE }; IF ~Rope.Equal[into.name, name] THEN { cache _ GetCache[into, name]; IF cache#NIL THEN CheckOne[cache.importee]; }; [] _ SymTab.Insert[treated, name, $x]; quit _ TRUE; }; toTreat: SymTab.Ref _ SymTab.Create[]; treated: SymTab.Ref _ SymTab.Create[]; EnsureCacheing[into]; CheckOne[into]; WHILE SymTab.Pairs[toTreat, TreatOne] DO {} ENDLOOP; done _ done1; }; DesignRenameEventProc: CDEvents.EventProc = { newName: Rope.ROPE _ NIL; WITH x SELECT FROM r: Rope.ROPE => newName _ r; ENDCASE => NULL; IF design=NIL THEN RETURN; IF design.mutability=readonly THEN { TerminalIO.PutF["don't rename design %g to %g; it is read only\n", [rope[design.name]], [rope[newName]]]; RETURN [dont _ TRUE]; }; IF newName#NIL THEN { cache: Cache _ GetCache[design, newName, false]; IF cache#NIL THEN { TerminalIO.PutF["don't rename design %g to %g; it would create circular imports or caching problems\n", [rope[design.name]], [rope[newName]]]; RETURN [dont _ TRUE]; }; }; }; LocalCopy: PUBLIC PROC [into: Design, import: Object] RETURNS [Object] = { InRepList: PROC [rl: CDDirectory.ReplaceList, ob: Object] RETURNS [BOOL_FALSE] = { FOR list: CDDirectory.ReplaceList _ rl, list.rest WHILE list#NIL DO IF list.first.old=ob THEN RETURN [TRUE]; ENDLOOP; }; ReplaceChildrenByImports: PROC [me: Object, design: Design, fromDesign: Design] = { replaceList: CDDirectory.ReplaceList _ NIL; PerChild: CDDirectory.EachObjectProc = { child: Object; IF me.class.composed THEN { IF InRepList[replaceList, me] THEN RETURN; -- eliminate duplicates IF CDDirectory.IsIncluded[fromDesign, me] THEN { child _ CreateImportWithSource[into: design, objectName: CDDirectory.Name[me, fromDesign], source: fromDesign, exact: FALSE]; IF child=NIL OR CD.InterestRect[child]#CD.InterestRect[me] OR child.bbox#me.bbox THEN child _ CreateImportWithoutSource[into: design, objectName: CDDirectory.Name[me, fromDesign], importeeName: fromDesign.name, ir: CD.InterestRect[me], bbox: me.bbox, exact: true]; IF child=NIL THEN ERROR; } ELSE { ca: BOOL; [child, ca] _ CDDirectory.Another1[me: me, fromOrNil: fromDesign, into: design]; IF child=NIL THEN ERROR; IF ~ca THEN ReplaceChildrenByImports[me: me, design: design, fromDesign: fromDesign]; }; replaceList _ CONS[NEW[CDDirectory.ReplaceRec_[old: me, new: child]], replaceList]; } }; [] _ CDDirectory.EnumerateChildObjects[me: me, proc: PerChild]; IF replaceList#NIL THEN [] _ CDDirectory.ReplaceDirectChild[me: me, design: design, replace: replaceList]; }; --ReplaceChildrenByImports WITH import.specific SELECT FROM impPtr: ImportSpecific => { newOb: Object; ca: BOOL; IF impPtr.boundDesign=NIL THEN ERROR; [newOb, ca] _ CDDirectory.Another1[me: impPtr.boundOb, fromOrNil: impPtr.boundDesign, into: into]; IF newOb=NIL THEN ERROR; IF ~ca THEN ReplaceChildrenByImports[me: newOb, design: into, fromDesign: impPtr.boundDesign]; RETURN [newOb] }; ENDCASE => ERROR CD.Error[calling, "bad object class"] }; Another1: PROC [me: Object, fromOrNil: Design, into: Design, friendly: BOOL] RETURNS [new: CD.Object_NIL, childAccessible: BOOL_TRUE] = { impPtr: ImportSpecific = NARROW[me.specific]; own: REF; IF into=fromOrNil AND into#NIL THEN RETURN [me, TRUE]; IF into#NIL THEN { IF into=impPtr.boundDesign AND impPtr.boundOb#NIL THEN { RETURN [new_impPtr.boundOb, childAccessible_TRUE]; }; IF Rope.Equal[into.name, impPtr.designName] THEN { x: CD.Object _ CDDirectory.Fetch[into, impPtr.objectName]; IF x#NIL THEN { new _ x; childAccessible _ TRUE }; RETURN; }; }; new _ FetchImport[into: into, objectName: impPtr.objectName, importeeName: impPtr.designName]; IF new=NIL AND impPtr.boundOb#NIL AND impPtr.boundDesign#NIL THEN new _ CreateImportWithSource[into: into, objectName: impPtr.objectName, source: impPtr.boundDesign, exact: FALSE]; IF new=NIL OR impPtr.ir#CD.InterestRect[new] OR me.bbox#new.bbox THEN new _ CreateImportWithoutSource[into: into, objectName: impPtr.objectName, importeeName: impPtr.designName, ir: impPtr.ir, bbox: me.bbox, exact: true]; IF new=NIL THEN { cache: Cache _ GetCache[into, impPtr.designName, true]; new _ NEW[CD.ObjectRep _ [ bbox: impPtr.boundOb.bbox, class: importsClass, layer: CD.undefLayer, specific: NEW[ImportRep _ impPtr^] ]]; IF cache#NIL THEN { [] _ SymTab.Store[cache.objects, impPtr.objectName, new]; IF cache.importee=NIL THEN cache.importee _ impPtr.boundDesign; CDDirectory.SetOwner[into, new]; } }; IF new#me THEN { own _ CDProperties.GetObjectProp[new, $OwnerDesign]; CDProperties.AppendProps[looser: me.properties, winner: new.properties, putOnto: new]; CDProperties.PutObjectProp[new, $OwnerDesign, own]; }; }; Expand: PROC [me: CD.Object, fromOrNil: CD.Design_NIL, into: CD.Design_NIL, friendly: BOOL_FALSE] RETURNS [new: CD.Object_NIL, topAccessible: BOOL_FALSE, childAccessible: BOOL_FALSE] = { impPtr: ImportSpecific = NARROW[me.specific]; IF impPtr.boundOb=NIL THEN RETURN []; --can not expand unloaded object IF into#NIL --AND friendly-- THEN { [me, childAccessible] _ CDDirectory.Another1[me: me, fromOrNil: fromOrNil, into: into]; IF me#NIL THEN { IF ~CDImports.IsImport[me] THEN RETURN [me, TRUE, childAccessible]; new _ LocalCopy[import: me, into: into]; IF new#NIL THEN RETURN [new, TRUE, TRUE]; }; }; RETURN [impPtr.boundOb, FALSE, FALSE]; }; DeleteListFromSymTab: PROC [ref: SymTab.Ref, list: LIST OF ROPE] = { FOR l: LIST OF ROPE _ list, l.rest WHILE l#NIL DO [] _ SymTab.Delete[ref, l.first]; ENDLOOP }; MergeInImports: PUBLIC PROC [into: Design, importeeName: ROPE] = { ListFirst: CDDirectory.EachObjectProc = { WITH me.specific SELECT FROM imp: CDImports.ImportSpecific => IF imp.boundOb#NIL AND Rope.Equal[imp.designName, importeeName, TRUE] THEN obList _ CONS[me, obList]; ENDCASE => {}; }; PutCache: CDDirectory.PutInCacheProc = { CDProperties.PutObjectProp[cacheOb, $CameFrom, importeeName]; CDProperties.PutObjectProp[cacheOb, $OriginalName, CDDirectory.Name[forOb, NARROW[data]]]; }; RenameEachObject: RefTab.EachPairAction ~ { new: CD.Object = NARROW [val]; newName: Rope.ROPE = NARROW [CDProperties.GetObjectProp[new, $OriginalName]]; IF NOT RefTab.Insert[alreadyRenamed, new, NIL] THEN RETURN; -- already seen IF Rope.IsEmpty[newName] THEN RETURN; -- initial object was not named, don't bother IF NOT CDDirectory.Include[into, new, newName, FALSE] THEN TerminalIO.PutF["*** %g.%g not included in directory of %g\n", [rope[importeeName]], [rope[newName]], [rope[intoName]]]; }; obList: LIST OF CD.Object _ NIL; objectCache: RefTab.Ref _ RefTab.Create[]; cache: Cache _ GetCache[into, importeeName, false]; intoName: Rope.ROPE = CD.DesignName[into]; alreadyRenamed: RefTab.Ref _ RefTab.Create[]; [] _ CDDirectory.EnumerateDesign[design: into, proc: ListFirst]; -- build list of bound imports FOR ol: LIST OF CD.Object _ obList, ol.rest WHILE ol#NIL DO -- list contains only bound imports imp: CDImports.ImportSpecific = NARROW [ol.first.specific]; new: CD.Object = CDDirectory.AnotherRecursed[me: imp.boundOb, into: into, fromOrNil: imp.boundDesign, cx: objectCache, putInCache: PutCache, data: imp.boundDesign]; IF new=NIL THEN LOOP; -- some problem occured CDDirectory.ReplaceObject[design: into, old: ol.first, new: new]; IF cache#NIL THEN [] _ SymTab.Delete[cache.objects, imp.objectName]; ENDLOOP; [] _ RefTab.Pairs[objectCache, RenameEachObject]; -- try renaming all new objects TerminalIO.PutF["%g objects merged in from %g into %g\n", [integer[RefTab.GetSize[alreadyRenamed]]], [rope[importeeName]], [rope[intoName]]]; RefTab.Erase[objectCache]; RefTab.Erase[alreadyRenamed]; }; HasUnloadedImports: PUBLIC PROC [design: Design, object: CD.Object_NIL, recurse: BOOL_TRUE] RETURNS [yes: BOOL_FALSE, where: LIST OF Object_NIL] = { checked: RefTab.Ref _ RefTab.Create[]; EachObjectProc: CDDirectory.EachObjectProc = { IF me.class.xDesign THEN { WITH me.specific SELECT FROM imp: CDImports.ImportSpecific => { IF imp.boundOb=NIL THEN {quit _ TRUE; where _ CONS[me, where]} ELSE IF recurse THEN { where _ CONS[me, where]; quit _ CDDirectory.EnumerateObject[ob: imp.boundOb, proc: EachObjectProc, visited: checked]; IF ~quit THEN { [] _ RefTab.Insert[checked, imp.boundOb, NIL]; where _ where.rest } }; } ENDCASE => { TerminalIO.PutRopes[CD.Describe[me], " is funny class; we dont know how to check this class for unloaded imports\n"]; }; }; }; IF design#NIL THEN yes _ CDDirectory.EnumerateDesign[design: design, proc: EachObjectProc, visited: checked]; IF object#NIL AND ~yes THEN yes _ EachObjectProc[object]; }; OccursInDrawing: PUBLIC PROC [x: CD.Object, in: CD.Object] RETURNS [yes: BOOL_FALSE] = { h: REF HandleRec ~ NEW[HandleRec _ [seen: RefTab.Create[], x: x]]; pr: CD.DrawRef ~ CD.CreateDrawRef[[drawChild: PrunedDrawChild, devicePrivate: h]]; CD.DrawOb[pr, in ! found => {yes_TRUE; CONTINUE}]; }; found: ERROR = CODE; HandleRec: TYPE = RECORD [seen: RefTab.Ref, x: CD.Object]; PrunedDrawChild: CD.DrawProc = { h: REF HandleRec _ NARROW[pr.devicePrivate]; IF ob=h.x THEN ERROR found; IF ob.class.composed AND RefTab.Insert[h.seen, ob, $x] THEN CD.DrawOb[pr: pr, ob: ob, trans: trans, readOnlyInstProps: readOnlyInstProps]; }; DirectoryOp: PROC [me: Object, design: Design, name: ROPE, function: CDDirectory.DirectoryFunction] = { IF design#NIL AND function#remove THEN { iPtr: ImportSpecific = NARROW[me.specific]; cache: Cache _ GetCache[design, iPtr.designName, true]; IF cache#NIL THEN [] _ SymTab.Insert[cache.objects, iPtr.objectName, me]; }; }; FindCachedDesign: PUBLIC PROC [designName: Rope.ROPE, fileName: Rope.ROPE_NIL, createdTime: BasicTime.GMT _ BasicTime.nullGMT, checkUnloadedImps: BOOL_FALSE] RETURNS [found: CD.Design_NIL] = { Check: CDDesignCache.CheckProc = { ok _ ~checkUnloadedImps OR ~HasUnloadedImports[design].yes }; RETURN [CDDesignCache.Search[designName, fileName, createdTime, Check]] }; dirProcs: REF CDDirectory.DirectoryProcs ~ CDDirectory.InstallDirectoryProcs[importsClass, [ directoryOp: DirectoryOp, enumerateChildObjects: EnumerateItsObjects, replaceDirectChilds: ReplaceDirectChild, another: Another1, expand: Expand ]]; CDValue.RegisterKey[cacheListKey]; CDEvents.RegisterEventProc[$BeforeRenameDesign, DesignRenameEventProc]; END. $CDImportsImpl.mesa (part of ChipNDale) Copyright c 1984, 1986, 1987 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, March 20, 1984 5:50:51 pm PST Last edited by: Christian Jacobi, October 19, 1987 2:24:28 pm PDT Jean-Marc Frailong December 3, 1987 7:41:45 pm PST dont !!! the imported objects are not accessible for this design can't replace children the imported objects are not accessible for this design --get the entry in design into telling about importing importeeName --No caching involved --No caching involved --everything is ok --size conflict --check whether we should continue binding --XXX check circularity --continue binding --interest rects match; not only size but also location! in this case we assume --that it might (probably, but not always) be a conversion problem from cd23 --enumerates design to make sure it has caches for all direct imports -- bind --check all already imported designs for importing the new design --check the new design for importing of already imported and loaded designs --The test for circular imports is too weak: it recognizes problems only when imports are --cached. However, in case of interactive operations imports will be cached; bad use from --programs does not worry me, since the programs can be rerun after fixing. --In case of empty caching: too bad write the design and read it in again, then the cache --will be gone --imp is an imported and bound object which will be made local to design --but makes copy of children which are not importable because they don't have a name --build list of direct children --replace each direct child by an import --LocalCopy --Don't; we better give the real thing back [new, childAccessible] _ CDDirectory.Another1[me: impPtr.boundOb, fromOrNil: impPtr.boundDesign, into: into, friendly: friendly]; --what about a bbox, ir check? --Don't; we better give the real thing back [new, childAccessible] _ CDDirectory.Another1[me: x, fromOrNil: into, into: into, friendly: friendly]; --Includes all the imported and bound objects from importeeName (including --their transitive closure; but not indirect imports) into design. --this is a separate step because we want to modify and enumerate directory independent Try to register the import's local copies under their import name if it is possible Κγ˜codešœ(™(Kšœ Οmœ=™HKšœ;™;K™BK™2K˜—šΟk ˜ Kšœ ž˜ Kšžœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšžœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—K˜šΟn œžœžœ˜Kšžœžœ'˜1Kšœžœd˜}Kšžœ ˜Kšžœ˜—Kšžœžœ ˜K˜Kšžœžœžœ˜Kšœžœžœ˜Kšœžœžœ˜K˜KšœžœΟc˜1K˜šœžœžœžœ˜GKšœ˜Kšœ ˜ Kšœ'˜'Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ž˜ Kšœ˜—K˜Kšœžœžœžœ˜K˜š Ÿœžœ6žœžœžœžœ˜rKšœ ™ Kšœ7™7Kšœ˜—K˜šΠbnœ%˜7K™Kšœ7™7Kšœ˜—K˜š Ÿ œžœžœ*žœžœ žœ˜`Kšœ3˜3šžœžœžœ˜šžœ-žœž˜<šœ˜Kšžœ(žœžœ˜žœ˜E—Kšœ˜—K˜šŸ œžœ*žœ žœžœžœžœ˜šœžœžœ ˜Kšœ ˜ Kšœ˜šœ žœ˜"Kšœ1˜1Kšœ˜—Kšœ˜—šžœžœžœ˜šžœ žœ˜Kšœ2˜2Kšžœžœžœ2˜CK˜—Kšœ˜K˜—K˜—K˜š Ÿœžœžœ*žœ žœ!žœ˜›Kšœ2˜2Kšžœžœ ˜+Kšžœžœ ˜)Kš žœ žœžœžœžœ˜;Kšœ#˜#Kšœ1˜1š žœžœžœžœžœžœž˜3Kšœ>žœ˜E—šžœžœžœ˜Kš žœžœžœžœžœ˜šžœ˜Kšœžœžœ˜:Kšœžœ ˜"Kšœ'˜'K˜—Kšœ˜—K˜šŸœžœ ˜#Kšœžœ˜+šžœžœžœ˜Kšœ7˜7—šžœ˜Kšœžœžœ˜:Kšœžœ ˜"Kšœ'˜'K˜—Kšœ˜K˜—šŸœžœ ˜'Kšœžœ˜+šžœžœžœ˜Kšœ:˜:—šžœ˜Kšœ$žœžœ˜S—Kšœ˜—K˜šŸœžœžœžœ ˜1Kšžœžœ!˜/Kšœ˜K˜—š‘ œžœ˜'Kšœžœ˜+Kšžœ˜Kšžœ˜Kšœ&˜&Kšœ&˜&Kšœ˜—K˜š‘ œžœ˜%Kšœ žœ!žœ ˜>šžœžœžœ˜!Kšœžœžœ ˜/K˜—šžœ˜Kšœžœ ˜/Kšžœžœžœžœ ˜6Kšžœ ˜K˜—Kšœ!˜!Kšœ#˜#šœ˜Kšœžœ˜%Kšœ˜Kšœ3˜3Kšœ ž˜ K˜—Kšžœžœžœžœ˜Kšžœ˜ Kšœ˜—K˜šŸ œžœžœžœ˜Jšžœ-žœž˜žœž˜Q——K˜—K˜—K˜Kšœ%˜%Kš žœ žœžœ žœžœžœ˜+Kšžœžœžœ˜+KšœI˜Išžœžœ˜KšœQ˜Q—Kšœ˜Kšœ˜—K˜š Ÿ œž œ^žœžœžœ˜“Kšœ™Kšœžœ˜;Kšœžœ˜$KšœH˜Hšžœ žœžœ˜šœ<˜šžœžœ žœ˜Kšœžœ ˜Kšœ\˜\šžœžœ˜Kšœ)žœ˜.Kšœ˜K˜—K˜—K˜—šžœ˜ Kšœžœ_˜uK˜——K˜—K˜—šžœžœžœ˜KšœZ˜Z—šžœžœžœžœ˜Kšœ˜—K˜—K˜šŸœžœžœžœ žœ žœžœžœ˜XKšœžœ žœ,˜BKšœžœ žœ?˜RKšžœžœžœ˜2Kšœ˜K˜Kšœžœžœ˜Kšœ žœžœžœ ˜:š‘œžœ ˜ Kšœžœ žœ˜,Kšžœžœžœ˜šžœžœžœ˜