-- second procedure exporting module of silicon (pretty picture) program -- last modified by McCreight, December 21, 1983 10:02 AM -- to copy text properties properly -- modified (slightly) by Petit September 23, 1981 8:32 PM DIRECTORY ChipUserInt, multiGraphicsDefs, InlineDefs, SegmentDefs, StringDefs, ppdddefs,ppddefs, ppdefs; ppprocs2: PROGRAM IMPORTS ChipUserInt, ppdddefs,ppdefs, ppddefs, multiGraphicsDefs, InlineDefs, StringDefs EXPORTS ppdefs, ppddefs,ppdddefs = BEGIN OPEN ppdefs, ppdddefs,ppddefs, multiGraphicsDefs, SegmentDefs, StringDefs, InlineDefs; masterList: PUBLIC LONG POINTER TO list; cellList: PUBLIC LONG POINTER TO cList; cellNameMode: PUBLIC BOOLEAN ← FALSE; cnList: PUBLIC LONG POINTER TO list ← NIL; xx, yy: PUBLIC INTEGER; bb: PUBLIC BOOLEAN; ii, jj: CARDINAL; lp, lqp: LONG POINTER TO list; cp: LONG POINTER TO cList; localNameString:STRING←[30]; localBusString:STRING←[30]; ke: keyEvent; ss: STRING; cellStack: PUBLIC LONG POINTER TO cellSE; unDelPnt: PUBLIC LONG POINTER TO list; unDelGrpCnt, unDelItemCnt: PUBLIC CARDINAL; maxZeeLevels: CARDINAL ← 8; yWdt: CARDINAL = 13; sss: STRING ← [100]; tiCx: CARDINAL = 100; doZee: PUBLIC cmdProc = BEGIN x, y: INTEGER; width: CARDINAL; count: PROCEDURE [lev: CARDINAL, p: LONG POINTER TO cell object] RETURNS [cnt: CARDINAL] = BEGIN othCnt: CARDINAL; lp, lpp: LONG POINTER TO list; lev ← lev + 1; cnt ← 0; othCnt ← 0; lp ← p.ptr; WHILE lp # NIL DO lp.mark ← 0; lp ← lp.nxt; ENDLOOP; lp ← p.ptr; WHILE lp # NIL DO IF lp.ob.otyp = cell AND lp.mark = 0 THEN BEGIN othCnt ← othCnt + count[lev, LOOPHOLE[lp.ob]]; cnt ← cnt + 1; lpp ← lp.nxt; WHILE lpp # NIL DO IF lp.ob = lpp.ob THEN lpp.mark ← 1; lpp ← lpp.nxt; ENDLOOP; END; lp ← lp.nxt; ENDLOOP; lp ← p.ptr; WHILE lp # NIL DO lp.mark ← 0; lp ← lp.nxt; ENDLOOP; cnt ← MAX[cnt, othCnt]; cnt ← MAX[cnt, 1]; END; drCll: PROCEDURE [ lev: CARDINAL, p: LONG POINTER TO cell object, x, y: INTEGER, wd, inCnt: CARDINAL] = BEGIN lp, lpp: LONG POINTER TO list; cp: LONG POINTER TO cList; nxtx: INTEGER; twd, tt: CARDINAL; s: STRING; lev ← lev + 1; [s, cp] ← cellNam[p, inCnt]; nxtx ← MeasureText[s, fnt]; lpp ← makeList[ makeCnText[s, nxtx, yWdt, wd, p, cp], x, y + wd*yWdt/2, 0, 0]; lpp.nxt ← cnList; cnList ← lpp; nxtx ← nxtx + x + 5; lp ← p.ptr; WHILE lp # NIL DO IF lp.ob.otyp = cell AND lp.mark = 0 THEN BEGIN lpp ← lp; tt ← 0; WHILE lpp # NIL DO IF lp.ob = lpp.ob THEN BEGIN tt ← tt + 1; lpp.mark ← 1; END; lpp ← lpp.nxt; ENDLOOP; twd ← count[lev, LOOPHOLE[lp.ob]]; drCll[lev, LOOPHOLE[lp.ob], nxtx, y, twd, tt]; y ← y + twd*yWdt; END; lp ← lp.nxt; ENDLOOP; END; cnList ← NIL; cellNameMode ← TRUE; y ← 40; x ← 20; cp ← cellList; WHILE cp # NIL DO width ← count[0, LOOPHOLE[cp.ob]]; drCll[0, LOOPHOLE[cp.ob], x, y, width, 1]; y ← y + width*yWdt + 5; cp ← cp.nxt; ENDLOOP; dChange ← FALSE; reDrawRect[[0, 0, 0, 0], 2, TRUE, FALSE, TRUE]; END; cellNam: PROCEDURE [p: LONG POINTER TO cell object, cnt: CARDINAL] RETURNS [STRING, LONG POINTER TO cList] = BEGIN cpp: LONG POINTER TO cList ← cellList; lp: LONG POINTER TO list ← p.ptr; i: INTEGER ← 0; flg: BOOLEAN ← FALSE; sss.length ← 0; IF cnt > 1 THEN BEGIN AppendDecimal[sss, cnt]; AppendChar[sss, 'x]; END; WHILE cpp # NIL DO IF p = cpp.ob THEN BEGIN AppendString[sss, cpp.name]; flg ← TRUE; EXIT; END; cpp ← cpp.nxt; ENDLOOP; IF NOT flg THEN AppendString[sss, "--noname--"]; AppendChar[sss, '{]; WHILE lp # NIL DO i ← i + 1; lp ← lp.nxt; ENDLOOP; AppendDecimal[sss, i]; AppendChar[sss, '}]; RETURN[sss, cpp]; END; delCellDef: PUBLIC PROCEDURE [ cn: LONG POINTER TO cList, ob: LONG POINTER TO cell object] = BEGIN sp: LONG POINTER TO list; lpp: LONG POINTER TO list; defobs: LONG POINTER TO list ← ob.ptr; scp, tcp: LONG POINTER TO cell object; scp ← GetCellSuper[]; sp ← GetSuperPointer[]; lp ← sp; ob.returnable ← TRUE; WHILE lp # NIL DO IF lp.ob = ob THEN BEGIN lpp ← sp; IF masterList = lp THEN masterList ← lp.nxt ELSE WHILE lpp # NIL DO IF lpp.nxt = lp THEN BEGIN lpp.nxt ← lp.nxt; EXIT; END; lpp ← lpp.super; ENDLOOP; tcp ← scp; WHILE tcp # NIL DO IF tcp.ptr = lp THEN BEGIN tcp.ptr ← lp.nxt; EXIT; END; tcp ← tcp.super; ENDLOOP; lp.nxt ← NIL; lpp ← lp.super; flushDel[lp]; lp ← lpp; END ELSE lp ← lp.super; ENDLOOP; IF cn # NIL THEN BEGIN IF cellList = cn THEN cellList ← cellList.nxt ELSE BEGIN cp ← cellList; WHILE cp # NIL DO IF cp.nxt = cn THEN BEGIN cp.nxt ← cn.nxt; EXIT; END; cp ← cp.nxt; ENDLOOP; END; cn.ob.p.release[cn.ob]; END; END; moveOb: PUBLIC PROCEDURE [p: LONG POINTER TO list, x, y: INTEGER] = BEGIN reDrawRect[getRect[p], 3, TRUE, TRUE, FALSE]; p.lx ← p.lx + x; p.ly ← p.ly + y; reDrawRect[getRect[p], 0, TRUE, TRUE, FALSE]; END; doHard: PUBLIC cmdProc = BEGIN ss: STRING; ke: keyEvent; ok: BOOLEAN; [ok, ss, ke] ← typeIn[ "Type File Name", "without extension", "I will add .press"]; refreshTypeInScreen[]; IF NOT ok THEN RETURN; hardOut[ss, masterList]; END; doExpS: PUBLIC cmdProc = BEGIN backPnt: LONG POINTER TO LONG POINTER TO list; lp ← masterList; backPnt ← @masterList; WHILE lp # NIL DO IF lp.selected AND (lp.ob.otyp = cell OR lp.ob.otyp=bus) THEN BEGIN backPnt↑ ← lp.nxt; anyChanges ← sinceIOchanges ← TRUE; doTheExp[lp]; RETURN; END; backPnt ← @lp.nxt; lp ← lp.nxt; ENDLOOP; END; doExpP: PUBLIC cmdProc = BEGIN backPnt: LONG POINTER TO LONG POINTER TO list; lp ← masterList; backPnt ← @masterList; WHILE lp # NIL DO IF (lp.ob.otyp = cell OR lp.ob.otyp=bus) AND lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN BEGIN anyChanges ← sinceIOchanges ← TRUE; backPnt↑ ← lp.nxt; doTheExp[lp]; RETURN; END; backPnt ← @lp.nxt; lp ← lp.nxt; ENDLOOP; END; doTheExp: PROCEDURE [lpp: LONG POINTER TO list] = BEGIN dp: LONG POINTER TO cell object; bb: LONG POINTER TO bus object; lz: LONG POINTER TO list; id: CARDINAL ← lpp.idx; xo: CARDINAL ← BITAND[id, 1]; -- IF xo#0 THEN id←id+8; id ← BITAND[id, 12]; IF lpp # NIL THEN BEGIN IF lpp.ob.otyp=bus THEN BEGIN x,y,len:INTEGER; bb←LOOPHOLE[lpp.ob]; lz←NIL; x←lpp.lx; y←lpp.ly+bb.offsetFirst; len←bb.firstLength; THROUGH [0..bb.wCnt) DO lqp←makeList[makeWire[len,bb.wwidth,bb.l],x,y,0,0]; lqp.nxt←lz;lz←lqp; x←x+bb.wspace; y←y+bb.topIncr; len←len+bb.lenIncr; ENDLOOP; END ELSE IF lpp.ob.otyp=cell THEN BEGIN dp ← LOOPHOLE[lpp.ob]; lqp ← dp.ptr; lz ← NIL; WHILE lqp # NIL DO lz ← copyObject[lp: lqp, mp: lz, xoff: lpp.lx, yoff: lpp.ly]; lqp ← lqp.nxt; ENDLOOP; END; WHILE id # 0 DO rotReflList[FALSE, lz, TRUE]; id ← id - 4; ENDLOOP; IF xo # 0 THEN rotReflList[TRUE, lz, TRUE]; lqp ← lz; WHILE lqp # NIL AND lqp.nxt # NIL DO lqp ← lqp.nxt; ENDLOOP; IF lqp # NIL THEN BEGIN lqp.nxt ← masterList; masterList ← lz; END; lpp.nxt ← NIL; -- this is a storage leak, but the screen updaters may -- be holding a pointer to this list, for drawing a selection box. -- flushDel[lpp]; dChange ← TRUE; END; reCount[]; END; reCount: PUBLIC PROCEDURE = BEGIN selCount ← 0; lp ← masterList; WHILE lp # NIL DO IF lp.selected THEN selCount ← selCount + 1; lp ← lp.nxt; ENDLOOP; END; undrawUnsel: PROCEDURE [mp: LONG POINTER TO list] = BEGIN r: Rect; selCount ← 0; lp ← mp; ii ← 1; jj ← 1; WHILE lp # NIL DO IF lp.selected THEN BEGIN lp.selected ← FALSE; IF jj < ii THEN BEGIN r ← IF jj = 1 THEN getRect[lp] ELSE mergeRects[r, getRect[lp]]; jj ← jj + 1; END ELSE BEGIN IF jj = 1 THEN reDrawRect[getRect[lp], 1, TRUE, TRUE, FALSE] ELSE reDrawRect[mergeRects[r, getRect[lp]], 1, TRUE, TRUE, FALSE]; jj ← 1; ii ← ii + 1; END; END; lp ← lp.nxt; ENDLOOP; IF jj > 1 THEN reDrawRect[r, 1, TRUE, TRUE, FALSE]; END; selSingle: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN lpp: LONG POINTER TO list ← NIL; sflg: BOOLEAN ← FALSE; lp ← mp; IF lp = NIL THEN RETURN; WHILE lp # NIL DO IF lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN BEGIN IF lpp = NIL THEN lpp ← lp; IF sflg THEN BEGIN lpp ← lp; EXIT; END; IF lp.selected THEN sflg ← TRUE; END; lp ← lp.nxt; ENDLOOP; undrawUnsel[mp]; IF lpp = NIL THEN RETURN; lpp.selected ← TRUE; selCount ← 1; setupSelDisplay[lpp]; drawNewlySel[lpp]; END; selExtend: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN lp ← mp; WHILE lp # NIL DO IF NOT lp.selected AND lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN BEGIN lp.selected ← TRUE; selCount ← selCount + 1; drawNewlySel[lp]; setupSelDisplay[lp]; RETURN; END; lp ← lp.nxt; ENDLOOP; END; selNewThing: PUBLIC PROCEDURE [ mp, lp: LONG POINTER TO list, unOthers: BOOLEAN] = BEGIN IF unOthers THEN BEGIN undrawUnsel[mp]; selCount ← 0; END; IF lp = NIL THEN RETURN; lp.selected ← TRUE; selCount ← selCount + 1; setupSelDisplay[lp]; END; unselSingle: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN lp ← mp; WHILE lp # NIL DO IF lp.selected AND lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN BEGIN nullifySelDisplay[]; lp.selected ← FALSE; selCount ← selCount - 1; reDrawRect[getRect[lp], 1, TRUE, TRUE, FALSE]; RETURN; END; lp ← lp.nxt; ENDLOOP; END; selAreaSingle: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN x1, x2, y1, y2: INTEGER; undrawUnsel[mp]; nullifySelDisplay[]; x1 ← MIN[xx, selMarkPnt.x]; y1 ← MIN[yy, selMarkPnt.y]; x2 ← MAX[xx, selMarkPnt.x]; y2 ← MAX[yy, selMarkPnt.y]; lp ← mp; WHILE lp # NIL DO IF inRect[lp, x1, y1, x2, y2] THEN BEGIN lp.selected ← TRUE; selCount ← selCount + 1; drawNewlySel[lp]; END; lp ← lp.nxt; ENDLOOP; END; selAreaExtend: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN x1, x2, y1, y2: INTEGER; nullifySelDisplay[]; x1 ← MIN[xx, selMarkPnt.x]; y1 ← MIN[yy, selMarkPnt.y]; x2 ← MAX[xx, selMarkPnt.x]; y2 ← MAX[yy, selMarkPnt.y]; lp ← mp; WHILE lp # NIL DO IF inRect[lp, x1, y1, x2, y2] AND NOT lp.selected THEN BEGIN lp.selected ← TRUE; selCount ← selCount + 1; drawNewlySel[lp]; END; lp ← lp.nxt; ENDLOOP; END; unselAreaSingle: PUBLIC PROCEDURE [mp: LONG POINTER TO list, xx, yy: INTEGER] = BEGIN x1, x2, y1, y2: INTEGER; nullifySelDisplay[]; x1 ← MIN[xx, selMarkPnt.x]; y1 ← MIN[yy, selMarkPnt.y]; x2 ← MAX[xx, selMarkPnt.x]; y2 ← MAX[yy, selMarkPnt.y]; lp ← mp; WHILE lp # NIL DO IF inRect[lp, x1, y1, x2, y2] AND lp.selected THEN BEGIN lp.selected ← FALSE; selCount ← selCount - 1; reDrawRect[getRect[lp], 1, TRUE, TRUE, FALSE]; END; lp ← lp.nxt; ENDLOOP; END; inRect: PROCEDURE [lp: LONG POINTER TO list, x1, y1, x2, y2: INTEGER] RETURNS [BOOLEAN] = BEGIN x, y, sx, sy: INTEGER; x ← lp.lx; y ← lp.ly; IF BITAND[lp.idx, 4] = 0 THEN BEGIN sx ← lp.ob.size[0]; sy ← lp.ob.size[1]; END ELSE BEGIN sx ← lp.ob.size[1]; sy ← lp.ob.size[0]; END; IF x >= x2 OR y >= y2 OR x + sx <= x1 OR y + sy <= y1 THEN RETURN[FALSE]; IF x < x1 OR y < y1 OR x + sx > x2 OR y + sy > y2 THEN RETURN[FALSE]; RETURN[TRUE]; END; localCellName: STRING ← [50]; DepletionStrengthName: PUBLIC PROC [imp: DepletionStrength] RETURNS [STRING] = BEGIN RETURN[(SELECT imp FROM enhancement => "enh", zeroThresh => "0-thresh", weakDepletion => "wk depl", strongDepletion => "depl", ENDCASE => "?")]; END; setupSelDisplay:PROCEDURE[lp: listPtr] = BEGIN localNameString.length ← 0; AppendProps[to: localNameString, from: lp.props]; locIName ← localNameString; localCellName.length ← 0; WITH dob: lp.ob SELECT FROM wire => BEGIN AppendLevel[to: localCellName, from: dob.l]; AppendString[to: localCellName, from: " wire"]; locCell ← localCellName; END; rect => BEGIN AppendLevel[to: localCellName, from: dob.l]; AppendString[to: localCellName, from: " rectangle"]; locCell ← localCellName; END; xstr => BEGIN AppendString[to: localCellName, from: DepletionStrengthName[dob.impl]]; AppendString[to: localCellName, from: " "]; AppendLevel[to: localCellName, from: dob.l]; AppendString[to: localCellName, from: " xstr"]; locCell ← localCellName; END; cont => BEGIN AppendLevel[to: localCellName, from: dob.l]; AppendString[to: localCellName, from: " contact"]; locCell ← localCellName; END; bus => BEGIN AppendString[to: localCellName, from: ""]; AppendDecimal[s: localCellName, n: dob.wCnt]; AppendString[to: localCellName, from: "-wire "]; AppendLevel[to: localCellName, from: dob.l]; AppendString[to: localCellName, from: " bus"]; locCell ← localCellName; END; text => locCell←"text"; cnText => locCell←"cell name text"; cell => BEGIN FOR cpp: cListPtr ← cellList, cpp.nxt WHILE cpp # NIL DO IF lp.ob = cpp.ob THEN BEGIN AppendString[to: localCellName, from: "instance of cell "]; AppendString[to: localCellName, from: cpp.name]; locCell ← localCellName; RETURN; END; ENDLOOP; locCell←"instance of unnamed cell"; END; ENDCASE => NULL; END; AppendLevel: PROC [to: STRING, from: level] = BEGIN AppendString[to: to, from: (SELECT from FROM cut => "cut", dif => "n-diffusion", pol => "poly", met => "metal", imp => "depletion implant", ovg => "overglass", bur => "buried contact", snerd => "?", cut2 => "inter-metal via", pdif => "p-diffusion", pwelCont => "p-diffusion to substrate", met2 => "metal2", pwel => "p-substrate", nwel => "n-well", nwelCont => "n-diffusion to well", ENDCASE => "unspecified")]; END; nullifySelDisplay:PROCEDURE = BEGIN locIName←""; locCell←"()"; END; rotReflSel: PUBLIC PROCEDURE [refl: BOOLEAN] = BEGIN rotReflList[refl, masterList, FALSE]; END; rotReflList: PROCEDURE [ refl: BOOLEAN, mlp: LONG POINTER TO list, force: BOOLEAN] = BEGIN mix, miy, may, max, xx, yy, mdif: INTEGER; flg: BOOLEAN ← FALSE; ii: CARDINAL; lp ← mlp; WHILE lp # NIL DO IF lp.selected OR force THEN BEGIN ii ← IF BITAND[lp.idx, 4] = 0 THEN 0 ELSE 1; IF NOT flg THEN BEGIN mix ← lp.lx; miy ← lp.ly; may ← lp.ly + lp.ob.size[ii + 1]; max ← lp.lx + lp.ob.size[ii]; flg ← TRUE; END ELSE BEGIN mix ← MIN[mix, lp.lx]; miy ← MIN[miy, lp.ly]; may ← MAX[may, lp.ly + lp.ob.size[ii + 1]]; max ← MAX[max, lp.lx + lp.ob.size[ii]]; END; END; lp ← lp.nxt; ENDLOOP; mdif ← MAX[max - mix, may - miy]; lp ← mlp; WHILE lp # NIL DO IF lp.selected OR force THEN BEGIN ii ← IF BITAND[lp.idx, 4] = 0 THEN 0 ELSE 1; anyChanges ← sinceIOchanges ← TRUE; IF refl THEN BEGIN lp.idx ← BITXOR[lp.idx, 1]; lp.lx ← max - lp.lx + mix - lp.ob.size[ii]; END ELSE BEGIN lp.idx ← BITAND[lp.idx + 4, 15]; IF BITAND[lp.idx, 1] # 0 THEN lp.idx ← BITXOR[lp.idx, 8]; xx ← lp.lx - mix; yy ← lp.ly - miy; lp.lx ← mix - yy - lp.ob.size[ii + 1] + may - miy; lp.ly ← miy + xx; END; lp.ridx ← BITXOR[lp.idx, 1]; END; lp ← lp.nxt; ENDLOOP; IF force THEN RETURN; IF refl THEN reDrawRect[[mix, miy, max, may], 1, TRUE, TRUE, FALSE] ELSE reDrawRect[[mix, miy, mix + mdif, miy + mdif], 1, TRUE, TRUE, FALSE]; END; rotReflPnt: PUBLIC PROCEDURE [refl: BOOLEAN, xx, yy: INTEGER] = BEGIN mdif: INTEGER; lp ← masterList; WHILE lp # NIL DO IF lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN BEGIN lp.idx ← IF refl THEN BITXOR[lp.idx, 1] ELSE BITAND[lp.idx + 4, 15]; lp.ridx ← BITXOR[lp.idx, 1]; mdif ← MAX[lp.ob.size[0], lp.ob.size[1]]; reDrawRect[ [lp.lx, lp.ly, lp.lx + mdif, lp.ly + mdif], 1, TRUE, TRUE, FALSE]; anyChanges ← sinceIOchanges ← TRUE; RETURN; END; lp ← lp.nxt; ENDLOOP; END; mergeRects: PUBLIC PROCEDURE [a, b: Rect] RETURNS [Rect] = BEGIN RETURN[[MIN[a.x1, b.x1], MIN[a.y1, b.y1], MAX[a.x2, b.x2], MAX[a.y2, b.y2]]]; END; getRect: PUBLIC PROCEDURE [l: LONG POINTER TO list] RETURNS [r: Rect] = BEGIN ii: CARDINAL ← IF BITAND[l.idx, 4] = 0 THEN 0 ELSE 1; oi:INTEGER←l.ob.surround; r.x1 ← l.lx-oi; r.y1 ← l.ly-oi; r.x2 ← l.lx + l.ob.size[ii]+oi; r.y2 ← l.ly + l.ob.size[ii + 1]+oi; END; cannonRect: PUBLIC PROCEDURE [r: Rect] RETURNS [Rect] = BEGIN t: INTEGER; IF r.x1 > r.x2 THEN BEGIN t ← r.x1; r.x1 ← r.x2; r.x2 ← t; END; IF r.y1 > r.y2 THEN BEGIN t ← r.y1; r.y1 ← r.y2; r.y2 ← t; END; RETURN[r]; END; makeList: PUBLIC PROCEDURE [ p: LONG POINTER TO object, x, y: INTEGER, o: orientation, refl: reflection] RETURNS [lp: LONG POINTER TO list] = BEGIN lp ← alocList[]; lp↑.lx ← x; lp↑.ly ← y; lp↑.ob ← p; lp↑.idx ← o*2 + refl; lp↑.ridx ← BITXOR[1, lp.idx]; END; putProp: PUBLIC PROC [lp: listPtr, attribute, value: Atom, allowDuplAttr: BOOLEAN ← FALSE] = BEGIN IF attribute=NIL THEN BEGIN WHILE lp.props#NIL DO victim: propPtr ← lp.props; lp.props ← victim.next; ppUncZone.FREE[@victim]; ENDLOOP; END ELSE BEGIN IF NOT allowDuplAttr THEN BEGIN pp: LONG POINTER TO propPtr ← @lp.props; WHILE pp↑#NIL DO IF pp.attribute=attribute THEN BEGIN victim: propPtr ← pp↑; pp↑ ← victim.next; ppUncZone.FREE[@victim]; END ELSE pp ← @pp.next; ENDLOOP; END; IF value#NIL THEN lp.props ← ppUncZone.NEW[prop ← [next: lp.props, attribute: attribute, value: value]]; END; END; AppendProps: PUBLIC PROC [to: LONG STRING, from: propPtr, startPos: CARDINAL ← 0] = BEGIN NoMoreRoomInTo: ERROR = CODE; Periods: PROC [n: CARDINAL] = BEGIN WHILE n>0 DO IF to.maxlength<=to.length THEN ERROR NoMoreRoomInTo; to[to.length] ← '.; to.length ← to.length+1; n ← n-1; ENDLOOP; END; Append: PROC [s: LONG STRING] = BEGIN IF NOT started THEN BEGIN started ← TRUE; IF startPos>0 THEN Periods[3]; END; IF s.length<=startPos THEN startPos ← startPos-s.length ELSE BEGIN FOR i: CARDINAL IN [startPos..s.length) DO IF to.maxlength<=to.length+3 THEN Periods[4]; to[to.length] ← s[i]; to.length ← to.length+1; ENDLOOP; startPos ← 0; END; END; started: BOOLEAN ← FALSE; FOR p: propPtr ← from, p.next WHILE p#NIL DO ENABLE NoMoreRoomInTo => GOTO Finished; IF started THEN Append[", "]; Append[LOOPHOLE[p.attribute]]; Append[": "]; Append[LOOPHOLE[p.value]]; ENDLOOP; EXITS Finished => NULL; END; -- of AppendProps inrect: PUBLIC PROCEDURE [x, y: INTEGER, lp: LONG POINTER TO list] RETURNS [BOOLEAN] = BEGIN xs, ys: INTEGER; IF BITAND[lp.idx, 4] = 0 THEN BEGIN xs ← lp.ob.size[0]; ys ← lp.ob.size[1]; END ELSE BEGIN xs ← lp.ob.size[1]; ys ← lp.ob.size[0]; END; IF x IN [lp.lx..lp.lx + xs] AND y IN [lp.ly..lp.ly + ys] THEN RETURN[TRUE] ELSE RETURN[FALSE]; END; flushDel: PUBLIC PROCEDURE [lp: LONG POINTER TO list] = BEGIN lpp: LONG POINTER TO list; WHILE lp # NIL DO lp.ob.p.release[lp.ob]; lpp ← lp.nxt; lp.deleted ← TRUE; freeList[lp]; lp ← lpp; ENDLOOP; END; --copy stuff: copyObject: PUBLIC PROCEDURE [lp, mp: LONG POINTER TO list, xoff, yoff: INTEGER] RETURNS [np: LONG POINTER TO list] = BEGIN np ← makeList[lp.ob.p.anotherme[lp.ob], lp.lx + xoff, lp.ly + yoff, 0, 0]; np.idx ← lp.idx; np.ridx ← lp.ridx; np.selected ← FALSE; copyProps[np, lp]; np ← insertList[mp, np]; END; copyProps: PUBLIC PROCEDURE [n, o: listPtr] = BEGIN n.props ← NIL; FOR pop: propPtr ← o.props, pop.next WHILE pop # NIL DO n.props ← ppUncZone.NEW[prop ← [next: n.props, attribute: pop.attribute, value: pop.value]]; ENDLOOP; END; minmax: PUBLIC PROCEDURE [lp: LONG POINTER TO list] RETURNS [mix, miy, max, may: INTEGER] = BEGIN flg: BOOLEAN ← TRUE; ii: CARDINAL; mix ← max ← miy ← may ← 0; WHILE lp # NIL DO ii ← IF BITAND[lp.idx, 4] = 0 THEN 0 ELSE 1; IF flg THEN BEGIN mix ← lp.lx; max ← lp.lx + lp.ob.size[ii]; miy ← lp.ly; may ← lp.ly + lp.ob.size[ii + 1]; flg ← FALSE; END ELSE BEGIN mix ← MIN[mix, lp.lx]; max ← MAX[max, lp.lx + lp.ob.size[ii]]; miy ← MIN[miy, lp.ly]; may ← MAX[may, lp.ly + lp.ob.size[ii + 1]]; END; lp ← lp.nxt; ENDLOOP; END; typeInNum: PUBLIC PROCEDURE [os1, os2, os3: STRING] RETURNS [bb: BOOLEAN, ii: INTEGER, ke: keyEvent] = BEGIN s:STRING; i:CARDINAL; [bb,s,ke]←typeIn[os1,os2,os3]; ii←0; IF NOT bb THEN RETURN; FOR i IN[0..s.length) DO IF s[i] IN ['0..'9] THEN ii←ii*10+(s[i]-'0); ENDLOOP; IF s[0]='- THEN ii←-ii; FreeString[s]; END; typeIn: PUBLIC PROCEDURE [os1, os2, os3: STRING] RETURNS [bb: BOOLEAN, is: STRING, ke: keyEvent] = BEGIN pos: CARDINAL; invertColors[]; EraseArea[tiCx - 3, bwBottom+4, 700, bwMsgBottom-6]; pos ← ReplaceText[os1, tiCx, bwBottom + 20, fnt, normal]; pos ← ReplaceText[os2, tiCx, bwBottom + 30, fnt, normal]; pos ← ReplaceText[os3, tiCx, bwBottom + 40, fnt, normal]; [bb, is, ke] ← getstr[tiCx, bwBottom + 50]; IF bb THEN is ← newString[is] ELSE refreshTypeInScreen[]; restoreColors[]; END; typeInC: PUBLIC PROCEDURE [os1, os2, os3: STRING] RETURNS [kk: keyEvent] = BEGIN pos: CARDINAL; invertColors[]; EraseArea[tiCx - 3, bwBottom+4, 700, bwMsgBottom-6]; pos ← ReplaceText[os1, tiCx, bwBottom + 20, fnt, normal]; pos ← ReplaceText[os2, tiCx, bwBottom + 30, fnt, normal]; pos ← ReplaceText[os3, tiCx, bwBottom + 40, fnt, normal]; kk ← getchr[]; restoreColors[]; END; typeOut: PUBLIC PROCEDURE [os1, os2, os3: STRING] = BEGIN pos: CARDINAL; EraseArea[tiCx - 3, bwBottom+4, 700, bwMsgBottom-6]; pos ← ReplaceText[os1, tiCx, bwBottom + 20, fnt, normal]; pos ← ReplaceText[os2, tiCx, bwBottom + 30, fnt, normal]; pos ← ReplaceText[os3, tiCx, bwBottom + 40, fnt, normal]; END; refreshTypeInScreen: PUBLIC PROCEDURE = BEGIN EraseArea[tiCx - 3, bwBottom+4, 700, bwMsgBottom-6]; END; getErfil: PUBLIC cmdProc = BEGIN ok: BOOLEAN; [ok, ss, ke] ← typeIn["", "Type Error File Name:", "(in full)"]; IF NOT ok THEN RETURN; dChange ← TRUE; IF NOT openErfile[ss] THEN RETURN; END; enterText: PUBLIC cmdProc = BEGIN IF NOT bb THEN RETURN; FOR lp: listPtr ← masterList, lp.nxt WHILE lp # NIL DO IF (lp.ob.otyp = wire OR lp.ob.otyp = cont) AND lp.ob.p.inMe[lp.ob, xx - lp.lx, yy - lp.ly, lp.idx] THEN {RequestItemProp[lp]; IF lp.selected THEN setupSelDisplay[lp]; RETURN}; ENDLOOP; END; enterName: PUBLIC cmdProc = BEGIN FOR lp: listPtr ← masterList, lp.nxt WHILE lp # NIL DO IF lp.selected THEN {RequestItemProp[lp]; setupSelDisplay[lp]; RETURN}; ENDLOOP; END; RequestItemProp: PROC [lp: listPtr] = BEGIN OPEN ChipUserInt; s: STRING ← NIL; BEGIN ParseAtom: PROC [start, beyondEnd: CARDINAL] RETURNS [Atom] = BEGIN WHILE start<beyondEnd AND s[start]=' DO start ← start+1 ENDLOOP; WHILE start<beyondEnd AND s[beyondEnd-1]=' DO beyondEnd ← beyondEnd-1; ENDLOOP; IF start<beyondEnd THEN BEGIN ts: STRING ← [200]; ts.length ← beyondEnd-start; FOR i: CARDINAL IN [0..ts.length) DO ts[i] ← s[start+i] ENDLOOP; RETURN[MakeAtom[ts]]; END ELSE RETURN[NIL]; END; -- of ParseAtom isSignal: BOOLEAN = SELECT lp.ob.otyp FROM wire, cont => TRUE, ENDCASE => FALSE; firstColon: CARDINAL; attribute, value: Atom; s ← RequestString[ s1: "Enter attribute-value pair as ATTRIBUTE: VALUE"L, initResult: (IF isSignal THEN "SIGNAL NAME: "L ELSE "INSTANCE NAME: "L) ! Punt => GOTO ForgetIt]; firstColon ← s.length; IF s.length>0 THEN BEGIN FOR i: CARDINAL IN [0..s.length) DO IF s[i]=': THEN {firstColon ← i; EXIT}; ENDLOOP; END; attribute ← ParseAtom[0, firstColon]; value ← ParseAtom[firstColon+1, s.length]; IF attribute#NIL OR HeSaysYes["Shall I delete this node's entire property list?"L] THEN BEGIN putProp[lp: lp, attribute: attribute, value: value, allowDuplAttr: FALSE]; anyChanges ← sinceIOchanges ← dChange ← TRUE; END; GOTO ForgetIt; EXITS ForgetIt => IF s#NIL THEN FreeString[s]; END; END; END.