	SUBROUTINE WRKFIL(NREC,ARRAY,IFUNC)
C COPYRIGHT 1983 GLENN C.EVERHART
C PERMISSION IS GRANTED TO COPY, BUT NOT FOR PROFIT
C
C WORKFILE PSEUDO-MAINTAINER FOR VAX
C
C THIS ROUTINE IS INTENDED TO PERMIT THE SCRATCH FILE OF
C PORTACALC TO BE DISPENSED WITH BY USING A LARGE IN-MEMORY
C ARRAY. A BITMAP WILL SET UP WHEN THE ELEMENT IS INIT'ED AND
C THE DEFAULT ELEMENT WILL BE COMPUTED AND RETURNED
C IF AN UNINITIALIZED ELEMENT IS USED.
	INCLUDE 'VKLUGPRM.FTN'
	PARAMETER CUP=1
C
C
	INTEGER*4 NRC
	INTEGER*2 NRC2(2)
	EQUIVALENCE(NRC2(1),NRC)
C RECORD NUMBER TO ACCESS
	INTEGER NREC 
	LOGICAL*1 ARRAY(128)
	INTEGER IFUNC
	INTEGER*2 IPGMAX,LPGMXF,IPGMOD,LPGMOD
	COMMON/FILEMX/IPGMAX,LPGMXF,IPGMOD,LPGMOD
C LENGTHS (IN K) OF FILES FOR VALUES OR FORMULAS ARE IPGMAX,LPGMXF
C
	INTEGER*2 NCEL,NXINI
	COMMON/NCEL/NCEL,NXINI
	INTEGER*2 MFID,IFID(8,LFM),MFMOD
	INTEGER*2 RRWACT,RCLACT
	COMMON/RCLACT/RRWACT,RCLACT
	LOGICAL*1 LFID(16,LFM)
	EQUIVALENCE(IFID(1,1),LFID(1,1))
	COMMON/FRM/MFID,IFID,MFMOD
	LOGICAL*1 LI,LJ,IBYTE
C DEFFMT IS THE DEFAULT FORMAT FOR NUMERICS. INITIALLY IT WILL BE F9.2
	LOGICAL*1 DEFFMT(10),DVFMT(12)
	EQUIVALENCE(DVFMT(2),DEFFMT(1))
	COMMON/DEFVBX/DVFMT
C FORMAT BLOCK (ONE ONLY, 512 BYTES, BUT ORGANIZED AS 45 FORMAT
C AREAS WITH DATA.)
	LOGICAL*1 FMTDAT(9,45)
	COMMON/FMTBFR/FMTDAT
C
C IFUNC SPECIFIES WHAT TO DO:
C	=0	READ INTO ARRAY
C	=1	WRITE FROM ARRAY INTO WRKARY
C	=2	INITIALIZE (JUST CLEARS BITMAP HERE)(OPEN)
C	=3	CLOSE (CLEARS BITMAP HERE)
	IF(IFUNC.LT.0.OR.IFUNC.GT.3)RETURN
	JFUN=IFUNC+1
	GOTO (1000,2000,3000,4000),JFUN
1000	CONTINUE
C READ
	CALL FVLDGT(NREC,1,IBYTE)
	IF(IBYTE.NE.0)GOTO 1001
C UNINITIALIZED ARRAY ELEMENT: SET IT UP.
	DO 1003 N=1,128
1003	ARRAY(N)=0
	ARRAY(1)='P'
	ARRAY(2)='#'
	ARRAY(3)='#'
	ARRAY(118)=15
	DO 1004 N=1,9
1004	ARRAY(N+119)=DEFFMT(N)
C RETURN THE DEFAULT FORMAT NOW.
	RETURN
1001	CONTINUE
	DO 1053 N=1,128
1053	ARRAY(N)=0
	ARRAY(119)=IBYTE
	ARRAY(118)=15
	ARRAY(1)=48
C LET ARRAY INITIALLY BE SET SENSIBLY..
	DO 1054 N=1,9
1054	ARRAY(N+119)=DEFFMT(N)
C WE MAY MODIFY FORMAT LATER TOO...
C NOW HAVE A NON-DEFAULT ELEMENT TO READ... GO THROUGH SYMBOL TBL LOGIC
C FOR THESE, WE USE 16-BYTE "CELLS" WHICH HAVE THE FOLLOWING FORMAT:
C	ID	2 BYTES (CELL ADDRESS, MUST BE 1 OR MORE FOR VALID)
C	FLAG	1 BYTE  (TYPE OF CELL:
C				0 = UNUSED
C				1 = 1 OF 1 CELLS
C				2 = NONTERMINAL OF MORE THAN 1 CELL
C				3 = LAST OF >1 CELLS
C	FORMAT	1 BYTE  (INDEX OF FORMAT STRING FOR THIS CELL; FORMATS
C				ARE STORED RESIDENT, UP TO 45 OF THEM,
C				SET BY DF COMMAND.)
C	FORMULA	12 BYTES  (FORMULA TEXT)
C SET UP HASH CODE NOW FOR THE WAY WE NEED...
C	IPM=(LPGMXF*64/LFM)+1
	IBF=(LFM+31)/32
	LLL=(LPGMXF*2)/IBF
	IPM=LLL
	IF(IPM.LT.1)IPM=1
C FORCE IPM (MAX MEM PAGE) TO BE IN VALID RANGE
C	IHHI=NREC/256
C	IHHI=IHHI.AND.127
C	IHASH=NREC.AND.255
C	IHASH=IHASH*128+IHHI
C	IHASH=IHASH.AND.32767
	IHASH=NREC
	JHASH=MOD(IHASH,LFM)
	IF(LPGMOD.NE.0)GOTO 5305
	IPAG=(IHASH/LFM)+1
	IPAG=MOD(IPAG,IPM)+1
	GOTO 5306
5305	CONTINUE
C SPEED OPTIMAL PACK
	FPG=FLOAT(LPGMOD)
	IF(FPG.LT.0.)FPG=FPG+65536.
	FPG=FLOAT(IHASH)*FLOAT(IPM)/FPG
	IPAG=FPG
	IPAG=MOD(IPAG,IPM)
	IPAG=IPAG+1
C	IPAG=1+(IHASH*IPM)/RRCL
5306	CONTINUE
	IF(IPAG.LE.0)IPAG=1
	IF(MFID.EQ.0)MFID=IPAG
C NOW MFID HAS MEMORY PAGE CURRENTLY PRESENT, IPAG IS DESIRED ONE FOR THIS
C FORMULA. NOTE WHILE WE USE A HASHCODE TO SEARCH FOR FORMULAS, ALL SEGMENTS
C OF A FORMULA MUST BE PLACED IN ONE MEMORY PAGE. THUS, IT IS POSSIBLE TO
C RUN OUT OF SPACE IF THE MEMORY BUFFER GETS TOO SMALL. CURRENT HASH
C CODE TRIES TO SPREAD THE FORMULAS OUT, BUT BIG MEMORY BUFFERS ALWAYS
C WIN.....
	IF(IPAG.EQ.MFID)GOTO 1400
	IF(LPGMXF.LE.(LFM/64))GOTO 1400
C WRITE WHATEVER'S IN MEMORY TO FILE AND READ THE NEW PAGE IN.
	IBF=(LFM+31)/32
	IF(IBF.LT.1)IBF=1
C IBF IS BLK FACTOR
	L=1
	LLBK=(MFID-1)*IBF+1
	LHBK=MFID*IBF
	DO 1170 N=LLBK,LHBK
	IF(MFMOD.EQ.0)GOTO 1170
C SKIP WRITING OUT IF BLOCK WAS NOT MODIFIED SINCE READIN
	LL=L+31
	WRITE(7'N)((IFID(K,KK),K=1,8),KK=L,LL)
	L=L+32
1170	CONTINUE
C NOW READ IN THE DATA
	MFMOD=0
C MARK NEW BLOCK UNTOUCHED
	MFID=IPAG
	L=1
	LLBK=(MFID-1)*IBF+1
	LHBK=MFID*IBF
	DO 1171 N=LLBK,LHBK
	LL=L+31
	READ(7'N)((IFID(K,KK),K=1,8),KK=L,LL)
	L=L+32
1171	CONTINUE
C DATA ALL SHOULD BE THERE NOW... OK, GO AHEAD.
1400	CONTINUE
C NOW HAVE THE DESIRED MEMORY PAGE; READ THE FORMULA INTO ARRAY
C BUFFER.
	IARSUB=1
C FOR SIMPLICITY FORGET THE HASHCODE WITHIN MEMORY BUFFERS, JUST SEARCH
C FROM START...
	IFLAG=0
	IFMT=0
	DO 2500 NN=1,LFM
	n=mod((nn+jhash),lfm)+1
	IF(NN.GT.3.AND.IFID(1,N).EQ.-1)GOTO 2505
C SKIP OUT IF HIT A VIRGIN CELL AFTER 3 TRIES
	IF(IFID(1,N).NE.NREC)GOTO 2500
	IFLAG=LFID(3,N)
	IF(IFMT.EQ.0)IFMT=LFID(4,N)
	DO 2502 K=1,12
	LI=LFID(K+4,N)
C COPY FORMULA TEXT INTO ARRAY. END ON NULLS...
	IF(LI.LE.0)GOTO 2500
	ARRAY(IARSUB)=LI
	IARSUB=IARSUB+1
2502	CONTINUE
	IF(IFLAG.EQ.1.OR.IFLAG.EQ.3)GOTO 2505
2500	CONTINUE
2505	CONTINUE
C GET FORMAT NOW...
	IF(IFMT.LE.0)RETURN
	DO 2510 N=1,9
2510	ARRAY(119+N)=FMTDAT(N,IFMT)
	GOTO 5000
2000	CONTINUE
C WRITE
C NOW SET INIT'D BIT; WRITE ARRAY ELEMENT OUT.
C FIRST FIND FORMAT AREA OR SET IT UP.
	IFMT=0
	LFF=0
C FAKE OUT THE SAVING OF FVLD INFO IN THIS ARRAY TOO.
C THIS IS INCOMPLETE AND NO LITTLE OF A KLUDGE BUT THE CODE WILL
C GENERALLY SET THEM TOGETHER, AND THIS GUARANTEES THAT IF
C FURTHER SETS TRY TO SET FVLD TO ARRAY(119), THEY'LL WORK AS
C THEY SHOULD.
C HERE SET MAX ARRAY ELEMENTS USED
C EXPECT (ID2-1)*RRW+ID1
C ID1 IS RRW DIM, ID2 IS RCL DIM
	NRC2(1)=NREC
	IRUSED=MOD(NRC,RRW)
	ICUSED=((NRC-IRUSED)/RRW)+1
	IF(ICUSED.GT.RCLACT)RCLACT=ICUSED
	IF(IRUSED.GT.RRWACT)RRWACT=IRUSED
C SET RRWACT, RCLACT
	IF(ARRAY(119).NE.0)CALL FVLDST(NREC,1,ARRAY(119))
	DO 2011 N=1,45
	IF(FMTDAT(1,N).LE.0.AND.LFF.EQ.0)LFF=N
C SAVE FIRST FREE FORMAT AREA IN CASE THIS IS A NEW FORMAT...
	DO 2010 M=1,9
	IF(ARRAY(M+119).NE.FMTDAT(M,N))GOTO 2011
2010	CONTINUE
	IFMT=N
	GOTO 2012
2011	CONTINUE
C ON FALL THROUGH, WE FOUND NOTHING FOR IT...
C USE HIS FORMAT UNLESS WE HAVE NO ROOM, IN WHICH CASE USE LAST AREA
	IF(LFF.EQ.0)LFF=45
	IFMT=LFF
	DO 2013 N=1,9
2013	FMTDAT(N,LFF)=ARRAY(119+N)
C SAVE FORMAT DATA WE NOW POINT TO...
2012	CONTINUE
C NOW THE HARDER PART... MUST WRITE THE ARRAY'S FORMULA TOO...
C	IPM=(LPGMXF*64/LFM)+1
	IBF=(LFM+31)/32
	LLL=(LPGMXF*2)/IBF
	IPM=LLL
	IF(IPM.LT.1)IPM=1
C FORCE IPM (MAX MEM PAGE) TO BE IN VALID RANGE
C	IHHI=NREC/256
C	IHHI=IHHI.AND.127
C	IHASH=NREC.AND.255
C	IHASH=IHASH*128+IHHI
C	IHASH=IHASH.AND.32767
	IHASH=NREC
	JHASH=MOD(IHASH,LFM)
	IF(LPGMOD.NE.0)GOTO 5307
	IPAG=(IHASH/LFM)+1
	IPAG=MOD(IPAG,IPM)+1
	GOTO 5308
5307	CONTINUE
C SPEED OPTIMAL PACK
	FPG=FLOAT(LPGMOD)
	IF(FPG.LT.0.)FPG=FPG+65536.
	FPG=FLOAT(IHASH)*FLOAT(IPM)/FPG
	IPAG=FPG
	IPAG=MOD(IPAG,IPM)
	IPAG=IPAG+1
C	IPAG=1+(IHASH*IPM)/RRCL
5308	CONTINUE
	IF(IPAG.LE.0)IPAG=1
	IF(MFID.EQ.0)MFID=IPAG
C NOW MFID HAS MEMORY PAGE CURRENTLY PRESENT, IPAG IS DESIRED ONE FOR THIS
C FORMULA. NOTE WHILE WE USE A HASHCODE TO SEARCH FOR FORMULAS, ALL SEGMENTS
C OF A FORMULA MUST BE PLACED IN ONE MEMORY PAGE. THUS, IT IS POSSIBLE TO
C RUN OUT OF SPACE IF THE MEMORY BUFFER GETS TOO SMALL. CURRENT HASH
C CODE TRIES TO SPREAD THE FORMULAS OUT, BUT BIG MEMORY BUFFERS ALWAYS
C WIN.....
	IF(IPAG.EQ.MFID)GOTO 2400
	IF(LPGMXF.LE.(LFM/64))GOTO 2400
C WRITE WHATEVER'S IN MEMORY TO FILE AND READ THE NEW PAGE IN.
	IBF=(LFM+31)/32
C IBF IS BLK FACTOR
	L=1
	LLBK=(MFID-1)*IBF+1
	LHBK=MFID*IBF
	DO 2170 N=LLBK,LHBK
	IF(MFMOD.EQ.0)GOTO 2170
C SKIP WRITEOUT IF OLD PAGE WAS NOT MODIFIED
	LL=L+31
	WRITE(7'N)((IFID(K,KK),K=1,8),KK=L,LL)
	L=L+32
2170	CONTINUE
C NOW READ IN THE DATA
	MFID=IPAG
C MARK NEXT PAGE AS MODIFIED SINCE WE WILL NOW WRITE INTO IT
C	MFMOD=1
	L=1
	LLBK=(MFID-1)*IBF+1
	LHBK=MFID*IBF
	DO 2171 N=LLBK,LHBK
	LL=L+31
	READ(7'N)((IFID(K,KK),K=1,8),KK=L,LL)
	L=L+32
2171	CONTINUE
C DATA ALL SHOULD BE THERE NOW... OK, GO AHEAD.
2400	CONTINUE
C NOW HAVE THE DESIRED MEMORY PAGE; READ THE FORMULA INTO ARRAY
C BUFFER.
	MFMOD=1
	IARSUB=1
C FOR SIMPLICITY FORGET THE HASHCODE WITHIN MEMORY BUFFERS, JUST SEARCH
C FROM START...
C OMIT THE ZEROING WHEN READING IN FROM FILE EXCEPT IN /MERGE MODE
	IF(NXINI.NE.0)GOTO 6233
	DO 1490 NN=1,LFM
	n=mod((nn+jhash),lfm)+1
	IF(NN.GE.3.AND.IFID(1,N).EQ.-1)GOTO 6233
	IF(IFID(1,N).NE.NREC)GOTO 1490
C ZERO OLD RECORDS OF THIS ONE...
	NCEL=NCEL-1
	IF(NCEL.LT.0)NCEL=0
	DO 1498 KK=1,8
1498	IFID(KK,N)=0
1490	CONTINUE
6233	CONTINUE
	IFLAG=0
	DO 1500 NN=1,LFM
	n=mod((nn+jhash),lfm)+1
	IF(IFID(1,N).NE.-1.AND.IFID(1,N).NE.0
     1     .AND.IFID(1,N).NE.NREC)GOTO 1500
C FOUND A NULL NODE...
C FILL IT IN NOW.
	NCEL=NCEL+1
	IFID(1,N)=NREC
	IFLAG=1
	LFID(4,N)=IFMT
	LFID(3,N)=IFLAG
	DO 1502 K=1,12
	LI=ARRAY(IARSUB)
	IF(LI.LE.0)GOTO 1505
C CHOP IT OFF AT 109 ALSO...
	IF(IARSUB.GT.109)GOTO 1560
	LFID(K+4,N)=LI
	IARSUB=IARSUB+1
1502	CONTINUE
C NONTERMINAL COPY...NEED ANOTHER CELL. FIRST TEST FOR EXACT FIT,
C HOWEVER.
	IF(ARRAY(IARSUB).LE.0)GOTO 1560
	IFLAG=2
	LFID(3,N)=IFLAG
C NOW GO GET MORE SPACE FOR NEXT NODE.
C NOTE IT COULD RUN OUT, BUT JUST PUNT THAT.
	GOTO 1500
1560	CONTINUE
	IF(IFLAG.EQ.1)IFLAG=3
	LFID(3,N)=IFLAG
C SETS UP EITHER 1 OR 3 FOR TERMINAL NODES
	GOTO 1505
C ESCAPE FROM LOOP ON ENDS...
1500	CONTINUE
C HERE WE RAN OUT OF ROOM. TOO BAD...CAN'T REALLY HELP IT OR
C DO MUCH. JUST FORGET IT.
C HOWEVER, PRINT A MESSAGE ON SCREEN AT LEAST...
	CALL UVT100(CUP,1,1)
	WRITE(6,8970)
8970	FORMAT(' Formula file overflowed. Try a larger file.')
1505	CONTINUE
C DONE NOW.
	GOTO 5000
3000	CONTINUE
C OPEN (CLR BITMAP)
	MFID=0
	GOTO 5000
4000	CONTINUE
C CLOSE (CLR BITMAP)
	CLOSE(UNIT=7,DISP='DELETE')
	MFID=0
5000	RETURN
	END
