Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!BLIULG11.BITNET!A-PIRARD From: A-PIRARD@BLIULG11.BITNET (Andre' PIRARD) Newsgroups: comp.lang.forth Subject: Re: File handling tips Message-ID: <8904121802.AA20096@jade.berkeley.edu> Date: 12 Apr 89 11:45:14 GMT References: Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: Forth Interest Group International List Organization: The Internet Lines: 279 I've been reading the discussion about "file systems" with much interest. I feel the more fundamental question is what to use blocks for. Blocks are a very efficient means to implement some sort of virtual storage indeed and, because of this, can be used to contain anything of the so-called binary format. Thus, trying to split blocks contents into varying length lines or like things is irrelevant. On the other hand, having them hold Forth source code was done because nothing else was available. It is one of the worst aspects of Forth because of the difficulty to maintain source code and the waste of disk space (about three time what is really needed). It even influenced some people to recommend source code horizontal layout as being good program layout style practices. The rational approach is to build the tools to solve the needs, not to try turning the needs into what the tools can provide. If source code is best held in files of variable length records, then let us build the tools to maintain it that way. That is a what I would call "conventional" files system, a means to interpret these files and possibly a Forth-built-in editor if the system does not provide editing source code without quitting Forth. I explained Comforth's file system in a former note. The way it interprets a file is a recursive "FLOAD filename" being somewhat different from LOAD in that it is externally driven (one cannot have interpreted text jump from one line to another as LOADed text can, or skip the rest of a block) but it does not make much of a difference for usual source code. A Forth-hosted editor can simply hold a file in storage if it is not too large. The obvious advantage is that it can be interpreted from there (we call it SLOAD, S for storage) and even on exiting the editor to be reentered with the cursor at the point of an interpretation error. This is much like having shrunken source blocks in storage except that all of a set must be in at a time (but it take 3 times less space) and that one knows where was what at the time of a system crash. Once a decent files system is available, communicating data to/from other programs is a simple matter. As to implementing blocks themselves in order to comply with the standard for whatever else they can be put to good use, a conventional file system makes it a straightforward optional superset as shown in the file below. It loads in each Comforth implementation in a system independent manner. Andr . \ AMP 06mar88 Comforth-83 V5.3 Copyright DIALOGIC 1988 CR .( FORTH Blocks support) CR ( This file should be loaded on top of the development system to allow access ( to block files. Then the word SET#BUFF should be executed and the new system ( saved with FORTHGEN. The number of buffers will only be effective when the ( new system is loaded. FORTH+ DECIMAL ( --------------------- ) ( CONSTANTS & VARIABLES ) ( --------------------- ) VARIABLE RECENT ( Most recently used buffer pointer ) FILE BLFCB ( BLOCKS File Control Block ) 0 HEXA FFFF BLFCB 2! BLFCB 2+ RECENT ! ( Force write error if not open ) VARIABLE BLFOP ( True if file open ) BLFOP OFF 1024 CONSTANT B/BUF ( Bytes per buffer, 83-standard imposed ) : FIRST >FIRST @ ; ( First buffer address ) : LIMIT >LIMIT @ ; ( Last buffer end ) 64 CONSTANT C/L ( Editor: Characters per line ) NAUV DUP 2+ 'B NAUV ! USER SCR ( Editor: Current screen number ) NAUV DUP 2+ 'B NAUV ! USER OFFSET ( Blocks file offset ) NAUV DUP 2+ 'B NAUV ! USER R# ( Editor: Current character in screen ) ( -------------------------- ) ( INTERNAL SUPPORT FUNCTIONS ) ( -------------------------- ) : MASK ( BLKNUM' -- BLKNUM : REMOVE UPDATE BIT ) HEXA 7FFF AND ; : ?LOADING ( -- : Check for LOADing state ) BLK @ 0= ERROR" Use ONLY when loading" ; : ?DISK ( -- : Check for disk error, including not open ) BLFOP @ IF BLFCB IOERR ELSE TRUE THEN ABORT" BLOCKS file I/O error" ; ( ------------------------ ) ( SYSTEM INTERFACE AND LRU ) ( ------------------------ ) : R/W ( ADDR BLOCK-NUM 1/0 -- : READ/WRITE A BLOCK TO ADDR ) >R ?DISK ( NOT OPEN ERROR ) B/BUF UM* ( STARTING BYTE IN FILE ) ROT B/BUF BOUNDS DO ( OVER STORAGE SEGMENTS ) 2DUP BLFCB POINT ( POSITION FILE ) I BPS ( STORAGE ADDRESS/LENGTH ) 0 DPICK IF ( READ ) BLFCB INDATA IF BLFCB READ DROP ELSE BLANK THEN ELSE BLFCB WRITE THEN ?DISK BPS 0 D+ ( INCREMENT FILE BYTE POINTER ) BPS +LOOP 2DROP R> DROP ; : BEST ( BLKNUM -- ADDR FLAG : LRU BUFFER REUSED, TRUE IF TO BE READ ) >R RECENT DUP @ ( PREVIOUS AND CURRENT IN SEARCH ) BEGIN DUP 2- @ MASK R@ <> ( BLKNUM NOT FOUND ) OVER @ AND ( NOR CHAIN END ) WHILE NIP DUP @ REPEAT DUP @ ROT ! RECENT @ OVER ! DUP RECENT ! ( UNCHAIN, RECHAIN AT TOP ) DUP 2+ SWAP 2- @ DUP MASK R@ <> IF DUP 0< IF 2DUP MASK 0 R/W THEN ( NOT BLKNUM, WRITE IF UPDATED ) DROP R@ OVER 4 - ! TRUE ELSE DROP FALSE THEN R> DROP ; ( -------------- ) ( STANDARD WORDS ) ( -------------- ) : EMPTY-BUFFERS ( -- : MARK ALL BUFFERS UNUSED ) 0 LIMIT FIRST 2+ DO I ! I ( CHAINING ) HEXA 7FFF I 2- ! ( INVALIDATE BLOCK NUM ) [ B/BUF 4 + ] LITERAL +LOOP RECENT ! ; : SAVE-BUFFERS ( -- : WRITE BUFFERS TO DISK, KEEPING CONTENTS ) RECENT BEGIN @ DUP WHILE DUP 2+ OVER 2- @ DUP 0< ( UPDATED ) IF MASK 2DUP 0 R/W SWAP 4 - ! ELSE 2DROP THEN REPEAT DROP ; : FLUSH ( -- : SAME WITHOUT KEEPING ) SAVE-BUFFERS EMPTY-BUFFERS ; : BUFFER ( BLOCK -- ADDR : OBTAIN NEXT AVAILABLE BUFFER, ASSIGN IT TO BLOCK ) BEST DROP ; : BLOCK ( BLOCK -- ADDR : BUFFER ADDR CONTAINING BLOCK ) >R RECENT @ DUP 2- @ MASK R@ = IF 2+ ELSE DROP R@ BEST IF DUP R@ 1 R/W THEN THEN R> DROP ; : UPDATE ( -- : MARK BUFFER AS CHANGED ) RECENT @ 2- DUP @ HEXA 8000 OR SWAP ! ; : LOAD ( BLOCK -- : START LOADING FROM BLOCK ) BLK @ >R >IN @ >R #TIB @ >R L>IN @ >R BLK ! >IN OFF B/BUF #TIB ! INTERPRET R> L>IN ! R> #TIB ! R> >IN ! R> BLK ! ; ( ---------------- ) ( EXTENDED SUPPORT ) ( ---------------- ) : --> ( -- : CONTINUE LOADING NEXT BLOCK ) ?LOADING >IN OFF BLK 1+! ; IMMEDIATE : \ ( Appropriate for blocks ) BLK @ IF >IN @ NEGATE C/L MOD >IN +! ELSE [COMPILE] \ THEN ; IMMEDIATE : (LINE) ( LINE BLOCK -- ADDR COUNT ) >R C/L B/BUF */MOD R> + BLOCK + C/L ; : .LINE ( LINE BLOCK -- : PRINT LINE ) (LINE) -TRAILING TYPE ; : LIST ( BLOCK -- : LIST BLOCK CONTENTS ) DECIMAL CR DUP SCR ! ." SCR # " . B/BUF C/L / 0 DO CR I 3 .R SPACE I SCR @ .LINE NOHOLD NOT ?LEAVE LOOP CR ; : INDEX ( BLOCK1 BLOCK2 -- : PRINT FIRST LINE FROM EACH SCREEN ) CR 1+ SWAP DO CR I 4 .R SPACE 0 I .LINE NOHOLD NOT ?LEAVE LOOP ; : TRIAD ( BLOCK -- : PRINT 3 SCREENS STARTING FROM BLOCK ) CR 3 OVER + SWAP DO CR I LIST NOHOLD NOT ?LEAVE LOOP CR ; : .BUF ( LIST RESIDENT BUFFERS STATUS ) RECENT BEGIN @ DUP WHILE DUP 2- @ DUP MASK . DUP 0< IF ." Updated " THEN HEXA 7FFF = IF ." Free " THEN REPEAT DROP ; ( ------------ ) ( OPEN / CLOSE ) ( ------------ ) : (SRCE) ( -- ADDR : DETERMINE INPUT STREAM ADDRESS ) BLK @ ?DUP IF BLOCK ELSE TIB THEN ; : BCLOSE ( -- FLAG : CLOSE BLOCKS FILE ) FALSE BLFOP @ IF ( OPEN ) FLUSH BLFOP OFF BLFCB CLOSE OR THEN ; : NOBLOCKS BCLOSE CLOSED? ; : (USING) ( FNA FNL --- FLAG : SWITCH WORK FILES ) BCLOSE IF 2DROP 2 EXIT THEN LIMIT FIRST - 0 B/BUF UM/MOD 1 < ABORT" Too little buffers" DROP EMPTY-BUFFERS BLFCB OPENU IF 1 EXIT THEN BLFCB MUTEIOERR BLFOP ON FALSE ; : USING ( : DITTO ) "TOKEN (USING) DUP CASE 2 OF CLOSED? ENDOF 1 OF OPEN? ENDOF DROP ENDCASE ; ( ------------ ) ( PATCH SYSTEM ) ( ------------ ) ' (SRCE) >SOURCE PRESET ' NOBLOCKS 'B BYE ! : SET#BUFF ( N -- : SET THE NUMBER OF BUFFERS TO N ) [ B/BUF 4 + ] LITERAL UM* DROP ( BUFFER AREA SIZE ) NEGATE -BSIZE PRESET ; ( SET BOOT-UP LITERAL ) ( S0 SN WSAVE WILL SAVE SCREENS S0 TO SN INCLUSIVE ) ( TO THE HOST FILE "FILE" WITH TRAILING BLANKS REMOVED ) ( --> AND ;S SHOULD THEN BE REMOVED IN ORDER TO ALLOW FLOAD ) : WSAVE ( START END -- ) "TOKEN FCBSIZE RESERVE DUP OPENO OPEN? SWAP 1+ ROT DO 16 0 DO I 64 * J BLOCK + 64 -TRAILING 2 PICK WRITE DUP PUTEOR LOOP LOOP DUP PUTEOF CLOSE FCBSIZE FREE CLOSED? ; CR .( Now set 'num' the number of buffers, CR .( and save your new system. CR .( Type : CR .( 'num' SET#BUFF CR .( FLOAD FORTHGEN.F83 CR .( FORTHGEN CR .( BYE CR .( and execute your new system.