<> <> <> <> 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 ROPE _ NIL; 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["", 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: ROPE_NIL, allways: BOOL_FALSE] RETURNS [import: REF ImportDesign_NIL] = { checkCalled: BOOL _ FALSE; 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: BOOL_FALSE; 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 ROPE_NIL] = { IF for#NIL THEN WITH CDProperties.GetDesignProp[for, $ImportHints] SELECT FROM rL: LIST OF ROPE => RETURN [rL]; ENDCASE => NULL; }; RemSpaces: PROC [r: ROPE] RETURNS [ROPE_NIL] = { leng: INT _ Rope.Length[r]; start: INT _ 0; WHILE startstart 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: ROPE _ NIL; 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: ROPE_NIL] = { rl: LIST OF ROPE _ GetHintList[into]; key, rest: ROPE _ NIL; 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 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; }; 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: BOOL_FALSE, foundWithoutChildren: BOOL_FALSE, moduleName: ROPE_NIL, objectName: ROPE_NIL, 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_false] = { <<--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: BOOL _ FALSE; 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] }; <> <> <> <<$loaded imports are recursively checked and changed to $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.