-- I/O module of silicon (pretty picture) program

-- last modified by McCreight, December 3, 1982  9:44 AM
-- modified by Petit, September 20, 1981
DIRECTORY
  InlineDefs,
  StreamDefs,
  SystemDefs,
  IODefs,
  AltoDefs,
  DirectoryDefs,
  AltoFileDefs,
  StringDefs,
  ppoutdefs,
  ppdddefs,ppddefs,
  ppdefs;
ppio: PROGRAM
  IMPORTS
    ppdefs, ppddefs, ppdddefs,ppoutdefs, InlineDefs, StreamDefs, StringDefs, DirectoryDefs
  EXPORTS ppddefs =
  BEGIN
  OPEN ppdefs, ppddefs, ppdddefs,ppoutdefs, InlineDefs, StreamDefs, IODefs, StringDefs,
    DirectoryDefs;

  fp: AltoFileDefs.FP;

  -- press command byte defs:
  fontset: CARDINAL = 160B;
  setx: CARDINAL = 356B;
  sety: CARDINAL = 357B;
  showchar: CARDINAL = 360B;
  showcharim: CARDINAL = 363B;
  showrect: CARDINAL = 376B;
  setBrt: CARDINAL = 370B;
  setHue: CARDINAL = 371B;
  setSat: CARDINAL = 372B;

  currentColor: level;
  hardCopyScaleNumber: INTEGER = 42;
  hScale: INTEGER;

  hBrttab: ARRAY level OF CARDINAL ← [30, 255, 255, 255, 235, 255, 190, 255
		,180,255,255,180,255,220,255,255];
  hHuetab: ARRAY level OF CARDINAL ← [10, 70, 215, 130, 40, 220, 10, 220
		,10,70,255,15,255,5,5,255];
  hSattab: ARRAY level OF CARDINAL ← [0, 190, 180, 190, 225, 220, 112, 120
		,255,190,255,200,255,80,255,255];
  layNam: ARRAY level OF CHARACTER ← ['C, 'D, 'P, 'M, 'I, 'G, 'B, 'X,
		'O, 'Q, 'X, 'S, 'X, 'T, 'X, 'X];

  byteCnt, saveByte: CARDINAL;
  hscale: PROCEDURE [x, y: INTEGER] RETURNS [INTEGER, INTEGER];

  -- dummy font name:
  fontName: ARRAY [1..20] OF CARDINAL ← [
    9, 110B, 105B, 114B, 126B, 105B, 124B, 111B, 103B, 101B, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0];

  inObject: PROCEDURE [version: CARDINAL] RETURNS [ob: LONG POINTER TO object] =
    BEGIN
    j, k: CARDINAL;
    w, l, we, le,ii,sur: INTEGER;
    lev:level;
    sur←6;
    j ← inWord[];
    SELECT j FROM
      1 =>
        BEGIN
        k ← inWord[];  -- get unique cell id
        ob ← cellNameA[k].p.anotherme[cellNameA[k]]
        END;
      2 =>
        BEGIN
        w ← inWord[];
        l ← inWord[];
        k ← inWord[];
        IF BITAND[k,20000B]#0 THEN j ← inWord[];-- if angle, get angle ext.
        IF version>4 AND BITAND[k,10000B]#0
	  THEN sur ← inWord[];-- if pdif, get surround
        we ← BITAND[BITSHIFT[k, -6], 77B];
        le ← BITAND[k, 77B];
        ob ←
          IF BITAND[k, 40000B] # 0 THEN makePullup[w, l,we,le]
          ELSE IF BITAND[k,20000B]#0 THEN
		 makeAngleXstr[w, l, BITAND[k, 100000B] # 0,we,le,j]
          ELSE IF BITAND[k,10000B]#0 THEN
	    makePXstr[w, l, BITAND[k, 100000B] # 0,we,le,sur]
	  ELSE makeXstr[w, l, BITAND[k, 100000B] # 0,we,le];
        END;
      3 =>
        BEGIN
        j ← inWord[];  -- get contact type
        k ← BITAND[j, 37B];  -- get contact type
        l ← BITSHIFT[j, -8];
	IF version>4 THEN sur←inWord[];
        SELECT contTypA[k] FROM
          mPol => ob ← makePolycon[l];
          mDif => ob ← makeDifcon[l];
          butt => ob ← makeButcon[];
          burr => BEGIN
		w←inWord[];
		k←inWord[];
		j←BITSHIFT[k,-8];
		ob ← makeBuCont[w,l,j,BITAND[k,377B]];
	    END;
          mm2 => ob ← makeMmCont[l,0,0];
          mPDif => ob ← makePDifcon[l,sur];
          nwell => ob ← makeNwellcon[l];
          mmDif => ob ← makeMmDifcon[l];
          mmPol => ob ← makeMmPolcon[l];
          mmPDif => ob ← makeMPDifcon[l,sur];
          ENDCASE => ERROR;
        END;
      4 =>
        BEGIN
        w ← inWord[];
        l ← inWord[];
        lev ← inWord[];
	IF version>4 AND lev=pdif THEN sur←inWord[];
        ob ← makeWire[l, w, lev,sur];
        END;
      5 =>
        BEGIN
        w ← inWord[];
        l ← inWord[];
        lev ← inWord[];
        ob ← makeRect[w, l, lev];
        END;
      6 => BEGIN ob ← makeText[inString[]]; END;
      7 =>
        BEGIN
        w ← inWord[];
        l ← inWord[];
        lev ← inWord[];--level
        j ← inWord[];--cnt
        we ← inWord[];--spacing
        le ← inWord[];--top incr
        ii ← inWord[];--bot incr
        ob ← makeBus[l, w, lev,j,we,le,ii];
        END;
      8 =>
        BEGIN
        obb: obPtr = inObject[version];
        w ← inWord[];
        l ← inWord[];
        we ← inWord[];
        le ← inWord[];
        ii ← inWord[];--cnt
        j ← inWord[];--idx
        ob ← makeRep[obb, w, l, we, le, ii, j];
        END;
      ENDCASE => BEGIN ob ← NIL; END;
    END;

  inList: PROCEDURE [ver: CARDINAL] RETURNS [lp: LONG POINTER TO list] =
    BEGIN
    i, j, k, l: CARDINAL;
    tp: LONG POINTER TO list;
    pop: LONG POINTER TO prop;
    lp ← NIL;
    i ← inWord[];
    FOR j IN [0..i) DO
      tp ← alocList[];
      tp.nxt ← lp;
      tp.lx ← inWord[];
      tp.ly ← inWord[];
      tp.idx ← inWord[];
      tp.ridx ← BITXOR[tp.idx, 1];
      tp.ob ← inObject[ver];
      tp.props ← NIL;
      IF ver > 3 THEN
        BEGIN
        k ← inWord[];
        FOR l IN [0..k) DO
          pop ← inProp[];
          IF pop # NIL THEN putProp[tp, pop];
          IF pop # NIL AND pop.ptyp = text THEN tp.gotText ← TRUE;
          ENDLOOP;
        END;
      IF tp.ob # NIL THEN lp ← tp;
      ENDLOOP;
    END;
  inProp: PROCEDURE RETURNS [LONG POINTER TO prop] =
    BEGIN
    i: CARDINAL;
    i ← inWord[];
    SELECT i FROM
      1 =>
        BEGIN
        tp: LONG POINTER TO text prop ← alocTextProp[];
        tp.s ← inString[];
        RETURN[tp];
        END;
      ENDCASE => RETURN[NIL];
    END;

  inWord: PROCEDURE RETURNS [UNSPECIFIED] =
    BEGIN
    IF NOT ppHandle.endof[ppHandle] THEN RETURN[ppHandle.get[ppHandle]]
    ELSE RETURN[0];
    END;

  readAll: PUBLIC PROCEDURE
    RETURNS [mp: LONG POINTER TO list, cp: LONG POINTER TO cList] =
    BEGIN
    i, j, ver: CARDINAL;
    lp, lpp, lqp: LONG POINTER TO list;
    cdp: LONG POINTER TO cell object;
    cpp: LONG POINTER TO cList;
    ss: STRING;
    pop: LONG POINTER TO text prop;
    i ← inWord[];  -- read code word
    ver ← inWord[];  -- read version #
    cCnt ← inWord[];  -- read count of cells
    cellNameA ← DESCRIPTOR[
      GetSpace[(cCnt + 1)*SIZE[LONG POINTER TO object]], cCnt + 1];
    IF ver < 3 THEN ERROR;
    cp ← NIL;
    FOR i IN [0..cCnt] DO
      -- 0 is an illegal cell that can get generated by a bug
      -- in the output routines
      cellNameA[i] ← makeCell[Lambda, Lambda, 0, NIL];
      ENDLOOP;
    FOR i IN [1..cCnt] DO
      j ← inWord[];
      cdp ← cellNameA[j];
      ss ← inString[];
      cdp.size[0] ← cdp.size[2] ← inWord[];
      cdp.size[1] ← inWord[];
      cdp.cnt ← inWord[];
      cdp.ptr ← inList[ver];
      IF ss.length > 0 THEN
        BEGIN
        cpp ← alocCList[];
        cpp.nxt ← cp;
        cp ← cpp;
        cpp.ob ← cdp.p.anotherme[cdp];
        cpp.name ← ss;
        cdp.returnable ← FALSE;
        END;
      ENDLOOP;

    mp ← inList[ver];  -- get master list

    FOR i IN [1..cCnt] DO cellNameA[i].p.release[cellNameA[i]]; ENDLOOP;
    FreeSpace[BASE[cellNameA]];
    lp ← mp;
    mp ← NIL;
    WHILE lp # NIL DO
      IF lp.ob.otyp = text THEN
        BEGIN
        lpp ← mp;
        lqp ← NIL;
        FOR i IN [0..1] DO
          DO
            IF lpp = NIL THEN BEGIN lpp ← lp.nxt; EXIT; END;
            IF ((lpp.ob.otyp = wire AND lpp.ob.l IN [dif..met]) OR lpp.ob.otyp = cont)
              AND lpp.ob.p.inMe[lpp.ob, lp.lx - lpp.lx, lp.ly - lpp.ly, lpp.idx]
              THEN BEGIN lqp ← lpp; EXIT; END;
            lpp ← lpp.nxt;
            ENDLOOP;
          IF lqp # NIL THEN EXIT;
          ENDLOOP;
        IF lqp # NIL THEN
          BEGIN
          pop ← alocTextProp[];
          pop.s ← LOOPHOLE[lp.ob, LONG POINTER TO text object].s;
          putProp[lqp, pop];
          lqp.gotText ← TRUE;
          END;
        lp ← lp.nxt;
        END
      ELSE BEGIN lpp ← lp.nxt; lp.nxt ← mp; mp ← lp; lp ← lpp; END;
      ENDLOOP;
    END;

  inString: PROCEDURE RETURNS [s: STRING] =
    BEGIN
    i, j, len: CARDINAL;
    flg: BOOLEAN;
    j ← inWord[];
    len ← BITSHIFT[j, -8];
    IF len = 0 THEN BEGIN s ← ""; RETURN; END;
    s ← GetString[len];
    s.length ← 0;
    flg ← TRUE;
    FOR i IN [0..len) DO
      IF flg THEN AppendChar[s, BITAND[j, 377B]]
      ELSE BEGIN j ← inWord[]; AppendChar[s, BITSHIFT[j, -8]]; END;
      flg ← NOT flg;
      ENDLOOP;
    END;
  openIfile: PUBLIC PROCEDURE [fname: STRING] RETURNS [BOOLEAN] =
    BEGIN
    IF NOT DirectoryLookup[@fp, fname, FALSE] THEN RETURN[FALSE];
    ppHandle ← NewWordStream[fname, Read];
    RETURN[TRUE];
    END;
  openOTfile: PUBLIC PROCEDURE [fname: STRING] RETURNS [BOOLEAN] =
    BEGIN
    --	IF NOT DirectoryLookup[@fp,fname,FALSE] THEN RETURN[FALSE];
    ppHandle ← NewByteStream[fname, Write + Append];
    RETURN[TRUE];
    END;

  -- ******** hardcopy stuff:

  ovByteCnt: CARDINAL;
  ovLimit: CARDINAL = 10000;
  padWds, pagCnt: CARDINAL;

  hardDrR: drRecord ← [
    [0,0,0,0], [0,0,0,0], hardOutArea, hardOutArea, nullOutl, nulldtxt, 0];
  nullOutl: PROCEDURE [a, b, c, d: INTEGER, q: color, p: POINTER TO Rect] =
    BEGIN END;
  nulldtxt: PROCEDURE [a, b, c, d: INTEGER, s: STRING, p: POINTER TO Rect] =
    BEGIN END;

  hardOut: PUBLIC PROCEDURE [fn: STRING, lp: LONG POINTER TO list] =
    BEGIN
    j: CARDINAL;
    fullName: STRING ← [30];
    dChange ← TRUE;
    fullName.length ← 0;
    AppendString[fullName, fn];
    AppendString[fullName, ".press"];
    IF NOT openOfile[fullName, TRUE] THEN RETURN;
    byteCnt ← 0;
    pagCnt ← 0;
    hWout[0];  -- no text, so this ends the DL
    ovByteCnt ← byteCnt;
    currentColor ← NOcOL;  -- make sure first color we output isn't current
    hardDrR.r ← [cClipx1, cClipy1, cClipx2, cClipy2];
    hardDrR.bigr ← [cClipx1-wellSurround, cClipy1-wellSurround,
		cClipx2+wellSurround, cClipy2+wellSurround];
    hScale ← cScaleN*hardCopyScaleNumber;
    hscale ← IF cScaleD = 1 THEN hscale1 ELSE hscale2;
    WHILE lp # NIL DO
      lp.ob.p.drawme[lp.idx][lp.ob, lp.lx, lp.ly, @hardDrR]; lp ← lp.nxt; ENDLOOP;

    termEnt[];

    padWds ← byteCnt MOD 512;
    padWds ← 256 - padWds/2;
    FOR j IN [0..padWds) DO hWout[0]; ENDLOOP;
    pagCnt ← pagCnt + ((byteCnt + 3)/512);

    byteCnt ← 0;
    hWout[16];  -- dummy font defn -length
    hWout[4];  -- font-set, font
    hBout[32];
    hBout[127];
    FOR j IN [1..20] DO hBout[fontName[j]]; ENDLOOP;
    hWout[32];  -- face, source
    hWout[10];  -- size
    hWout[0];  -- rotation

    FOR j IN [0..256 - 16) DO hWout[0]; ENDLOOP;

    hWout[0];  -- page part
    hWout[0];  -- starts at record 0
    hWout[pagCnt];  -- length in pages
    hWout[padWds];  -- words of padding
    hWout[1];  -- font part
    hWout[pagCnt];  -- starts at record pagCnt
    hWout[1];  -- length in pages
    hWout[0];  -- undefined
    FOR j IN [0..256 - 8) DO hWout[0]; ENDLOOP;

    hWout[27183];  -- code word
    hWout[pagCnt + 3];  -- total records
    hWout[2];  -- # of parts
    hWout[pagCnt + 1];  -- where part dir starts
    hWout[1];  -- # of pages in part dir
    hWout[177777B];  -- # of parts
    hWout[112300B];  -- date
    hWout[106745B];  -- date
    hWout[1];
    hWout[1];
    hWout[177777B];
    hWout[177777B];
    hWout[124B];
    FOR j IN [0..115) DO hWout[177777B]; ENDLOOP;
    FOR j IN [0..256 - 115 - 13) DO hWout[0]; ENDLOOP;
    closeFile[];
    END;


  --hscale:PROCEDURE[x,y:INTEGER]RETURNS[INTEGER,INTEGER]=
  --    BEGIN
  --	RETURN[((cxoff+x)*hScale)/cScaleD,640-((cyoff+y)*hScale)/cScaleD];
  --	RETURN[((cxoff+x)*hScale)/cScaleD,((cClipy2-y)*hScale)/cScaleD];
  --    END;
  hscale1: PROCEDURE [x, y: INTEGER] RETURNS [INTEGER, INTEGER] =
    BEGIN
    tx, ty: INTEGER;
    ty ← cxoff + x;
    tx ← cyoff + y;
    RETURN[tx*hScale, ty*hScale];
    END;
  hscale2: PROCEDURE [x, y: INTEGER] RETURNS [INTEGER, INTEGER] =
    BEGIN
    tx, ty: INTEGER;
    ty ← cxoff + x;
    tx ← cyoff + y;
    RETURN[
      (tx/cScaleD)*hScale + ((tx MOD cScaleD)*hScale)/cScaleD,
        (ty/cScaleD)*hScale + ((ty MOD cScaleD)*hScale)/cScaleD];
    END;
  hscaleRect: PROCEDURE [x1, y1, x2, y2: INTEGER]
    RETURNS [BOOLEAN, INTEGER, INTEGER, INTEGER, INTEGER] = INLINE
    BEGIN
    t: INTEGER;
    IF x1 > x2 THEN BEGIN t ← x1; x1 ← x2; x2 ← t; END;
    IF y1 > y2 THEN BEGIN t ← y1; y1 ← y2; y2 ← t; END;
    IF x1 > cClipx2 OR x2 < cClipx1 OR y1 > cClipy2 OR y2 < cClipy1 THEN
      RETURN[FALSE, 0, 0, 0, 0];
    [x1, y1] ← hscale[MAX[x1, cClipx1], MAX[y1, cClipy1]];
    [x2, y2] ← hscale[MIN[x2, cClipx2], MIN[y2, cClipy2]];
    RETURN[TRUE, x1, y2, x2, y1];
    END;

  hardOutArea: PROCEDURE [x1, y1, x2, y2: INTEGER, l: level, p: POINTER TO Rect] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    [bb, a, b, c, d] ← hscaleRect[x1, y1, x2, y2];
    IF bb THEN
      BEGIN
      IF l # currentColor THEN
        BEGIN
        currentColor ← l;
        hBout[setBrt];
        hBout[hBrttab[l]];
        hBout[setHue];
        hBout[hHuetab[l]];
        hBout[setSat];
        hBout[hSattab[l]];
        END;
      hBout[setx];
      hWout[a];
      hBout[sety];
      hWout[b];
      hBout[showrect];
      hWout[c - a];
      hWout[d - b];
      IF byteCnt > ovByteCnt + ovLimit THEN termEnt[];
      END;
    END;
  termEnt: PROCEDURE =
    BEGIN
    IF byteCnt = ovByteCnt THEN RETURN;
    IF BITAND[byteCnt, 1] # 0 THEN hBout[377];
    hWout[0];  -- type,font set
    hWout[0];  --..
    hWout[0];  --   begin byte #
    hWout[0];  -- first word of byte count
    hWout[0];  -- second word of ditto

    hWout[0];  -- Xe
    hWout[0];  -- Ye
    hWout[0];  -- left
    hWout[0];  -- bottom
    hWout[20600];  -- width
    hWout[27460];  -- height
    hWout[(byteCnt - ovByteCnt + 2)/2];  -- entity length
    pagCnt ← pagCnt + byteCnt/512;
    byteCnt ← byteCnt MOD 512;
    ovByteCnt ← byteCnt;
    currentColor ← NOcOL;  -- make sure first color we output isn't current
    END;
  outWord: PROCEDURE [ww: UNSPECIFIED] = BEGIN ppHandle.put[ppHandle, ww]; END;
  hBout: PROCEDURE [u: UNSPECIFIED] =
    BEGIN
    IF BITAND[byteCnt, 1] = 0 THEN saveByte ← BITSHIFT[BITAND[u, 377B], 8]
    ELSE outWord[BITOR[saveByte, BITAND[u, 377B]]];
    byteCnt ← byteCnt + 1;
    END;
  hWout: PROCEDURE [u: UNSPECIFIED] =
    BEGIN
    IF BITAND[byteCnt, 1] = 0 THEN BEGIN outWord[u]; byteCnt ← byteCnt + 2; END
    ELSE BEGIN hBout[BITSHIFT[u, -8]]; hBout[u]; END;
    END;

-- ********  CIF output stuff

  cellCnt: CARDINAL;

  --matrx is indexed by the orientation index: 0 = no rot.
  --  1= reflection, 4= rot 90 degress to the right, 5= rot 90 + reflected,
  --  8= rotate 180, 9= rotate 180 + refl, 12= rot 270 (right), 13= 270 + refl.

  matrx: ARRAY [0..15] OF RECORD [xsx, xsy, ysx, ysy: [0..15]] = [
    [0, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [
    0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [1, 0, 0, 1], [0, 0, 0, 1], [
    1, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 1, 0], [
    0, 1, 1, 0]];

  --  [0,0,0,0],[0,0,0,0],  [0,1,0,0],[0,1,0,0],
  --  [1,0,0,1],[1,0,0,1],  [0,0,1,0],[0,0,1,0],
  --  [1,0,0,0],[1,0,0,0],  [0,0,0,0],[0,0,0,0],
  --  [0,0,0,1],[0,0,0,1],  [0,1,1,0],[0,1,1,0] ];

  curLayer: level;
  cifScale: INTEGER ← 125;

  cifDrR: drRecord ← [
    [0,0,0,0], [0,0,0,0], cifOrArea, cifOrArea, nullOutl, nullCifDrawText, 0];

  nullCifDrawText:PROCEDURE[x,y,sx,sy:INTEGER,s:STRING,pz:POINTER TO Rect] =
    BEGIN
	NULL;
    END;

  cifOutDrawing: PUBLIC PROCEDURE [fn: STRING, lp: LONG POINTER TO list] =
    BEGIN
    fullName: STRING ← [30];
    cifScale ← pCifScale/2;
    clearMarked[lp];
    fullName.length ← 0;
    AppendString[fullName, fn];
    AppendString[fullName, ".cif"];
    IF NOT openOTfile[fullName] THEN RETURN;
    cellCnt ← 1;
    curLayer ← NOcOL;
    cifDrR.r ← [-77777B, -77777B, 77777B, 77777B];
    cifDrR.bigr ← [-77777B, -77777B, 77777B, 77777B];
    cifOutList[lp, 1, "TopLevel"];
    cifOutStr["C 1 M Y;"];
    cifOutChr[15C];
    cifOutStr[" End ..."];
    cifOutChr[15C];
    ppHandle.destroy[ppHandle];
    END;
  clearMarked: PROCEDURE [lp: LONG POINTER TO list] =
    BEGIN
    WHILE lp # NIL DO
      IF lp.ob.otyp = cell THEN
        BEGIN
        cp: LONG POINTER TO cell object ← LOOPHOLE[lp.ob];
        clearMarked[cp.ptr];
        END;
      lp.ob.marked ← FALSE;
      lp ← lp.nxt;
      ENDLOOP;
    END;
  cifOutList: PROCEDURE [lp: LONG POINTER TO list, cellNum: CARDINAL, cellnam:STRING] =
    BEGIN
    pp: LONG POINTER TO list ← lp;

    WHILE pp # NIL DO
      IF pp.ob.otyp = cell THEN
        BEGIN
        cp: LONG POINTER TO cell object ← LOOPHOLE[pp.ob];
        IF NOT cp.marked THEN
          BEGIN
          cp.marked ← TRUE;
          cellCnt ← cellCnt + 1;
          cp.cnt ← cellCnt;
          cifOutList[cp.ptr, cellCnt, findname[cp]];
          END;
        END;
      pp ← pp.nxt;
      ENDLOOP;

    cifOutStr["DS "];
    curLayer ← NOcOL;
    cifOutNum[cellNum];
    cifOutEndCom[];

    IF cellnam.length>0 THEN cifDrawCellName[cellnam];

    WHILE lp # NIL DO cifOutObject[lp, cellNum = 1]; lp ← lp.nxt; ENDLOOP;

    cifOutStr["DF"];
    curLayer ← NOcOL;
    cifOutEndCom[];
    END;
  cifOutObject: PROCEDURE [lp: LONG POINTER TO list, textOK: BOOLEAN] =
    BEGIN
    IF lp.ob.otyp = cell THEN
      BEGIN
      x, y: locNum;
      ob: LONG POINTER TO cell object ← LOOPHOLE[lp.ob];
      ii: CARDINAL ← lp.idx;
      jj: CARDINAL;
      x ← lp.lx + ob.size[0]*matrx[ii].xsx + ob.size[1]*matrx[ii].xsy;
      y ← lp.ly + ob.size[0]*matrx[ii].ysx + ob.size[1]*matrx[ii].ysy;
      cifOutStr["C "];
      cifOutNum[ob.cnt];
      cifOutChr[' ];
      IF ii # 0 THEN
        BEGIN
        IF (jj ← BITAND[ii, 12]) # 0 THEN
          BEGIN
          cifOutStr["R "];
          cifOutStr[
            (IF jj = 4 THEN "0,1 "
             ELSE
               IF jj = 8 THEN "-1,0 " ELSE IF jj = 12 THEN "0,-1 " ELSE "1,0 ")];
          END;
        IF BITAND[ii, 1] # 0 THEN cifOutStr["M X "];
        END;
      cifOutStr["T "];
      cifOutPoint[x, y];
      cifOutEndCom[];
      END
    ELSE
      BEGIN
      lp.ob.p.drawme[lp.idx][lp.ob, lp.lx, lp.ly, @cifDrR];
      IF textOK AND lp.gotText AND (lp.ob.otyp=wire OR lp.ob.otyp=cont) THEN
        BEGIN
        tp: LONG POINTER TO text prop ← getTextProp[lp];
        cifDrawText[lp.lx, lp.ly, 0, 0, tp.s, NIL,
		IF lp.ob.otyp=cont THEN 'M ELSE layNam[lp.ob.l] ];
        END;
      END;
    END;
  cifOrArea: PROCEDURE [x1, y1, x2, y2: INTEGER, l: level, p: POINTER TO Rect] =
    BEGIN
    x, y: LONG INTEGER;
    IF l # curLayer THEN
      BEGIN
      curLayer ← l;
      cifOutStr["LN"];
      cifOutChr[layNam[l]];
      cifOutEndCom[];
      END;
    x ← x1;
    y ← y1;
    x ← (x + x2)*cifScale;
    y ← (y + y2)*cifScale;
    x ← x/2;
    y ← y/2;
    cifOutStr["B "];
    cifOutSNum[ABS[x2 - x1]];
    cifOutChr[' ];
    cifOutSNum[ABS[y2 - y1]];
    cifOutChr[' ];
    cifOutLongInt[x];
    cifOutChr[',];
    cifOutLongInt[y];
    cifOutEndCom[];
    END;

  cifDrawText: PROCEDURE [
    x, y, sx, sy: INTEGER, s: STRING, pz: POINTER TO Rect, ls:CHARACTER] =
    BEGIN
    cifOutStr["94 "];
    cifOutStr[s];
    cifOutChr[' ];
    cifOutSNum[x + 1];
    cifOutStr["  "];
    cifOutSNum[y + 1];
    cifOutStr[" N"];
    cifOutChr[ls];
    cifOutChr[' ];
    cifOutEndCom[];
    END;

  cifDrawCellName: PROCEDURE [s: STRING] =
    BEGIN
    cifOutStr["9 "];
    cifOutStr[s];
    cifOutEndCom[];
    END;

  cifOutStr: PUBLIC PROCEDURE [s: STRING] =
    BEGIN
    FOR i: CARDINAL IN [0..s.length) DO ppHandle.put[ppHandle, s[i]]; ENDLOOP;
    END;
  cifOutChr: PUBLIC PROCEDURE [c: CHARACTER] =
    BEGIN ppHandle.put[ppHandle, c]; END;
  cifOutEndCom: PROCEDURE = BEGIN cifOutChr[';]; cifOutChr[15C]; END;
  cifOutLongInt: PUBLIC PROCEDURE [li: LONG INTEGER] =
    BEGIN
    q: LONG INTEGER;
    r: INTEGER;
    IF li < 0 THEN BEGIN cifOutChr['-]; li ← -li; END;
    q ← li/10;
    IF q # 0 THEN cifOutLongInt[q];
    r ← LowHalf[li MOD 10];
    cifOutChr['0 + r];
    END;
  cifOutPoint: PROCEDURE [x, y: locNum] =
    BEGIN cifOutSNum[x]; cifOutChr[',]; cifOutSNum[y]; cifOutChr[' ]; END;
  cifOutSNum: PROCEDURE [x: locNum] =
    BEGIN a: LONG INTEGER; a ← cifScale; a ← a*x; cifOutLongInt[a]; END;
  cifOutNum: PUBLIC PROCEDURE [x: INTEGER] = BEGIN cifOutLongInt[LONG[x]]; END;

  findname: PROCEDURE [p: LONG POINTER TO cell object] RETURNS[s:STRING] =
    BEGIN
    cp: LONG POINTER TO cList←cellList;
    s ← "";
    WHILE cp # NIL DO
      IF cp.ob = p THEN BEGIN s ← cp.name; RETURN; END; cp ← cp.nxt; ENDLOOP;
    END;

  --************* error file reading stuff:

  erfHan: DiskHandle;
  gotErf: BOOLEAN ← FALSE;
  erfLine: STRING ← [200];

  gtByt: PROCEDURE RETURNS [CHARACTER] =
    BEGIN
    IF NOT erfHan.endof[erfHan] THEN RETURN[erfHan.get[erfHan]] ELSE RETURN[15C];
    END;

  rdErfLine: PUBLIC PROCEDURE RETURNS [x, y: INTEGER, s: STRING, nums: BOOLEAN] =
    BEGIN
    c: CHARACTER;
    i, j: CARDINAL;
    x ← y ← 0;
    IF NOT gotErf OR erfHan.endof[erfHan] THEN
      BEGIN s ← "NONE"; nums ← FALSE; RETURN; END;
    cifScale ← pCifScale/2;
    erfLine.length ← 0;
    s ← erfLine;
    c ← 'a;
    WHILE c # 15C AND s.length < s.maxlength DO
      c ← gtByt[]; IF c # 15C THEN AppendChar[s, c]; ENDLOOP;
    WHILE c # 15C DO c ← gtByt[]; ENDLOOP;
    [x, i, nums] ← scanLine[s, 0];
    IF nums THEN [y, i, nums] ← scanLine[s, i];
    IF nums THEN y ← -y ELSE i ← 0;
    WHILE i < s.length AND s[i] = '  DO i ← i + 1; ENDLOOP;
    IF i # 0 THEN
      BEGIN
      j ← 0;
      WHILE i < s.length DO s[j] ← s[i]; i ← i + 1; j ← j + 1; ENDLOOP;
      s.length ← j;
      END;
    END;
  scanLine: PUBLIC PROCEDURE [s: STRING, i: CARDINAL]
    RETURNS [v: INTEGER, j: CARDINAL, any: BOOLEAN] =
    BEGIN
    vv: LONG INTEGER;
    minFlg: BOOLEAN ← FALSE;
    vv ← 0;
    j ← i;
    any ← TRUE;
    v ← 0;
    WHILE j < s.length AND (s[j] = 40C OR s[j] = 11C) DO j ← j + 1; ENDLOOP;
    IF j = s.length OR (s[j] # '- AND NOT s[j] IN ['0..'9]) THEN
      BEGIN any ← FALSE; RETURN; END;
    IF s[j] = '- THEN BEGIN minFlg ← TRUE; j ← j + 1; END;
    WHILE j < s.length AND s[j] IN ['0..'9] DO
      vv ← vv*10 + (s[j] - '0); j ← j + 1; ENDLOOP;
    vv ← vv/cifScale;
    v ← LowHalf[IF minFlg THEN -vv ELSE vv];
    END;

  openErfile: PUBLIC PROCEDURE [fname: STRING] RETURNS [BOOLEAN] =
    BEGIN
    IF gotErf THEN erfHan.destroy[erfHan];
    IF NOT DirectoryLookup[@fp, fname, FALSE] THEN RETURN[FALSE];
    erfHan ← NewByteStream[fname, Read];
    gotErf ← TRUE;
    RETURN[TRUE];
    END;


  END.