-- 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.