-- CellLibrarian.mesa
-- a program to run within Chipmonk
-- written by E. McCreight, August 27, 1981 3:50 PM
-- replace-cells-from-file written by R. Pasco, January 25, 1982
-- last modified by E. McCreight, March 29, 1983 2:14 PM
DIRECTORY
ChipUserInt,
InlineDefs,
ppdddefs: FROM "ppdddefs" USING [AdjustCallersBBoxes],
ppddefs,
ppdefs,
StringDefs;
CellLibrarian: PROGRAM
IMPORTS ChipUserInt, InlineDefs, ppdddefs,
ppddefs, ppdefs, StringDefs =
BEGIN OPEN ChipUserInt, ppddefs, ppdefs, StringDefs;
uz: PUBLIC UNCOUNTED ZONE ← NIL;
maxStars: INTEGER = 8;
spntAr: TYPE = ARRAY [0..maxStars) OF ssInd;
ssInd: TYPE = RECORD[st, end: [0..255]];
-- specifies a substring: chrs [st..end)
-- G e n e r a l l y - U s e f u l P r o c e d u r e s
CalcBBox: PROC [ob: obPtr] RETURNS [noChange: BOOLEAN] =
{RETURN[TRUE]};
-- This is a stub to be replaced by the same routine in
-- Chipmonk when it is repaired and exported.
LibrarianExplain: PROCEDURE [why: STRING,
explanation, what: STRING ← NIL] =
BEGIN
IF what = NIL THEN what ← "Can't run CellLibrarian [Confirm]";
Explain[why, explanation, what];
END;
MarkList: PROCEDURE[head: listPtr,
selectedOnly: BOOLEAN ← FALSE] =
BEGIN
FOR lp: listPtr ← head, lp.nxt WHILE lp#NIL DO
IF lp.selected OR NOT selectedOnly THEN
MarkObject[lp.ob];
ENDLOOP;
END;
MarkObject: PROCEDURE[ob: obPtr] =
BEGIN
ob.marked ← TRUE;
WITH dob: ob SELECT FROM
cell => MarkList[dob.ptr];
ENDCASE => NULL;
END;
BBList: PROCEDURE[head: listPtr] =
BEGIN
FOR lp: listPtr ← head, lp.nxt WHILE lp#NIL DO
lp.ridx ← InlineDefs.BITXOR[lp.idx, 1];
BBObject[lp.ob];
ENDLOOP;
END;
BBObject: PROCEDURE[ob: obPtr] =
BEGIN
IF ob.marked THEN
BEGIN
ob.marked ← FALSE;
ob.size[2] ← ob.size[0];
WITH dob: ob SELECT FROM
cell => BBList[dob.ptr];
ENDCASE => NULL;
[] ← CalcBBox[ob];
END;
END;
UnlistUnmarkedCells: PROCEDURE[lpp: LONG POINTER TO listPtr, keepOnlySelected: BOOLEAN ← FALSE] =
BEGIN
WHILE lpp↑#NIL DO
ob: LONG POINTER TO object ← lpp↑.ob;
IF (ob.otyp=cell AND NOT ob.marked) OR
(keepOnlySelected AND NOT lpp↑.selected) THEN
lpp↑ ← lpp↑.nxt ELSE lpp ← @lpp↑.nxt;
ENDLOOP;
END;
ReSizeCells: PROCEDURE[lpp: LONG POINTER TO listPtr, keepOnlySelected: BOOLEAN ← FALSE] =
BEGIN
WHILE lpp↑#NIL DO
ob: LONG POINTER TO object ← lpp↑.ob;
IF (ob.otyp=cell AND NOT ob.marked) OR
(keepOnlySelected AND NOT lpp↑.selected) THEN
lpp↑ ← lpp↑.nxt ELSE lpp ← @lpp↑.nxt;
ENDLOOP;
END;
Capitalize: PROCEDURE[s: STRING] =
BEGIN
IF s#NIL THEN FOR i: CARDINAL IN [0..s.length) DO
s[i] ← UpperCase[s[i]];
ENDLOOP;
END;
starCount: PROCEDURE[s: STRING] RETURNS[c: INTEGER] =
BEGIN
c←0;
FOR i: CARDINAL IN [0..s.length) DO
IF s[i]='* THEN c←c+1;
ENDLOOP;
END;
namesMatch: PROCEDURE[s1, s2: STRING, c1, c2: CARDINAL]
RETURNS[BOOLEAN, spntAr] =
BEGIN -- only s1 can have stars
myAr, otherAr: spntAr;
b: BOOLEAN;
newc1: CARDINAL ← c1+1;
myAr[0] ← [c2,c2];
SELECT TRUE FROM
c1=s1.length => RETURN[c2=s2.length, myAr];
c2=s2.length =>
RETURN[newc1=s1.length AND s1[c1]='*, myAr];
s1[c1]='* =>
FOR i: CARDINAL IN [c2..s2.length] DO
myAr[0].end ← i;
[b,otherAr] ← namesMatch[s1,s2,newc1,i];
IF b THEN
BEGIN
FOR j: INTEGER IN [1..maxStars) DO
myAr[j] ← otherAr[j-1];
ENDLOOP;
RETURN[TRUE,myAr];
END;
ENDLOOP;
s2[c2]=s1[c1] =>
BEGIN
[b,myAr] ← namesMatch[s1,s2,newc1,c2+1];
RETURN[b,myAr];
END;
ENDCASE => NULL;
RETURN[FALSE, myAr];
END;
replaceName: PROCEDURE[cell: LONG POINTER TO cList,
ar: spntAr, ns: STRING] =
BEGIN
newName: STRING ← [400];
grpCnt: INTEGER ← 0;
oldName:STRING ← cell.name;
FOR i: CARDINAL IN [0..ns.length) DO
IF ns[i]='* THEN
BEGIN
FOR j: INTEGER IN [ar[grpCnt].st..ar[grpCnt].end) DO
AppendChar[newName,oldName[j]];
ENDLOOP;
grpCnt ← grpCnt+1;
END
ELSE AppendChar[newName,ns[i]];
ENDLOOP;
FOR c2: LONG POINTER TO cList ← cellList, c2.nxt
WHILE c2#NIL DO
IF StringDefs.EquivalentString[newName, c2.name] THEN
BEGIN
Explain[newName,"already in use. [Confirm]",
"No replacement done."];
EXIT;
END;
REPEAT
FINISHED =>
BEGIN -- nobody exists by new name
-- for now:
Explain[cell.name,"becomes [Confirm]", newName];
FreeString[cell.name];
cell.name ← newString[newName];
END;
ENDLOOP;
END;
-- O p e r a t o r b o d i e s
RenameCells: PROCEDURE =
BEGIN
name, newn: STRING ← NIL;
ReturnString: PROCEDURE[s: LONG POINTER TO STRING] =
{IF s↑#NIL THEN {FreeString[s↑]; s↑ ← NIL}};
BEGIN ENABLE UNWIND =>
{ReturnString[@name]; ReturnString[@newn]};
nameSC, newnSC: INTEGER;
theAr: spntAr;
match: BOOLEAN;
stNumMes: STRING ← [20];
stNumMes.length ← 0;
AppendString[stNumMes,"(up to "];
AppendDecimal[stNumMes,maxStars];
AppendString[stNumMes," stars)"];
name ← RequestString[s1: "Old name:", s2: stNumMes,
s3: "(CR or Cancel to exit)"];
nameSC ← starCount[name];
WHILE nameSC>maxStars DO
ReturnString[@name];
name ← RequestString[s1: "Old name:", s2: stNumMes,
s3: "(too many stars; try again!)"];
nameSC ← starCount[name];
ENDLOOP;
WHILE name#NIL AND name.length>0 DO
newn ← RequestString[s1: "New name:", s2: stNumMes];
newnSC ← starCount[newn];
WHILE newnSC>maxStars DO
ReturnString[@newn];
newn ← RequestString[s1: "New name:", s2: stNumMes,
s3: "(too many stars; try again!)"];
newnSC ← starCount[newn];
ENDLOOP;
IF newn=NIL OR newn.length=0 THEN EXIT;
Capitalize[name]; Capitalize[newn];
FOR cell: LONG POINTER TO cList ← cellList, cell.nxt
WHILE cell#NIL DO
[match,theAr] ← namesMatch[name,cell.name,0,0];
IF match THEN replaceName[cell,theAr,newn];
ENDLOOP;
name ← RequestString[s1: "Old name:", s2: stNumMes,
s3: "(CR or Cancel to exit)"];
nameSC ← starCount[name];
WHILE nameSC>maxStars DO
ReturnString[@name];
name ← RequestString[s1: "Old name:", s2: stNumMes,
s3: "(too many stars; try again!)"];
nameSC ← starCount[name];
ENDLOOP;
ENDLOOP;
END;
ReturnString[@name]; ReturnString[@newn];
END; -- of RenameCells
PurgeUnusedCells: PROCEDURE
[keepOnlySelected, prompt: BOOLEAN ← FALSE] =
BEGIN
FOR cell: LONG POINTER TO cList ← cellList, cell.nxt
WHILE cell#NIL DO
cell.ob.marked ← FALSE;
ENDLOOP;
FOR cell: LONG POINTER TO cell object ← GetCellSuper[],
cell.super WHILE cell#NIL DO
cell.marked ← FALSE;
ENDLOOP;
MarkList[masterList, keepOnlySelected];
IF prompt THEN
FOR cell: LONG POINTER TO cList ← cellList, cell.nxt
WHILE cell#NIL DO
IF NOT cell.ob.marked AND HeSaysYes[cell.name,
"Shall I keep this cell type?"] THEN
BEGIN
cell.ob.marked ← TRUE;
WITH c: cell.ob SELECT FROM
cell => MarkList[c.ptr];
ENDCASE => NULL;
END;
ENDLOOP;
UnlistUnmarkedCells[@masterList, keepOnlySelected];
-- take unreferenced cells
-- out of pictures at this and higher levels
FOR csp: LONG POINTER TO cellSE ← cellStack, csp.nxt
WHILE csp#NIL DO
UnlistUnmarkedCells[@csp.lp];
ENDLOOP;
BEGIN -- free names of unreferenced named objects
prev: LONG POINTER TO LONG POINTER TO cList ←
@cellList;
cell: LONG POINTER TO cList ← prev↑;
WHILE cell#NIL DO
IF cell.ob.marked THEN prev ← @cell.nxt ELSE
BEGIN
FreeString[cell.name];
prev↑ ← cell.nxt;
FreeSpace[cell];
END;
cell ← prev↑;
ENDLOOP;
END;
BEGIN -- free all unreferenced cells. This will leave behind
-- orphaned objects and lists, but they won't be written in
-- the output file.
nextCell: LONG POINTER TO cell object;
FOR cell: LONG POINTER TO cell object ← GetCellSuper[],
nextCell WHILE cell#NIL DO
nextCell ← cell.super;
IF NOT cell.marked THEN freeCell[cell];
ENDLOOP;
END;
-- At this point, all unreferenced cells are gone and all
-- referenced cells are marked. Adjust the bounding boxes for
-- consistency.
BBList[masterList];
END; -- of PurgeUnusedCells
ReplaceCellsFromFile: PROCEDURE [prompt: BOOLEAN] =
BEGIN
oldCellList: LONG POINTER TO cList ← cellList;
newCell, oldCell, nextNew, nextOld:
LONG POINTER TO cList ← NIL;
reReference: PROCEDURE [old, new: obPtr] =
-- change all calls to "old" into calls to "new"
BEGIN
substRefsInList: PROCEDURE [head: listPtr] =
BEGIN
FOR lp: listPtr ← head, lp.nxt UNTIL lp=NIL DO
lp.ob ← substRefsInOb[lp.ob];
ENDLOOP;
END;
substRefsInOb: PROCEDURE [ob: obPtr] RETURNS [obPtr] =
BEGIN
WITH dob: ob SELECT FROM
ENDCASE => NULL;
IF ob=old THEN
BEGIN
old↑.refCnt ← old↑.refCnt - 1;
new↑.refCnt ← new↑.refCnt + 1;
RETURN[new]
END
ELSE RETURN[ob];
END;
FOR s: LONG POINTER TO cell object ← GetCellSuper[],
s.super UNTIL s=NIL DO
substRefsInList[s.ptr];
ENDLOOP;
substRefsInList[masterList];
ppdddefs.AdjustCallersBBoxes[new];
END; -- of reReference
remove: PROCEDURE [cell: LONG POINTER TO cList,
from: LONG POINTER TO LONG POINTER TO cList] =
BEGIN
found: BOOLEAN ← FALSE;
super: LONG POINTER TO cell object ←
LOOPHOLE[cell.ob, LONG POINTER TO cell object];
list: listPtr ← super.ptr;
flushDel[list];
freeCell[super];
-- now unlink cell
IF cell=from↑ THEN -- head cell
BEGIN
from↑ ← cell.nxt;
found ← TRUE;
END
ELSE -- elsewhere in list
BEGIN
FOR c: LONG POINTER TO cList ← from↑, c.nxt
UNTIL c = NIL DO
IF c.nxt = cell THEN
BEGIN
c.nxt ← cell.nxt;
found ← TRUE;
EXIT;
END;
ENDLOOP;
END;
IF found THEN FreeSpace[cell] ELSE ERROR;
END; -- of remove
cellList ← NIL;
FreeString[RequestString["Do a ctl-tab-i now for the",
"file you want to merge in. Then confirm",
"this prompt with CR."]];
FOR oldCell ← oldCellList, nextOld WHILE oldCell#NIL DO
nextOld ← oldCell.nxt; -- save in case we remove the old cell
FOR newCell ← cellList, nextNew WHILE newCell#NIL DO
nextNew ← newCell.nxt;
-- save in case we remove the new cell
IF StringDefs.EquivalentString[oldCell.name,newCell.name]
THEN
IF ~prompt OR HeSaysYes["Replace",oldCell.name] THEN
BEGIN
-- change all refs to oldCell into refs to newCell
reReference[oldCell.ob,newCell.ob];
-- delete oldCell from its list
remove[oldCell,@oldCellList];
END
ELSE
BEGIN
-- change all refs to newCell into refs to oldCell
reReference[newCell.ob,oldCell.ob];
-- delete newCell from its list
remove[newCell,@cellList];
END;
ENDLOOP;
ENDLOOP;
-- concatenate new cell list onto end of old
IF oldCellList#NIL THEN
BEGIN
FOR oldCell ← oldCellList,oldCell.nxt
UNTIL oldCell.nxt = NIL DO
ENDLOOP;
oldCell.nxt ← cellList;
cellList ← oldCellList;
END;
END; -- of ReplaceCellsFromFile
-- M a i n P r o g r a m
BEGIN ENABLE Punt => GOTO Exit; -- for exits
tryAgain: BOOLEAN ← TRUE;
WHILE tryAgain DO
tryAgain ← FALSE;
SELECT TRUE FROM
HeSaysYes["Shall I purge ALL unreferenced cells?",
"(this is what people usually want)"] =>
PurgeUnusedCells[];
HeSaysYes["Shall I replace cells from a file?"] =>
ReplaceCellsFromFile[prompt: HeSaysYes[
"Shall I ask before replacing each cell type?"]];
HeSaysYes["Shall I rename some cells for you?"] =>
RenameCells[];
HeSaysYes["Shall I purge SOME unreferenced cells?"] =>
PurgeUnusedCells[
keepOnlySelected: HeSaysYes[
"Shall I erase the unselected items in the design?",
"(CAREFUL NOW!!)"],
prompt: HeSaysYes[
"Before I purge a cell type, should I ask you about it?"]];
ENDCASE => tryAgain ← TRUE;
ENDLOOP;
EXITS Exit => NULL;
END;
dChange ← TRUE;
END. -- of CellLibrarian