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

-- last modified by Dillon, April 11, 1984  12:11 AM
  -- to allow rdErfLine to use pCifScale<2 correctly
-- last modified by McCreight, December 20, 1983  2:34 PM
  -- to read in multiple implant levels
-- modified by Petit, September 20, 1981
DIRECTORY
  InlineDefs,
  StreamDefs,
  SystemDefs,
  IODefs,
  AltoDefs,
  DirectoryDefs,
  AltoFileDefs,
  StringDefs,
  ChipUserInt,
  ppoutdefs,
  ppdddefs,ppddefs,
  ppdefs;

ppio: PROGRAM
  IMPORTS
    ChipUserInt, ppdefs, ppddefs, ppdddefs,ppoutdefs, InlineDefs,
    StreamDefs, StringDefs, DirectoryDefs
  EXPORTS ppdefs, 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];

  contLevel: ARRAY [1..contTypALen] OF level =
    [dif, pol, dif,dif, met2, pdif,nwelCont,dif,pol,pdif,dif,dif]; -- for versions<6

  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
        impl: DepletionStrength ← enhancement;
        w ← inWord[];
        l ← inWord[];
        k ← inWord[];
        IF version>4 AND BITAND[k,10000B]#0
	  THEN sur ← inWord[];-- if pdif, get surround
        IF BITAND[k,20000B]#0 THEN j ← inWord[];-- if angle, get angle ext.
        IF BITAND[k, 100000B]#0 THEN
          BEGIN
          IF version>7 THEN impl ← inWord[] ELSE impl ← LAST[DepletionStrength];
          END;
        we ← BITAND[BITSHIFT[k, -6], 77B];
        le ← BITAND[k, 77B];
        lev ← IF BITAND[k,10000B]#0 THEN pdif ELSE dif;
        ob ←
          SELECT TRUE FROM
            BITAND[k, 40000B] # 0 => makePullup[w, l,we,le, lev],
            BITAND[k,20000B]#0  =>
              makeAngleXstr[w, l, impl,we,le,j, lev],
            ENDCASE => makeXstr[w, l, impl,we,le,lev];
        END;
      3 =>
        BEGIN
        j ← inWord[];  -- get contact type
        k ← BITAND[j, 37B];  -- get contact type
        l ← BITSHIFT[j, -8];
        lev ← IF version>5 THEN inWord[] ELSE contLevel[k];
        IF version>4 THEN sur←inWord[];
        SELECT contTypA[k] FROM
          mPol => ob ← makePolycon[l];
          mDif => ob ← makeDifcon[l, lev];
          difShort => ob ← makeDifShortCont[lev];
          butt => ob ← makeButcon[lev];
          burr => BEGIN
		w←inWord[];
		k←inWord[];
		j←BITSHIFT[k,-8];
		ob ← makeBuCont[w,l,j,BITAND[k,377B], lev];
	    END;
          mm2 => ob ← makeMmCont[l,0,0];
          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 => ob ← NIL;
    END;

  inList: PROCEDURE [ver: CARDINAL, lp: listPtr ← NIL]
    RETURNS [listPtr] =
    BEGIN
    i, j, k, l: CARDINAL;
    tail: listPtr;
    lp ← NIL;
    i ← inWord[];
    FOR j IN [0..i) DO
      tp: listPtr ← alocList[];
      tp.nxt ← NIL;
      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
          inProp[tp];
          ENDLOOP;
        END;
      IF tp.ob # NIL THEN -- link it in, in FIFO order
        {IF lp=NIL THEN lp ← tp ELSE tail.nxt ← tp; tail ← tp};
      ENDLOOP;
    RETURN[lp];
    END;

  instanceName, signalName: Atom;

  inProp: PROCEDURE [lp: listPtr] =
    BEGIN
    i: CARDINAL;
    i ← inWord[];
    SELECT i FROM
      1 =>
        BEGIN
        value: STRING = inString[];
        attribute: Atom = SELECT lp.ob.otyp FROM
          rect, wire => signalName,
          ENDCASE => instanceName;
        putProp[lp: lp, attribute: attribute, value: MakeAtom[value]];
        FreeString[value];
        END;
      2 =>
        BEGIN
        attribute: Atom = inAtom[];
        value: Atom = inAtom[];
        putProp[lp: lp, attribute: attribute, value: value];
        END;
      ENDCASE => NULL;
    END;

  inWord: PROC RETURNS [UNSPECIFIED]; -- variable

  readAll: PUBLIC PROCEDURE [get: PROC RETURNS[UNSPECIFIED]] =   BEGIN
    ml: listPtr;
    cl: cListPtr;

    [masterList: ml, cellList: cl, cellStack: cellStack] ← readChip[get
      ! ChipUserInt.Punt => GOTO NoChange];

    flushDel[unDelPnt];
    unDelPnt ← NIL;
    unDelGrpCnt ← unDelItemCnt ← 0;

    FOR lpp: LONG POINTER TO listPtr ← @masterList, @lpp.nxt DO
      IF lpp↑=NIL THEN {lpp↑ ← ml; EXIT};
      ENDLOOP; -- append ml to masterList

    FOR clp: LONG POINTER TO cListPtr ← @cellList, @clp.nxt DO
      IF clp↑=NIL THEN {clp↑ ← cl; EXIT};
      ENDLOOP; -- append cl to cellList

    pushLevel ← 0;
    FOR cs: cellSEPtr ← cellStack, cs.nxt WHILE cs#NIL DO
      pushLevel ← pushLevel+1;
      ENDLOOP;
    EXITS NoChange => NULL;
    END;

  readChip: PUBLIC PROCEDURE [get: PROC RETURNS[UNSPECIFIED]]
    RETURNS[masterList: listPtr, cellList: cListPtr, cellStack: cellSEPtr] =
    BEGIN
    i, j, ver, depth: CARDINAL;
    ss: STRING;

    inWord ← get;

    instanceName  ← atomTable[1] ← MakeAtom["Instance name"];
    signalName ← atomTable[2] ← MakeAtom["Signal name"];

    cellList ← NIL; -- local variables
    cellStack ← NIL;

    i ← inWord[];  -- read code word
    IF i#codeWordForDataFile AND
      NOT ChipUserInt.HeSaysYes["This really doesn't look like a valid .chip file."L,
        "Shall I press on anyway? (I might crash!)"L] THEN SIGNAL ChipUserInt.Punt;

    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;

    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
      cdp: LONG POINTER TO cell object;
      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: cListPtr ← alocCList[];
        cpp.nxt ← cellList;
        cellList ← cpp; -- add to existing cellList
        cpp.ob ← cdp.p.anotherme[cdp];
        cpp.name ← ss;
        cdp.returnable ← FALSE;
        END;
      ENDLOOP;

    depth ← IF ver<7 THEN 0 ELSE inWord[];
    WHILE depth>0 DO
      top: cellSEPtr = inPushedLevel[ver, depth];
      top.nxt ← cellStack;
      cellStack ← top;
      depth ← inWord[];
      ENDLOOP;

    IF ver>=7 THEN
      BEGIN
      fileChanges: BOOLEAN = inWord[];
      anyChanges ← anyChanges OR fileChanges;
      END;

    masterList ← inList[ver, NIL];

    FOR i IN [1..cCnt] DO cellNameA[i].p.release[cellNameA[i]]; ENDLOOP;
    FreeSpace[BASE[cellNameA]];
    END;

  atomTable: PUBLIC ARRAY [1..atomTableSize] OF Atom;

  inAtom: PROC RETURNS [a: Atom] =
    BEGIN
    i: INTEGER = inWord[];
    IF i>0 THEN
      BEGIN
      s: STRING ← inString[];
      a ← MakeAtom[s];
      FreeString[s];
      IF i<=256 THEN atomTable[i] ← a;
      END
    ELSE a ← atomTable[-i];
    END;

  inPoint: PROC RETURNS [p: Point] = {p.x ← inWord[]; p.y ← inWord[]};

  inRect: PROC RETURNS [r: Rect] =
    {[[r.x1, r.y1]] ← inPoint[]; [[r.x2, r.y2]] ← inPoint[]};

  inInt: PROC RETURNS [i: INT] =
    BEGIN
    ln: LongNumber;
    ln.highbits ← inWord[];
    ln.lowbits ← inWord[];
    i ← ln.li;
    END;

  inPushedLevel: PROC [ver: CARDINAL, depth: NAT] RETURNS [cs: cellSEPtr] =
    BEGIN
    changes: BOOLEAN = inWord[];
    origSize: Point = inPoint[];
    origBB: Rect = inRect[];
    dest: cellPtr = LOOPHOLE[inObject[ver]];
    lp: listPtr = inList[ver];
    instance: listPtr = inPositionInList[ver, lp];
    cs ← GetSpace[SIZE[cellSE]];
    cs↑ ← [nxt: NIL,
      changes: changes,
      origSize: origSize,
      origBB: origBB,
      dest: dest,
      lp: lp,
      instance: instance,
      udg: 0, udi: 0];
    cellStack ← cs;
    END;

  inPositionInList: PROC[ver: CARDINAL, within: listPtr] RETURNS [target: listPtr] =
    BEGIN
    i: INT ← inInt[];
    IF i=0 THEN RETURN[NIL];
    FOR lp: listPtr ← within, lp.nxt DO
      i ← i-1;
      IF i=0 THEN RETURN[lp];
      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;

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

  hdcpyHandle: StreamDefs.DiskHandle;  -- for hardcopy

  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"];
    hdcpyHandle ← NewWordStream[fullName, Write + Append];
    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;
    hdcpyHandle.destroy[hdcpyHandle];
    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] = {hdcpyHandle.put[hdcpyHandle, ww]};
  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;


  --************* 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;
    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 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*lambda)/pCifScale;
    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.