Category : Forth Source Code
Archive   : STREAMIO.ZIP
Filename : STREAM.TXT
((
The approach to Stream I/O illustrated here is essentially the same as that
used in the "C" language. It is particularly useful when reading a file
sequentially, character by character, to load a data structure.
A Stream consists of a stream control block and a buffer. The address of
the Stream Control Block is the primary parameter used for all access and
operations pertaining to streams. This address is referred to as the
stream pointer.
All stream I/O is buffered to reduce the number of disk accesses. Thus,
the file is not completely updated on disk until the file is specifically
closed or updated. Files should be closed when they are no longer needed
to allow re-use of that memory.
Two "stacks" are maintained, one for input stream pointers and one for
output stream pointers. All output goes to the stream on the top of the
output stack. If there are no streams on the output stack the output is
sent to the screen. Likewise, all input comes from the stream on the top
of the input stack and if there are no streams on the input stack the input
is taken from the keyboard.
The Stream Control Block consists of 10 elements which occupy 18 bytes.
))
ONLY FORTH ALSO DEFINITIONS
DOS ALSO
DECIMAL
10 CONSTANT [LF]
13 CONSTANT [CR]
\ offset initial value
0 CONSTANT @ptr \ buf \ adr of current position in buffer
2 CONSTANT @lim \ buf \ adr of last position in buffer
4 CONSTANT @buf \ buf \ adr of start of buffer
6 CONSTANT @size \ #block \ buffer size
8 CONSTANT @r/w \ ' r/w \ cfa of R/W rountine
10 CONSTANT @eof \ ' eof \ cfa of EOF routine
12 CONSTANT @bits \ 0 \ Flags, has file been written to?
13 CONSTANT @type \ 0
14 CONSTANT @link \ keyboard
16 CONSTANT @handle \ 0
18 CONSTANT #stream \ length of Stream Control Block
VARIABLE [in] ( --adr) 0 [in] ! \ pointer of current Input Stream
VARIABLE [out] ( --adr) 0 [out] ! \ pointer of current Output Stream
:
:
: >handle ( stream--handle) @handle + @ ;
: >buf ( stream--buf) @buf + @ ;
: >pos ( stream--n) DUP ( @ptr + ) @ SWAP >buf - ;
\ When initializing the Stream Control Block the "@ptr" and "@lim" are both
\ set to the address of the start of the buffer.
: stream.ptr.0! ( stream --) DUP >buf SWAP ( @ptr + ) ! ;
: stream.max.0! ( stream --) DUP >buf SWAP @lim + ! ;
: stream.max.! ( n stream --) TUCK >buf + SWAP @lim + ! ;
POSTFIX \ declare assembler syntax
CODE -IN ( --) \ backspace within input stream
[in] #) BX MOV @ptr [BX] AX MOV
AX @buf [BX] CMP U< \ ptr>buf?
IF @ptr [BX] WORD DEC THEN NEXT END-CODE
LABEL read/write ( bx=stream/ax=0:flush,1:read,2:write--bx=stream/ax=buf)
BX PUSH AX PUSH
@r/w [BX] AX MOV AX PUSH >H EXECUTE H> \ do r/w function ( *IMP )
BX POP @buf [BX] AX MOV AX @ptr [BX] MOV \ stream.ptr.0!
RET END-CODE
CODE IN ( --c)
( *)HERE ( **)HERE
[in] #) BX MOV @ptr [BX] AX MOV AX @lim [BX] CMP \ ptr
AX BX XCHG @ptr [BX] WORD INC NEXT \ incr ptr
THEN
0= IF 1 # AX MOV read/write #) CALL \ ptr=lim?: do a read
AX @lim [BX] CMP ( **)ROT JNE \ lim<>buf?: back to get char
@ptr [BX] WORD INC \ else: inc ptr, return
-1 # AX MOV AX PUSH NEXT \ endstream: -1
THEN
@eof [BX] AX MOV AX PUSH >H EXECUTE H> \ do eof function ( *IMP )
( *) #) JMP \ back to get char
END-CODE
\ : INPUT ( adr,len--) BOUNDS ?DO IN I C! LOOP ;
\ : XINPUT ( seg,adr,len--) BOUNDS ?DO IN OVER I LC! LOOP DROP ;
CODE IN| ( seg,off,n--seg,off',n',stream,?) ( wam )
CX POP DI POP AX POP SI PUSH ES PUSH
AX ES MOV CLD
[in] #) BX MOV @ptr [BX] SI MOV @lim [BX] DX MOV
BEGIN
BEGIN CX<>0
WHILE 2ROT SI DX CMP U> \ ?lim>buf
WHILE MOVSB CX DEC \ get char
REPEAT ( lin<=buf)
AX POP DX POP ES PUSH DI PUSH CX PUSH
AX ES MOV DX SI MOV 0= \ ?lim=buf
IF 1 # AX MOV \ do read flag
ELSE -1 # AX MOV \ eof flag
THEN BX PUSH AX PUSH NEXT \ push stream flag
REPEAT ( CX=0)
SI @ptr [BX] MOV
AX POP DX POP ES PUSH DI PUSH CX PUSH
AX ES MOV DX SI MOV
BX PUSH AX AX XOR AX PUSH NEXT
END-CODE
VARIABLE #READ ( --adr) \ Also set in "r/w", See STRMDISK.TXT
: XINPUT ( seg,off,n--) ( wam )
BEGIN IN| DUP \ ?valid read
WHILE 0< IF 0 derror THEN \ ?read beyond eof
1 OVER @r/w + @EXECUTE \ refresh buf
stream.ptr.0! \ reset @ptr
#READ @ 0= \ ?eof
IF -1 HLD ! 1
2DROP DROP EXIT
THEN
REPEAT 2DROP 2DROP DROP ;
: INPUT ( adr,n--) CS@ -ROT XINPUT ;
CODE OUT ( c--)
[out] #) BX MOV @ptr [BX] AX MOV \ ptr,adr
AX BX XCHG CX POP
CL 0 [BX] MOV BX INC \ write char, inc ptr adr
AX BX XCHG AX @ptr [BX] MOV
AX @lim [BX] CMP U<= \ ?lim<=buf
IF 2 # AX MOV read/write #) CALL
THEN NEXT END-CODE
: OUTPUT ( adr,len--) 0 ?DO COUNT OUT LOOP DROP ;
: XOUTPUT ( seg,adr,len--) BOUNDS ?DO DUP I LC@ OUT LOOP DROP ;
: .cr ( --) [CR] OUT [LF] OUT ;
: *output ( *str --) COUNT 0 ?DO COUNT OUT LOOP DROP ;
\ Stream I/O, screen and keyboard.
\ --------------------------------
HERE 1 ALLOT \ leave addr of HERE on stack, used by "screen" \ 1 byte buf
CREATE
DUP , DUP 1+ , , 1 , ' NOOP , ' NOOP , 0 ,
HERE 2+ 82 ALLOT \ leave address on stack, used by "keyboard"
CREATE
0 , 0 , , 0 , ' NOOP , ' NOOP , 0 ,
: get.console ( --)
CREATE [em? 1 C, \ Messages to screen
CODE send ( str,len--) \ SEND to screen
CX POP BX POP HEX E3 ( JCXZ ) DECIMAL
IF [em? #) 0 # BYTE CMP 0<>
IF HERE 2 # AH MOV 0 [BX] DL MOV 33 INT
BX INC LOOP
THEN THEN NEXT END-CODE
: *send ( *str --) COUNT send ;
CODE screen-r/w ( adr,stream--) \ drop
2 # AH MOV 33 INT AX POP NEXT END-CODE
CODE scr ( --)
[em? #) 0 # BYTE CMP 0<>
IF 2 # AH MOV [CR] # DL MOV 33 INT
[LF] # DL MOV 33 INT THEN NEXT END-CODE
: crlf! ( adr --) [ [CR] [LF] COMBINE ] LITERAL SWAP ! ;
: keybuf ( --adr) [
CODE loadkeybuf ( adr--ax,dx) \ Uses DOS fxn to load buf \ 0 0 10 hdos ;
DX POP 10 # AX MOV 33 INT AX PUSH U>=
IF DX PUSH NEXT ELSE >H derror H> THEN END-CODE ( *IMP )
VARIABLE prekey ( --adr) 0 prekey !
: key-r/w ( adr,stream--)
DROP prekey @ COUNT send
[ 80 2- ] LITERAL keybuf C! keybuf loadkeybuf 2DROP
keybuf 1+ COUNT DUP 2+
scr ;
' key-r/w
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/