commit e7388dbd184971836e2c0a92173ca5d46280683a
parent 56a291497aee16da749be263394e65b887beae34
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Mon, 18 Jul 2022 17:02:26 -0400
sys/file: add freadbuf and fwritebuf to protocol
fgetc and fputc will work, but will lead to important waste. With concepts like
freadbuf and fwritebuf, we minimize that waste while offloading the complexity
of handling cross-buffer read/write operations to FS-agnostic code.
However, this "pre-inc" shortcut I took in fs/fat looks ugly now, I have to fix
it.
Diffstat:
6 files changed, 62 insertions(+), 26 deletions(-)
diff --git a/fs/doc/file.txt b/fs/doc/file.txt
@@ -0,0 +1,46 @@
+# File subsystem
+
+This subsystems defines a "filesystem" protocol and upon it defines convenience
+word around files. To be able to plug into this subsystem, a filesystem needs
+to have these words (not with the same name, the words will plug into the
+subsystem's aliases):
+
+fopen ( path -- fcursor )
+ Open file at path and return a cursor through which other file-related word
+ identify the target file. Once a file isn't used anymore, it should be
+ closed with fclose. Aborts on error.
+
+fnewfile ( path -- direntry )
+ Create a new empty file at path. Errors out if path's parent is unreachabe or
+ if path already exists.
+
+fclose ( fcursor -- )
+ Close cursor fcursor and free its resources.
+
+fseek ( pos fcursor -- )
+ Place the cursor at offset "pos" (in bytes).
+
+freadbuf ( n fcursor -- a? read-n )
+ Try to read "n" bytes from file from current position. Unless end of file is
+ reached, at least 1 byte must be read, but otherwise "read-n" can be lower
+ than n, even if that doesn't take the cursor to the end of the file. The idea
+ is to take the cursor, at most, to the end of its buffer. Return the number of
+ bytes read and, if it was nonzero, return an address to the beginning of that
+ buffer.
+
+fwritebuf ( a n fcursor -- written-n )
+ Try to write "n" bytes from buffer "a" to file from current position, growing
+ the file if needed. The idea is the same as with freadbuf: the filesystem can
+ proceed as is best for its implementation, as long as it writes at least 1
+ byte.
+
+## File API
+
+On top of that protocol above, the File subsystem implements those words:
+
+fgetc ( fcursor -- c )
+ Read a single character from fcursor. If the end of file (EOF) is reached,
+ returns -1.
+
+fputc ( c fcursor -- )
+ Write a single character to fcursor, growing the file if needed.
diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs
@@ -163,6 +163,7 @@ here const )fnbuf
: FCUR_size ( fcur -- n ) 16 + @ ;
: FCUR_size! ( n fcur -- ) 16 + ! ;
: FCUR_buf( ( fcur -- a ) 20 + ;
+: FCUR_)buf ( fcur -- a ) FCUR_buf( ClusterSize + ;
: FCUR_bufpos ( fcur -- a ) dup FCUR_pos ClusterSize mod swap FCUR_buf( + ;
: FCUR_dirent ( fcur -- dirent )
8 + @ BPB_BytsPerSec /mod ( offset sec ) 1 readsector ( off ) fatbuf( + ;
@@ -212,9 +213,14 @@ alias drop fatflush ( fcursor -- )
over FCUR_cluster! ( pos fc )
then ( pos fcursor ) FCUR_pos! ;
-: fatgetc ( fcursor -- c )
+\ TODO: this whole business about advancing the cursor *before* reading is
+\ shady. Fix this, read should happen at current cursor pos, post-inc.
+\ Also, this is broken for n!=1
+: fatreadbuf ( n fcursor -- a? n )
dup FCUR_pos 1+ over FCUR_size over <= if \ EOF!
- 2drop -1 exit then ( fc pos )
- over fatseek ( fcursor ) FCUR_bufpos c@ ;
+ drop 2drop 0 exit then ( n fc pos )
+ over fatseek ( n fcursor )
+ dup FCUR_bufpos swap FCUR_)buf over - ( n pos nmax )
+ rot min ( pos n ) ;
: fatclose ( fcursor ) dup fatflush 0 swap FCUR_flags! ;
diff --git a/fs/sys/file.fs b/fs/sys/file.fs
@@ -1,24 +1,7 @@
-\ File subsystem
+\ File subsystem, see doc/file
?f<< /lib/scratch.fs
?f<< /lib/with.fs
-\ This subsystems defines a "filesystem" protocol and upon it defines
-\ convenience word around files. This subsystem is a bit weird because the
-\ boot sequence has already defined 3 of those words from the protocol. They
-\ are:
-
-\ fopen ( path -- fcursor )
-\ Open file at path and return a cursor through which other file-related word
-\ identify the target file. Once a file isn't used anymore, it should be
-\ closed with fclose. Aborts on error.
-
-\ fclose ( fcursor -- )
-\ Close cursor fcursor and free its ressources.
-
-\ fgetc ( fcursor -- c )
-\ Read a single character from fcursor. If the end of file (EOF) is reached,
-\ returns -1.
-
\ We need a private scratchpad here because some cursors can be quite
\ long-lived. If we use the system scratchpad, short-lived data will overwrite
\ our cursors.
diff --git a/fs/tests/fs/fat.fs b/fs/tests/fs/fat.fs
@@ -5,16 +5,16 @@
\ 4. It has a 512 sector size
?f<< tests/harness.fs
?f<< fs/fat.fs
-: readN ( fcursor n -- ) >r begin dup fatgetc drop next drop ;
+: fatgetc ( fcursor -- c ) 1 swap fatreadbuf if c@ else -1 ( EOF ) then ;
testbegin
\ Tests for fs/fat
S" tests/fattest" fatfindpath ( dirent )
openfile ( fcursor ) dup fatgetc 'T' #eq
-dup $ff readN ( fcursor )
+$ff over fatseek \ TODO: make cursor post-inc. see fatlo.fs
dup fatgetc 'f' #eq dup fatgetc 'o' #eq dup fatgetc 'o' #eq
-dup $fd readN ( fcursor )
+$1ff over fatseek
dup fatgetc 'b' #eq
-dup $dfc readN ( fcursor )
+$ffc over fatseek
dup fatgetc 'E' #eq dup fatgetc 'O' #eq dup fatgetc 'F' #eq
dup fatgetc -1 #eq
fatclose
diff --git a/fs/xcomp/boothi.fs b/fs/xcomp/boothi.fs
@@ -1,6 +1,7 @@
bootfile xcomp/boothi.fs
0 value curfd \ file descriptor of the file currently being read
0 value fecho
+: fgetc ( fcursor -- c ) 1 swap freadbuf if c@ else -1 ( EOF ) then ;
: f< ( -- c ) curfd fgetc fecho if dup emit then ;
: fload ( fname -- )
floaded, curfd >r
diff --git a/fs/xcomp/glue2.fs b/fs/xcomp/glue2.fs
@@ -1,5 +1,5 @@
bootfile xcomp/glue2.fs
\ Glue code that goes between the filesystem part and boothi
alias fatopen fopen
-alias fatgetc fgetc
+alias fatreadbuf freadbuf
alias fatclose fclose