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 =
Types and Data Structures
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;
TextOps Main Procs
DoPLAFix: PROC [comm: CDSequencer.Command] ~ {
DoInst: PROC[inst: CD.Instance, ob: CD.Object] RETURNS[quit: BOOL ← FALSE] = {
refExtrProc: REF ← CDProperties.GetProp[inst, $SisyphExtractProc];
refCodeFor: REF ← CDProperties.GetProp[inst, $CodeFor];
code: IO.ROPE;
IF refExtrProc=NIL THEN RETURN[FALSE];
IF refCodeFor=NIL THEN RETURN[FALSE];
code ← NARROW[refCodeFor];
IF code.Find["PLAGen"]=-1 THEN RETURN[FALSE];
IF code.Find["PLAOutDrHeader"]#-1 THEN RETURN[FALSE];
IF CDProperties.GetProp[inst.ob, $SisyphExtractProc]#NIL THEN ERROR;
IF CDProperties.GetProp[inst.ob, $CodeFor]#NIL THEN ERROR;
CDProperties.PutProp[inst.ob, $SisyphExtractProc, refExtrProc];
CDProperties.PutProp[inst.ob, $CodeFor, refCodeFor];
CDProperties.PutProp[inst, $SisyphExtractProc, NIL];
CDProperties.PutProp[inst, $CodeFor, NIL];
TerminalIO.PutF["%g\n", IO.rope[NARROW[code]]]};
DoObject: PROC[obj: CD.Object] RETURNS[quit: BOOL ← FALSE] = { };
top: CD.Object;
WHILE CDCells.IsPushedIn[comm.design] DO
[] ← CDCellsInteractions.PopFromCell[comm.design, interactive] ENDLOOP;
top ← comm.design.actual.first.dummyCell.ob;
[] ← ScanAll[comm.design, top, TRUE, FALSE, DoInst, DoObject];
TerminalIO.PutRope["Done\n"]};
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]};
TextOps Enumeration
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];
[]llsInteractions.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𡤁]];
EXITS MarkSelected => {
[]lls.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};
ScanDesign: PROC [design: CD.Design, instProc: InstProc, objProc: ObjProc] = {
CellEnumeratorProc: CDDirectory.EachEntryAction = {RETURN[ScanCell[name, ob]]};
IF CDDirectory.Enumerate[design, CellEnumeratorProc] THEN RETURN;
FOR pushes: LIST OF CD.PushRec ← design^.actual, pushes.rest WHILE pushes#NIL DO
IF ScanCell[NIL, pushes.first.dummyCell.ob] THEN EXIT ENDLOOP};
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
[]hInst[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};
TextOps Satellite and Expression processing
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<text.Length[]
DO
SELECT text.Fetch[index]
FROM
'' => 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]};
Add Borders and Color
AddIconBorder: PROC [design: CD.Design, ob: CD.Object] ~ {
name: IO.ROPE ← CDDirectory.Name[ob, design];
layer: CD.Layer ← CDLayers.CurrentLayer[design];
w: INT ← CDLayers.LayerWidth[design, layer];
ir: CD.Rect ← CD.InterestRect[ob];
vert: CD.Object ← CDRects.CreateRect[size: [w,ir.y2-ir.y1], l: layer];
hor: CD.Object ← CDRects.CreateRect[size: [ir.x2-ir.x1,w], l: layer];
inst: CD.Instance;
inst ← NEW[CD.InstanceRep ← [ob: vert, trans: [off: [ir.x1, ir.y1]] ] ];
CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull];
IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"];
inst ← NEW[CD.InstanceRep ← [ob: vert, trans: [off: [ir.x2-w, ir.y1]] ] ];
CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull];
IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"];
inst ← NEW[CD.InstanceRep ← [ob: hor, trans: [off: [ir.x1, ir.y1]] ] ];
CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull];
IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"];
inst ← NEW[CD.InstanceRep ← [ob: hor, trans: [off: [ir.x1, ir.y2-w]] ] ];
CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull];
IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"];
TerminalIO.PutF["Borders added in %g\n", IO.rope[name]];
CDOps.Redraw[design]};
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]};
Add Multiple Text Lines
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***"];
[]Ops.IncludeObject[design: command.design, ob: ob, trans: [pos, original]];
r ← TerminalIO.RequestRope[NIL];
pos.y ← pos.y - grid ENDLOOP};
Build Cross Reference Lists
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[];
[]lls.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};
Replace Unbound Library
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"]};
Panel Utilities
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]];
[]Panel.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)]]};