<> <> <> DIRECTORY Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDImports, CDLayers, CDOps, CDPanel, CDPanelFonts, CDPopUpMenus, CDProperties, CDRects, CDSatellites, CDTexts, CDSequencer, CDSequencerExtras, CDValue, CDViewer, Core, CoreOps, SymTab, IO, PopUpMenus, PopUpSelection, RefTab, RegularExpression, Rope, Sisyph, TerminalIO, TextOps, ViewerClasses, ViewerOps; TextOpsImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDImports, CDLayers, CDOps, CDPanel, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDSequencerExtras, CDTexts, CDValue, CDViewer, IO, CDPopUpMenus, CoreOps, PopUpSelection, SymTab, RefTab, RegularExpression, Rope, Sisyph, TerminalIO, ViewerOps SHARES CDCellCommands, CDPopUpMenus = BEGIN <> TSPType: TYPE = TextOps.TSPType; firstInvisible: TSPType = expr; tspNms: ARRAY TSPType OF IO.ROPE _ [ text: "Text", sat: "Satellite", expr: "Expression", -- firstInvisible name: "Name", iForC: "Icon Code", iForS: "Icon Sch", extract: "Extract Proc", virus: "Prop Virus", any: "ANY" ]; tspNms3: ARRAY TSPType OF IO.ROPE _ [ text: "text", sat: "sat", expr: "expr", name: "name", iForC: "code", iForS: "schm", extract: "extr", virus: "virus", any: "any" ]; tspProps: ARRAY TSPType OF ATOM _ [ text: NIL, sat: NIL, expr: $SisyphExpressions, name: $SignalName, iForC: $CodeFor, iForS: $IconFor, extract: $SisyphExtractProc, virus: $CDBringoverLibraryName, any: NIL]; Finder: TYPE = RegularExpression.Finder; InstProc: TYPE = PROC[inst: CD.Instance] RETURNS[quit: BOOL _ FALSE]; InstObProc: TYPE = PROC[inst: CD.Instance, ob: CD.Object] RETURNS[quit: BOOL _ FALSE]; ObjProc: TYPE = PROC[obj: CD.Object] RETURNS[quit: BOOL _ FALSE]; Signal: SIGNAL[msg: IO.ROPE] = CODE; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[] _ CDCellsInteractions.PopFromCell[comm.design, interactive] ENDLOOP;>> <> <<[] _ ScanAll[comm.design, top, TRUE, FALSE, DoInst, DoObject];>> <> <<>> InitTextScanPropPanel: PROC = { tech: CD.Technology _ CD.FetchTechnology[$cmosB]; panelHeight: INT _ CDValue.FetchInt[tech, $PanelHeight, global, 120]; CDValue.Store[tech, $TextScanProp, NEW[TSPType _ text]]; CDValue.Store[tech, $TextScanPropNm, tspNms[text]]; CDPanel.Button[button: [text: "search", xpos: 0], command: $TextOpsSearch, tech: tech]; CDPanel.Button[button: [text: "replace", xpos: 50], command: $TextOpsReplace, tech: tech]; CDPanel.Button[button: [text: "prop:", xpos: 105], proc: ChangeTextScanProp, tech: tech]; CDPanel.Label[[width: 140, cdValueKey: $TextScanPropNm, redisplay: TRUE], tech]; CDPanel.Line[tech]; CDValue.StoreInt[tech, $PanelHeight, panelHeight+18]; ReSizePanelViewers[18]}; ReSizePanelViewers: PROC[heightChange: INT] = { EachViewer: PROC[v: ViewerClasses.Viewer] RETURNS[BOOL _ TRUE] = { design: CD.Design _ CDViewer.DesignOf[v]; IF design#NIL THEN IF RefTab.Store[designs, design, design] THEN ReSizePanelViewer[design, heightChange]}; designs: RefTab.Ref _ RefTab.Create[]; ViewerOps.EnumerateViewers[EachViewer]}; ReSizePanelViewer: PROC[design: CD.Design, heightChange: INT] = { viewer: ViewerClasses.Viewer _ CDPanel.Create[design]; column: ViewerClasses.Column _ ViewerOps.ViewerColumn[viewer]; ViewerOps.SetOpenHeight[viewer, viewer.wh + heightChange]; ViewerOps.ComputeColumn[column]}; TextOpsMenuCommand: PROC [command: CDSequencer.Command] ~ { ThreeBools: TYPE = RECORD[doReplace, oneOnly, global: BOOL]; tb: ThreeBools _ SELECT command.key FROM $FindOneMatchingRopeInDesign => [FALSE, TRUE, TRUE], $FindOneMatchingRopeInContext => [FALSE, TRUE, FALSE], $FindEachMatchingRopeInDesign => [FALSE, FALSE, TRUE], $FindEachMatchingRopeInContext => [FALSE, FALSE, FALSE], $ReplaceOneMatchingRopeInDesign => [TRUE, TRUE, TRUE], $ReplaceOneMatchingRopeInContext => [TRUE, TRUE, FALSE], $ReplaceEachMatchingRopeInDesign => [TRUE, FALSE, TRUE], $ReplaceEachMatchingRopeInContext => [TRUE, FALSE, FALSE], ENDCASE => ERROR; TextOpsCommand[command, tb.doReplace, tb.oneOnly, tb.global]}; TextOpsCommand: PROC [command: CDSequencer.Command, doReplace, oneOnly, global: BOOL] ~ { DoInst: InstObProc = { IF aborted^ THEN RETURN[TRUE]; [quit, count] _ IF CDTexts.IsText[inst.ob] THEN ReplaceSat[tsp, design, doReplace, oneOnly, count, inst, ob, finder, replace] ELSE ReplaceExpr[tsp, design, doReplace, oneOnly, count, inst, finder, replace]}; DoObject: ObjProc = {[quit, count] _ ReplaceExpr[tsp, design, doReplace, oneOnly, count, obj, finder, replace]}; design: CD.Design _ command.design; count: NAT _ 0; tsp: TSPType _ GetTextScanProp[design]^; patternRef: IO.ROPE; pattern: IO.ROPE; replace: IO.ROPE; finder: Finder; searched: RefTab.Ref _ RefTab.Create[]; oneFound: BOOL _ FALSE; aborted: REF BOOL _ NEW[BOOL _ FALSE]; CDSequencer.UseAbortFlag[design, aborted]; IF doReplace THEN replace _ GetText[design]; patternRef _ GetPattern[design]; pattern _ OnlyStarOrHashMatching[patternRef]; finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE ! RegularExpression.MalformedPattern => { TerminalIO.PutF["Syntax error in adjusted pattern \"%g\"\n", IO.rope[pattern]]; GOTO prematureExit}]; TerminalIO.PutF["\nMatch Property: %g\n", IO.rope[tspNms[tsp]]]; TerminalIO.PutF["Match Pattern: \"%g\"\n", IO.rope[patternRef]]; IF doReplace THEN TerminalIO.PutF[" New Pattern: \"%g\"\n", IO.rope[replace]]; TerminalIO.PutF["Match Context: %g\n", IO.rope[IF global THEN "Global" ELSE "Local"]]; oneFound _ ScanContext[design, DoInst, DoObject, global, oneOnly]; TerminalIO.PutF["%g matches.\n", IO.int[count]]; IF oneFound OR doReplace AND count#0 THEN CDSequencer.ExecuteCommand [key: $ResetScaleTop, design: design, queue: dontQueue, comm: command]; <<[key: $ResetScaleSel, design: design, queue: dontQueue, comm: command];>> EXITS prematureExit => TerminalIO.PutF["Replace not done.\n"]}; ChangeTextScanProp: PROC [comm: CDSequencer.Command] = { tspNmList: LIST OF IO.ROPE; tspCur: TSPType; n: CARDINAL; FOR ts: TSPType DECREASING IN TSPType DO tspNmList _ CONS[tspNms[ts], tspNmList] ENDLOOP; TerminalIO.PutRope["Change Match Property\n"]; n _ PopUpSelection.Request[header: "Match Property", choice: tspNmList]; tspCur _ IF n=0 THEN GetTextScanProp[comm.design]^ ELSE VAL[n-1]; SetTextScanProp[comm.design, tspCur]}; TextOpsButtonCommand: PROC [comm: CDSequencer.Command] ~ { doReplace: BOOL _ SELECT comm.key FROM $TextOpsSearch => FALSE, $TextOpsReplace => TRUE, ENDCASE => ERROR; global: BOOL _ comm.b; oneOnly: BOOL _ comm.n#2; IF comm.n#1 THEN { TerminalIO.PutRope["Flush TextOps Cache\n"]; RefTab.Erase[globalCtx]; globalCtx _ RefTab.Create[]}; TextOpsCommand[comm, doReplace, oneOnly, global]}; <> ScanContext: PROC [design: CD.Design, instProc: InstObProc, objProc: ObjProc, allLevels, oneOnly: BOOL] RETURNS[found: BOOL _ FALSE] = { Push: PROC = { inst: CD.Instance _ CDOps.TheInstance[design: design]; []_CDCellsInteractions.PushInCellInstance[design, inst]}; pushes: INT; popped: BOOL _ FALSE; top: CD.Object; IF allLevels THEN WHILE CDCells.IsPushedIn[design] DO [] _ CDCellsInteractions.PopFromCell[design, interactive] ENDLOOP ELSE IF CDCells.IsPushedIn[design] THEN { popped _ TRUE; [] _ CDCells.EnumerateInstances[design.actual.rest.first.dummyCell.ob, DeselectAll]; [] _ CDCellsInteractions.PopFromCell[design, interactive]; top _ CDOps.TheInstance[design: design].ob}; IF top=NIL THEN top _ design.actual.first.dummyCell.ob; pushes _ ScanAll[design, top, allLevels, oneOnly, instProc, objProc]; IF popped THEN Push[]; IF pushes>1 THEN THROUGH [2..pushes] DO Push[] ENDLOOP; RETURN[pushes>0]}; ScanAll: PROC[design: CD.Design, top: CD.Object, goDeep, oneOnly: BOOL, instProc: InstObProc, objProc: ObjProc] RETURNS[pushes: INT _ 0] = { doInst: InstProc = { obVal: REF _ RefTab.Fetch[globalCtx, inst.ob].val; dive: BOOL _ goDeep AND (oneOnly OR obVal=NIL OR obVal=inst.ob); IF RefTab.Store[globalCtx, inst, inst] THEN IF instProc[inst, top] THEN GOTO MarkSelected; IF RefTab.Store[globalCtx, inst.ob, inst.ob] THEN IF objProc[inst.ob] THEN GOTO MarkSelected; IF dive AND CDCells.IsCell[inst.ob] THEN IF ((pushes _ ScanAll[design, inst.ob, goDeep, oneOnly, instProc, objProc])>0) THEN GOTO MarkSelected ELSE []_RefTab.Store[globalCtx, inst.ob, NEW[INT_1]]; EXITS MarkSelected => { []_CDCells.EnumerateInstances[top, DeselectAll]; inst.selected _ TRUE; RETURN[TRUE]}}; IF CDCells.EnumerateInstances[top, doInst] THEN pushes _ pushes + 1}; globalCtx: RefTab.Ref _ RefTab.Create[]; DeselectAll: InstProc = {inst.selected _ FALSE}; <> <> <> <> <> <<>> EnumDirectoryObjectsWithPattern: PROC [comm: CDSequencer.Command] ~ { proc: PROC [design: CD.Design, ob: CD.Object] _ GetObProc[comm.key]; finder: Finder _ GetFinder[comm.design]; CellEnumeratorProc: CDDirectory.EachEntryAction = { IF RegularExpression.SearchRope[finder, name].found THEN proc[comm.design, ob]}; [] _ CDDirectory.Enumerate[comm.design, CellEnumeratorProc]}; EnumSelectedObjects: PROC [comm: CDSequencer.Command] ~ { proc: PROC [design: CD.Design, ob: CD.Object] _ GetObProc[comm.key]; FOR w: CD.InstanceList _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO IF w.first.selected THEN proc[comm.design, w.first.ob] ENDLOOP}; ListUninstantiatedIconSchematics: PROC [comm: CDSequencer.Command] ~ { schTab: SymTab.Ref _ SymTab.Create[]; visited: RefTab.Ref _ RefTab.Create[]; EachInst: CDCells.InstEnumerator = { sch: IO.ROPE _ NARROW[CDProperties.GetProp[inst.ob, $IconFor]]; IF NOT CDCells.IsCell[inst.ob] THEN RETURN[FALSE]; IF sch.Length[]>0 THEN [] _ SymTab.Store[schTab, sch, sch]; IF RefTab.Store[visited, inst.ob, inst.ob] THEN [] _ CDCells.EnumerateInstances[inst.ob, EachInst]}; EachVisited: RefTab.EachPairAction = { nm: IO.ROPE _ CDDirectory.Name[NARROW[key], comm.design]; IF nm.Length[]>0 THEN [] _ SymTab.Delete[schTab, nm]}; EachUnVisited: SymTab.EachPairAction = {TerminalIO.PutF["%g\n", IO.rope[key]]}; FOR w: CD.InstanceList _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO []_EachInst[w.first] ENDLOOP; [] _ RefTab.Pairs[visited, EachVisited]; [] _ SymTab.Pairs[schTab, EachUnVisited]}; GetObProc: PROC[key: ATOM] RETURNS[proc: PROC [design: CD.Design, ob: CD.Object]] = { proc _ SELECT key FROM <<$AddIconBorderSelected,>> <<$AddIconBorderPattern => AddIconBorder,>> $ChangeColorSelected, $ChangeColorPattern => ChangeColor, ENDCASE => ERROR}; <> OnlyStarOrHashMatching: PROC[text: IO.ROPE] RETURNS[IO.ROPE] = { Insert: PROC[str: IO.ROPE] = {text _ Rope.Cat[text.Substr[0,index], str, text.Substr[index]]; index _ index+1}; index: INT; FOR index _ 0, index+1 WHILE index ERROR; '* => Insert["#"]; '# => LOOP; '[, '., '], '~, '^, '$, '+, '(, '|, '), '\\, '<, ':, ',, '>, '{, '} => Insert["'"]; ENDCASE ENDLOOP; RETURN[text]}; LogFind: PROC[ design: CD.Design, type: IO.ROPE, text: IO.ROPE, doReplace: BOOL, delete: BOOL, replace: IO.ROPE, on: REF, cell: CD.Object ] = { line0: IO.ROPE _ IO.PutFR["%g: %g ", IO.rope[type], IO.rope[text]]; online: IO.ROPE _ ""; inline: IO.ROPE _ ""; limit: INT _ 90; -- 120 if small IF doReplace THEN IF delete THEN {line0 _ line0.Cat[IO.PutFR["deleted "]]} ELSE { TerminalIO.PutF["%gchanged to\n", IO.rope[line0]]; line0 _ NIL; line0 _ IO.PutFR[" %g ", IO.rope[replace]]}; IF on#NIL THEN IF ISTYPE[on, CD.Object] THEN online _ IO.PutFR["on obj %g ", IO.rope[GetID[design, NARROW[on]]]] ELSE { inst: CD.Instance _ NARROW[on]; iRope: IO.ROPE _ CDOps.InstRope[inst]; IF ~iRope.Equal["rect comment"] THEN { oRope: IO.ROPE _ CDDirectory.Name[inst.ob, design]; IF oRope.Length[]=0 THEN online _ IO.PutFR["on inst %g ", IO.rope[iRope]] ELSE online _ IO.PutFR["on inst %g ", IO.rope[oRope]]}}; IF cell#NIL THEN inline _ IO.PutFR["in %g", IO.rope[GetID[design, cell]]]; IF line0.Length[] + online.Length[] + inline.Length[] < limit THEN {TerminalIO.PutF["%g%g%g\n", IO.rope[line0], IO.rope[online], IO.rope[inline]]; RETURN}; TerminalIO.PutF["%g\n", IO.rope[line0]]; SELECT online.Length[] + inline.Length[] FROM > limit => TerminalIO.PutF[" %g\n %g\n", IO.rope[online], IO.rope[inline]]; > 0 => TerminalIO.PutF[" %g%g\n", IO.rope[online], IO.rope[inline]]; ENDCASE}; GetID: PROC[design: CD.Design, obj: CD.Object] RETURNS[name: IO.ROPE] = { IF obj = CDOps.RealTopCell[design] THEN RETURN["(top level of design)"]; IF obj = design.actual.first.dummyCell.ob THEN RETURN [Rope.Cat[CDDirectory.Name[design.actual.first.mightReplace.ob, design], " (pushed in)"]]; name _ CDDirectory.Name[obj, design]; IF name.Length[]#0 THEN RETURN[name]; name _ CDOps.ToRope[obj]}; ReplaceRope: PROC[finder: Finder, text, replace: IO.ROPE] RETURNS[new: IO.ROPE] = { found: BOOL; at, atEnd, before, after: INT; IF finder=NIL THEN RETURN[text]; [found, at, atEnd, before, after] _ RegularExpression.SearchRope[finder, text]; IF NOT found THEN RETURN[text]; IF at=0 AND atEnd=0 AND before=0 AND after=0 THEN RETURN[replace]; -- * replace new _ Rope.Cat[text.Substr[0,at], replace, text.Substr[atEnd] ]}; ReplaceSat: PROC[tsp: TSPType, design: CD.Design, doReplace, oneOnly: BOOL, count: NAT, inst: CD.Instance, cell: CD.Object, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { delete: BOOL _ doReplace AND replace.Length[]=0; textSpec: CDTexts.TextSpecific _ NARROW[inst.ob.specific]; on: REF _ CDSatellites.GetMaster[cell, inst]; new: IO.ROPE _ replace; SELECT tsp FROM any => tsp _ IF on#NIL THEN sat ELSE text; text => IF on#NIL THEN RETURN[FALSE, count]; sat => IF on=NIL THEN RETURN[FALSE, count]; ENDCASE => RETURN[FALSE, count]; IF CD.InterestSize[inst.ob].x=0 OR CD.InterestSize[inst.ob].y=0 THEN {Signal["Zero dimension satellite"]; inst.selected _ TRUE; RETURN[TRUE, count]}; IF doReplace THEN { newOb: CD.Object; new _ ReplaceRope[finder, textSpec.text, replace]; IF new=textSpec.text THEN RETURN[FALSE, count]; newOb _ CDTexts.Create[new, textSpec.cdFont]; delete _ CD.InterestSize[newOb].x=0 OR CD.InterestSize[newOb].y=0; CDSequencer.MarkChangedIOOnly[design]; IF delete THEN {inst.selected _ TRUE; oneOnly _ TRUE} ELSE inst.ob _ newOb} ELSE IF ~RegularExpression.SearchRope[finder, textSpec.text].found THEN RETURN[FALSE, count]; LogFind[design, tspNms3[tsp], textSpec.text, doReplace, delete, new, on, cell]; RETURN[oneOnly, count+1]}; ReplaceExpr: PROC[ tsp: TSPType, design: CD.Design, doReplace: BOOL, oneOnly: BOOL, count: NAT, from: REF, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { quit _ FALSE; newCount _ count; IF tsp#any THEN [quit, newCount] _ ReplaceExprOnProp [tsp, design, doReplace, oneOnly, newCount, from, finder, replace] ELSE FOR tsp IN [firstInvisible..any) WHILE NOT quit DO [quit, newCount] _ ReplaceExprOnProp [tsp, design, doReplace, oneOnly, newCount, from, finder, replace] ENDLOOP}; ReplaceExprOnProp: PROC [tsp: TSPType, design: CD.Design, doReplace, oneOnly: BOOL, count: NAT, from: REF, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { propAtom: ATOM _ tspProps[tsp]; new: LIST OF IO.ROPE _ NIL; delete: BOOL _ doReplace AND replace.Length[]=0; changed: BOOL _ FALSE; exprs: LIST OF IO.ROPE _ NIL; ref: REF _ CDProperties.GetProp[from, propAtom]; quit _ FALSE; WITH ref SELECT FROM ropes: LIST OF IO.ROPE => {exprs _ ropes}; rope: IO.ROPE => {exprs _ LIST[rope]}; text: REF TEXT => {rope: IO.ROPE _ Rope.FromRefText[text]; exprs _ LIST[rope]}; atom: ATOM => {rope: IO.ROPE _ Atom.GetPName[atom]; exprs _ LIST[rope]}; ENDCASE => {exprs _ NIL}; FOR exprs _ exprs, exprs.rest WHILE exprs#NIL DO IF NOT doReplace THEN { IF ~ RegularExpression.SearchRope[finder, exprs.first].found THEN LOOP; LogFind[design, tspNms3[tsp], exprs.first, doReplace, delete, NIL, from, NIL]; count _ count +1; IF oneOnly THEN RETURN[TRUE, count]} ELSE { expr: IO.ROPE _ ReplaceRope[finder, exprs.first, replace]; IF (expr= exprs.first) THEN LOOP; LogFind[design, tspNms3[tsp], exprs.first, doReplace, delete, expr, from, NIL]; count _ count +1; changed _ TRUE; IF NOT delete THEN new _ CONS[expr, new]; IF oneOnly THEN { FOR temp: LIST OF IO.ROPE _ exprs.rest, temp.rest WHILE temp#NIL DO new _ CONS[temp.first, new] ENDLOOP; quit _ TRUE; EXIT} }; ENDLOOP; IF doReplace AND changed THEN { one: IO.ROPE _ IF new=NIL THEN NIL ELSE new.first; WITH ref SELECT FROM ropes: LIST OF IO.ROPE => ref _ new; rope: IO.ROPE => ref _ one; text: REF TEXT => ref _ Rope.ToRefText[one]; atom: ATOM => ref _ Atom.MakeAtom[one]; ENDCASE => ERROR; CDSequencer.MarkChangedIOOnly[design]; CDProperties.PutProp[from, propAtom, ref]}; RETURN[quit, count]}; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> ChangeColor: PROC[design: CD.Design, ob: CD.Object] = { size: CD.Position _ CD.InterestSize[ob]; off: CD.Position _ CD.InterestBase[ob]; layer: CD.Layer _ CDLayers.CurrentLayer[design]; mask: CD.Object _ CDRects.CreateRect[size: size, l: layer]; maskI: CD.Instance; name: IO.ROPE _ CDDirectory.Name[ob, design]; delete: BOOL _ layer = CD.commentLayer; EachInst: CDCells.InstEnumerator = { IF NOT CDRects.IsBareRect[inst.ob] THEN RETURN[FALSE]; IF CD.InterestSize[inst.ob]#size THEN RETURN[FALSE]; IF CD.InterestBase[inst.ob]#inst.trans.off THEN RETURN[FALSE]; IF CDProperties.GetProp[inst, $SisyphExtractProc]=NIL THEN RETURN[FALSE]; IF NARROW[CDProperties.GetProp[inst, $SisyphExtractProc], ATOM]#$ExtractNull THEN RETURN[FALSE]; IF delete THEN {maskI _ inst; TerminalIO.PutF["Color deleted in %g\n", IO.rope[name]]; RETURN[TRUE]}; IF inst.ob.layer=layer THEN {TerminalIO.PutF["Color unchanged in %g\n", IO.rope[name]]; RETURN[TRUE]}; inst.ob _ mask; TerminalIO.PutF["Color modified in %g\n", IO.rope[name]]; RETURN[TRUE]}; IF delete THEN { IF CDCells.EnumerateInstances[ob, EachInst] THEN IF CDCells.RemoveInstance[design, ob, maskI] THEN Signal["???"]} ELSE IF NOT CDCells.EnumerateInstances[ob, EachInst] THEN { maskI _ NEW[CD.InstanceRep _ [ob: mask, trans: [off: off] ] ]; CDProperties.PutProp[maskI, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, maskI] THEN Signal["???"]; TerminalIO.PutF["Color added in %g\n", IO.rope[name]]}; CDOps.Redraw[design]}; <> AddExpressionToEachSelected: PROC [command: CDSequencer.Command] ~ { count: NAT _ 0; id: IO.ROPE _ SELECT command.key FROM $AddInstanceExpressionToEachSelected => "Instance", $AddObjectExpressionToEachSelected => "Object", ENDCASE => ERROR; expr: IO.ROPE _ TerminalIO.RequestRope[id.Cat[" expression to add to selected: "]]; FOR w: CD.InstanceList _ CDOps.InstList[command.design], w.rest WHILE w#NIL DO IF w.first.selected THEN { on: REF _ SELECT command.key FROM $AddInstanceExpressionToEachSelected => w.first, $AddObjectExpressionToEachSelected => w.first.ob, ENDCASE => ERROR; exprs: LIST OF IO.ROPE _ NARROW[CDProperties.GetProp[on, Sisyph.expressionsProp]]; FOR test: LIST OF IO.ROPE _ exprs, test.rest WHILE test#NIL DO IF expr.Equal[test.first] THEN GOTO exit; REPEAT exit => LOOP ENDLOOP; exprs _ CONS[expr, exprs]; CDProperties.PutProp[on, Sisyph.expressionsProp, exprs]; count _ count+1}; ENDLOOP; TerminalIO.PutF["%g matches.\n", IO.int[count]]}; <> AddTextLines: PROC [command: CDSequencer.Command] ~ { pos: CD.Position _ command.pos; ob: CD.Object; lay: CD.Layer _ CDLayers.CurrentLayer[command.design]; r: IO.ROPE; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[command.design]; grid: INT _ Grid[command.design, font]; CDOps.Redraw[command.design]; lay _ CDPanelFonts.LayerForText[lay, command.design.technology]; IF font=NIL THEN CDSequencer.Quit["** no font"]; pos.y _ pos.y + font.origin.y; r _ TerminalIO.RequestRope["create text >"]; DO WHILE ~r.IsEmpty[] AND r.Fetch[] IN [IO.NUL..IO.SP] DO r _ r.Substr[1] ENDLOOP; WHILE ~r.IsEmpty[] AND r.Fetch[r.Length[]-1] IN [IO.NUL..IO.SP] DO r _ r.Substr[0, r.Length[]-1] ENDLOOP; IF r.IsEmpty[] THEN EXIT; ob _ CDTexts.Create[text: r, font: font, layer: lay]; IF ob=NIL THEN CDSequencer.Quit["***bad line***"]; []_CDOps.IncludeObject[design: command.design, ob: ob, trans: [pos, original]]; r _ TerminalIO.RequestRope[NIL]; pos.y _ pos.y - grid ENDLOOP}; <> BuildCrossReferenceLists: PROC [comm: CDSequencer.Command] ~ { InstEnumeratorProc: CDCells.InstEnumerator = { IF CDCells.IsCell[inst.ob] AND inst.selected THEN {nofCells _ nofCells+1; objNms _ CONS[CDDirectory.Name[inst.ob, comm.design], objNms]}}; ListEm: SymTab.EachPairAction = {list _ CONS[NARROW[val], list]}; rootCell: CD.Object _ comm.design^.actual.first.dummyCell.ob; objNms: LIST OF IO.ROPE _ NIL; top: Sisyph.Context _ Sisyph.Create[comm.design]; index: INT _ 0; nofCells: INT _ 0; maxNm: INT _ 0; OccSeq: TYPE = RECORD[name: IO.ROPE, seq: SEQUENCE size: CARDINAL OF BOOL]; list: LIST OF REF OccSeq; table: SymTab.Ref _ SymTab.Create[]; []_CDCells.EnumerateInstances[rootCell, InstEnumeratorProc]; FOR m: LIST OF IO.ROPE _ objNms, m.rest WHILE m#NIL DO AddToTable: PROC[wire: Core.Wire] = { name: IO.ROPE _ CoreOps.GetShortWireName[wire]; IF name.Length[]>0 THEN { ref: REF OccSeq _ NARROW[SymTab.Fetch[table, name].val]; IF ref=NIL THEN ref _ NEW[OccSeq[nofCells]]; ref.name _ name; ref[index] _ TRUE; maxNm _ MAX[name.Length[], maxNm]; []_SymTab.Store[table, name, ref]}; FOR i: INT IN [0..wire.size) DO AddToTable[wire[i]] ENDLOOP}; sub: Core.CellType _ Sisyph.ES[m.first, top]; AddToTable[sub.public]; index _ index +1; ENDLOOP; [ ] _ SymTab.Pairs[table, ListEm]; DO ok: BOOL _ TRUE; FOR l: LIST OF REF OccSeq _ list, l.rest WHILE l.rest#NIL DO TwoOcc: TYPE = RECORD[occ1, occ2: REF OccSeq]; SELECT Rope.Compare[l.first.name, l.rest.first.name] FROM less => LOOP; equal => ERROR; ENDCASE; [l.first, l.rest.first] _ TwoOcc[l.rest.first, l.first]; ok _ FALSE; ENDLOOP; IF ok THEN EXIT; ENDLOOP; TerminalIO.PutF["\nCross reference list for:\n"]; index _ 0; FOR m: LIST OF IO.ROPE _ objNms, m.rest WHILE m#NIL DO TerminalIO.PutF["%4g: %g\n", IO.int[index], IO.rope[m.first]]; index _ index +1; ENDLOOP; FOR m: LIST OF REF OccSeq _ list, m.rest WHILE m#NIL DO IF comm.key=$BuildCrossReferenceListsUnique THEN { used: NAT _ 0; FOR i: INT IN [0..nofCells) DO IF m.first[i] THEN used_used+1 ENDLOOP; IF used#1 THEN LOOP}; TerminalIO.PutF["%g ", IO.rope[m.first.name]]; FOR i: INT IN [0..(maxNm-m.first.name.Length[])) DO TerminalIO.PutRope[" "] ENDLOOP; FOR i: INT IN [0..nofCells) DO IF m.first[i] THEN TerminalIO.PutF["%2g", IO.int[i]] ELSE TerminalIO.PutF[" "] ENDLOOP; TerminalIO.PutF["\n"]; ENDLOOP}; <> ReplaceUnboundLibrary: PROC[command: CDSequencer.Command] ~ { DoInst: InstObProc = { }; DoObject: ObjProc = { imp: CDImports.ImportSpecific; new: IO.ROPE; IF ~CDImports.IsImport[obj] THEN RETURN; imp _ NARROW[obj.specific]; new _ ReplaceRope[finder, imp.designName, replace]; IF new=imp.designName THEN RETURN; TerminalIO.PutF["%g\n", IO.rope[imp.objectName]]; IF imp.boundOb#NIL THEN ERROR; -- RollBackAnd CDRead -X designFile IF imp.boundDesign#NIL THEN ERROR; -- RollBackAnd CDRead -X designFile imp.designName _ new; count _ count+1}; design: CD.Design _ command.design; tsp: TSPType _ name; count: NAT _ 0; doReplace: BOOL _ TRUE; replace: IO.ROPE _ IF doReplace THEN GetText[design] ELSE NIL; delete: BOOL _ doReplace AND replace.Length[]=0; patternRef: IO.ROPE _ GetPattern[design]; pattern: IO.ROPE _ OnlyStarOrHashMatching[patternRef]; oneFound: BOOL _ FALSE; finder: Finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE ! RegularExpression.MalformedPattern => { TerminalIO.PutF["Syntax error in adjusted pattern \"%g\"\n", IO.rope[pattern]]; GOTO prematureExit}]; TerminalIO.PutF["\nReplace Unbound Library\n"]; TerminalIO.PutF[" Old Library: \"%g\"\n", IO.rope[patternRef]]; TerminalIO.PutF[" New Library: \"%g\"\n", IO.rope[replace]]; TerminalIO.TOS[].Flush[]; IF ~TerminalIO.Confirm["Ready to proceed?"] THEN RETURN; oneFound _ ScanContext[design, DoInst, DoObject, TRUE, FALSE]; TerminalIO.PutF["%g matches.\n", IO.int[count]]; CDSequencer.ExecuteCommand [key: $ResetScaleTop, design: design, queue: dontQueue, comm: command]; EXITS prematureExit => TerminalIO.PutF["Replace not done.\n"]}; <> Grid: PROC[design: CD.Design, font: CDTexts.CDFont _ NIL] RETURNS[grid: NAT] = { viewers: CDViewer.ViewerList _ CDViewer.ViewersOf[design]; IF viewers#NIL THEN WITH ViewerOps.GetViewer[viewers.first, $Grid] SELECT FROM rgrid: REF CD.Number => grid _ rgrid^; ENDCASE => NULL ELSE grid _ design.technology.lambda*2; IF font#NIL THEN WHILE font.height > (grid*4)/3 DO grid _ grid*2 ENDLOOP}; GetFinder: PROC[design: CD.Design] RETURNS[finder: Finder] = { pattern: IO.ROPE _ OnlyStarOrHashMatching[GetPattern[design]]; finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE]}; GetPattern: PROC [design: CD.Design] RETURNS [pattern: Rope.ROPE] = { pattern _ CDPanel.TakeDownText[design, $pattern]; IF Rope.IsEmpty[pattern] THEN pattern _ NIL}; GetText: PROC [design: CD.Design] RETURNS [text: Rope.ROPE] = { text _ CDPanel.TakeDownText[design, $text]; IF Rope.IsEmpty[text] THEN text _ NIL}; PutText: PROC [design: CD.Design, text: Rope.ROPE] RETURNS[Rope.ROPE] = {CDPanel.PutUpText[design, $text, text]; RETURN[text]}; GetTextScanProp: PROC [design: CD.Design] RETURNS[tspRef: REF TSPType] = { tspRef _ NARROW[CDValue.Fetch[design, $TextScanProp]]; IF tspRef=NIL THEN { tspRef _ NEW[TSPType _ text]; CDValue.Store[design, $TextScanProp, tspRef]}; RETURN[tspRef]}; SetTextScanProp: PROC [design: CD.Design, tsp: TSPType] = { tspRef: REF TSPType _ GetTextScanProp[design]; tspRef^ _ tsp; CDValue.Store[design, $TextScanPropNm, tspNms[tsp]]; []_CDPanel.PutUp[design, $TextScanPropNm]}; CycleTextScanProp: PROC[design: CD.Design] = { tsp: TSPType _ GetTextScanProp[design]^; tspLast: TSPType _ LAST[TSPType]; tspn: CARDINAL _ tsp.ORD; tspl: CARDINAL _ tspLast.ORD; SetTextScanProp[design, VAL[(tspn+1) MOD (tspl+1)]]}; <> <> menu: PopUpMenus.Menu _ CDPopUpMenus.MakeMenu[ key: $TextOps, header: "TextOps", doc: "Text Search and Replace Operations" ]; CDCommandOps.RegisterWithMenu[ menu: $OtherProgramMenu, entry: "TextOps", doc: "Text Search and Replace Operations", key: $TextOps, proc: NIL]; <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> CDSequencerExtras.RegisterCommand [key: $TextOpsSearch, proc: TextOpsButtonCommand, queue: doQueue]; CDSequencerExtras.RegisterCommand [key: $TextOpsReplace, proc: TextOpsButtonCommand, queue: doQueue]; CDValue.RegisterKey[ $TextScanProp, NIL, $djc]; CDValue.RegisterKey[ $TextScanPropNm, NIL, $djc]; InitTextScanPropPanel[]; <> CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "List Uninstantiated Icon Schematics", doc: "Examines the IconFor property.", key: $ListUninstantiatedIconSchematics, proc: ListUninstantiatedIconSchematics ]; <> CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Change Color Pattern", doc: "Use panel color and pattern", key: $ChangeColorPattern, proc: EnumDirectoryObjectsWithPattern ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Change Color Selected", doc: "Use panel color and selected cells", key: $ChangeColorSelected, proc: EnumSelectedObjects ]; <> CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add Instance Expression To Each Selected", doc: "Add Instance Expression To Each Selected", key: $AddInstanceExpressionToEachSelected, proc: AddExpressionToEachSelected ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add Object Expression To Each Selected", doc: "Add Object Expression To Each Selected", key: $AddObjectExpressionToEachSelected, proc: AddExpressionToEachSelected ]; <> CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add mulitple text lines", doc: "Terminate with 2 CR's", key: $AddTextLines, proc: AddTextLines ]; <> CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Build Cross Reference Lists", doc: "Build cross reference lists from public of selected", key: $BuildCrossReferenceLists, proc: BuildCrossReferenceLists ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Build Cross Reference Lists - Unique only", doc: "Build cross reference lists from public of selected - Unique only", key: $BuildCrossReferenceListsUnique, proc: BuildCrossReferenceLists ]; <> CDCommandOps.RegisterWithMenu[ menu: $ImportMenu, entry: "Replace Unbound Library", doc: "Replace Unbound Library", key: $ReplaceUnboundLibrary, proc: ReplaceUnboundLibrary ]; END.