The file FatCore.fth contains the bulk of the file system code.
File reads and writes use sector cache buffers for file I/O. One buffer gives the lowest performance, since accessing more than one sector causes disk thrashing. WRITE-FILE accesses the FAT table and the data sectors of the disk so there should be at least two sector buffers for each file being actively written. READ-LINE tends to like more than two buffers - six are recommended, especially with slow drives.
#64 equ MAX_PATH \ -- len
The maximum size of a pathname including the file name.
#buffers bytes/sec * buffer: bufs \ -- addr
Sector cache.
#buffers cells buffer: csects \ -- addr
Holds sector numbers of the currently buffered sectors.
#buffers cells buffer: ctr#s \ -- addr ; SFP007
Holds transaction numbers of the currently buffered sectors.
The lowest number identifies the oldest sector.
#buffers buffer: wrpendings \ -- addr
Holds the write-pending flags for the currently buffered sectors.
#buffers buffer: pdrives \ -- addr
Holds the physical devices for the currently buffered sectors.
variable buff# \ -- addr
Holds the next available sector buffer number (0, 1, ..).
variable tr# \ -- addr ; SFP007
Holds the current transaction number.
cvariable cdrive \ -- addr
Holds the current drive number, which must be 0 for the
moment.
The following variables hold the disk characteristics. These will be changed at a later date to support multiple drives by providing a structure per drive.
variable SectorsPerTrack \ -- addr
Holds the number of sectors per track for the raw disk.
variable NumHeads \ -- addr
Holds the number of heads for the raw disk.
variable rootentries \ -- addr
Number of 32-byte directory entries in the root directory.
variable rootdsecs \ -- addr
Number of sectors in the root directory.
variable rootsector \ -- addr
Sector of root directory.
variable sec/cluster \ -- addr
Sectors per cluster.
variable clusshift \ -- addr
Equivalent shift count for sectors per cluster.
variable reservedsec \ -- addr
Reserved sectors: 1 for FAT12/16, usually 32 for FAT32.
variable totalsec \ -- addr
Total number of sectors.
variable FATsize \ -- addr
FAT size in sectors.
variable basesector \ -- addr
Start sector of the current partition, currently 0
variable dcurs \ -- addr
Holds the display cursor position. This is an aid for later
directory listing tools.
2variable savedDirEnt \ -- addr
Directory sectory and entry saved when a file/directory is found.
The following words manipulate the data above.
: initSecCache \ --
Clear the sector cache buffers.
: buf \ -- addr
return the address of the current/next sector cache buffer.
: csect \ -- addr
Return the address holding the current sector number.
: ctr# \ -- addr
Return the address holding the current transaction number.
: writePend \ -- addr
Return the address of the current sector write-pending flags (bytes).
: pdrive \ -- addr
Return the address of the device number (byte) in the cache line.
: bumpBuff# \ --
Step the current sector to the next sector cache buffer.
: wmark \ --
Mark the current sector cache buffer as modified, so that
it will be written back.
: RootDirSectors \ -- n
Number of sectors for the root directory.
: StartSector \ -- n
Return the sector number of the first data sector.
: c>s \ nclus -- nsec
Convert a number of clusters to the corresponding number of sectors.
The EQU FastShift? determines whether this word is implemented
as a multiply by sec/cluster or a shift by clusshift.
: s>c \ nsec -- nclus
Convert a number of sectors to the corresponding number of clusters.
The EQU FastShift? determines whether this word is implemented
as a divide by sec/cluster or a shift by clusshift.
: cluster>sec \ cluster -- sector
Converts a cluster number to a physical sector.
: sec>cluster \ sector -- cluster
Converts a physical sector to a cluster number.
: b>c \ bytes -- clusters
Returns the number of clusters needed to hold a number of bytes.
: b>cn \ bytes -- nclus noff
Convert a number of sectors to a number of complete clusters and the
sector offset (0..noff) within the following partially filled cluster.
: c>b \ clusters -- bytes
Converts clusters to a byte count.
: CountofClusters \ -- n
Number of clusters available for data. According to Microsoft,
the FAT type (12/16/32) depends solely on this number of
clusters, and not on the ASCII string in sector 0.
: nodir \ --
Reset the directory display cursor.
: wflush \ --
If the current sector cache buffer is marked as modified,
write it back.
: flushall \ --
Write all marked sector cache buffers back.
: seeksector \ sector -- found? ; look for a current sector
Return true if the given sector is already cached.
: setCtr# \ --
Update the global transaction number and set the current
sector's transaction number from it.
: oldest \ --
Set buff# to the oldest cached sector.
: readsector \ sector --
Ensure sector is in the cache buffers.
Several routines are vectored according to the FAT implementation on the drive. These routines use a table of xts to hold the action required for FAT12, FAT16 and FAT32. The variable FATtype holds the offset in bytes used to index the table.
Note that this code assumes a 32 bit Forth implementation.
variable FATtype \ -- addr
Holds the offset (0/4/8) in the FAT function tables.
: FATexec \ ?? table -- ??
From the function table, executes the function indexed
from FATtype.
: *3/2 ( n -- n' ) dup 2/ + ;
Signed multiply by 3/2. For FAT12 operations.
: *2/3 ( n -- n' ) $AAAAAAAA um* nip ;
Unsigned multiply by 2/3. For FAT12 operations.
create /fats \ -- addr
Vector table for /FAT below.
: /fat \ #bytes -- #entries
Given a memory size in bytes, returns the number
of complete FAT entries in it.
create FAToffsets \ -- addr
Vector table for FAToffset below.
: FAToffset \ cluster -- offset sector
Get sector number and offset for the given FAT entry.
: FAT@32 \ cluster -- n
Return the 28 bit FAT32 entry for the given cluster.
: FAT@16 \ cluster -- n
Return the 16 bit FAT16 entry for the given cluster.
: fat@12bndry \ offset sector -- w
Read a 16 bit FAT12 entry that crosses a sector boundary.
Offset is Bytes/Sector-1 and sector is the
sector number of the first sector.
: FAT@12 \ cluster -- n
Return the 12 bit FAT12 entry for the given cluster.
create FAT@s \ -- addr
Vector table for FAT@.
: FAT@ \ cluster -- n
Return the FAT entry for the given cluster.
: FAT!32 \ n cluster --
Set the FAT32 entry for the given cluster.
: FAT!16 \ n cluster --
Set the FAT16 entry for the given cluster.
: fat!12bndry \ w offset sector --
Write a 16 bit FAT12 entry that crosses a sector boundary.
Offset is Bytes/Sector-1 and sector is the
sector number of the first sector.
: wmerge12 \ n cluster nr -- nw
Merge two FAT12 entries before writing. N is the new
entry, nr is the entry from the disc, and cluster
is the entry number to which the value nw will be written.
: FAT!12 \ n cluster --
Set the FAT12 entry for the given cluster.
create FAT!s \ -- addr
Vector table for FAT@.
: FAT! \ n cluster --
Set the FAT entry for the given cluster.
create |cls \ -- addr
Table holding last-cluster markers for each FAT type.
: |cl \ -- n
Last-cluster marker.
variable bptr \ -- addr
Stream pointer into the current sector cache buffer.
variable bperror \ -- addr
If set non-zero, an error exists in the BPB.
: newb \ --
Reset the input stream.
: skipb \ --
Step to the next stream byte.
: getb \ -- byte
Get stream byte and step to next.
: getw \ -- word
Get 16 bit stream item and step past it. The item is read in
little-endian format.
: getl \ -- long
Get 32 bit stream item and step past it. The item is read in
little-endian format.
: wantb \ byte --
Read the next stream byte and if it is not the given byte,
set bperror to 1.
: wantw \ word --
Read the next stream word and if it is not the given word,
set bperror to 1.
: lengthen \ w -- u
Read the next 32 bit item. If w is non-zero, discard the new
item and return w, otherwise return the new item.
: bp_init \ --
Initialise the system, read the drive characteristics and
set up for file operations.
Each sector of a directory contains 16 entries indexed by DIRENTRY. The sector number DIRSECTOR is a 32-bit value addressing up to 2Tbytes. The root directory is a contiguous run of ROOTDSECS sectors starting at the sector in ROOTSECTOR. Subdirectories use a chain in the FAT table just like files. So, the root directory has a fixed number of possible directory entries. DIRCLUSTER is 0 when the root directory is selected.
For most drives, cluster 0 and cluster 1 are occupied by two copies of the FAT. Cluster 2 is usually the start of the root directory. For FAT12 and FAT16, the root directory is of fixed size.
: dt \ x acc n bits -- acc' x
Shift accumulator left by bits, add in n, and
bring the next item x to the top. Ugh!
Convert the current date and time into the packed 32 bit
format for directory entries:
yyyyyyymmmmddddd:hhhhhmmmmmmsssss
variable dircluster \ -- addr
Holds first cluster of the current directory, or 0 for the
root directory.
variable dirsector \ -- addr
Holds current sector number of directory.
variable direntry \ -- addr
Holds current entry number.
: dir[] \ offset -- addr
Index into the current directory entry.
Ensures that the entry is in the sector cache.
: secmask \ -- sector mask
Return the sector and the mask for testing the current
directory sector.
: firstsec? \ -- flag
Return true if we are at the first sector of a cluster.
: lastsec? \ -- flag
Return true if we are at the last sector of a cluster.
: attrib? \ mask -- flag
Test file attribute bits, returning non-zero if any bits in
the mask are set. The attributes are a bit mask
: dir? \ -- b
Return the first byte of the directory entry.
: dirsmudged? \ -- flag
Return true if the current directory entry is "smudged".
: dirsmudge \ --
Mark the current directory entry as "smudged".
: get-es \ -- entry sector
Return the current directory entry and sector.
: set-es \ entry sector --
Set the current directory entry and sector.
: dircluster@ \ -- clus
Return the current directory cluster.
: dircluster! \ clus --
Sect the current directory cluster, and hence start sector.
: DirValid? \ -- flag
Are we at a valid directory entry for display?
: sbackward \ --
Go to the previous directory cluster, use 1- for root.
: sforward \ --
Go to the next directory cluster, use FAT for subfolders,
1+ for root
: sector0? \ -- flag
Are we at the first sector of a directory?
: dsecup \ --
Step to the next directory sector.
: dsecdn \ --
Step to the previous directory sector.
: entbump \ offset -- n
Go to next/prev entry, where offset = +/-1
: dir++ \ --
Go to the next directory sector/entry.
: dir-- \ --
Go to the previous directory sector/entry.
: noend? \ clus -- notlast?
Return true if the cluster number is not an end-chain-marker.
: OKprev \ -- flag
True if the directory pointer is not at the very beginning
of the directory.
: OKnext \ -- flag ; okay to go forward?
True if the directory pointer is not at the very end of
the directory.
: dirnext \ -- flag
Jump to the next valid directory entry. Return non-zero
if the next entry is valid.
: todir \ --
Skip to first valid entry.
: dirprev \ -- flag
Jump to previous valid directory entry.
#13 buffer: npad \ -- addr
Temporary buffer for building 8.3 filenames.
: padc \ char --
Add one character to npad.
: pad$ \ caddr len --
Add string to npad.
: dfname \ -- caddr len
Return the main part of the file name with trailing spaces
removed.
: dfext \ -- caddr len
Return the extension part of the file name with trailing spaces
removed.
: dfullname \ -- caddr len
Return filename with extension.
: parent? \ -- flag
Return true if the current directory entry is a parent
directory, i.e. "..".
: cluster0 \ -- n
Get the first cluster number of the data for this entry.
: setClus0 \ u dirent --
Set the cluster number into the given directory entry.
: cluster0! \ n --
Set the first cluster number of the data for this entry.
: folder? \ -- flag
Is the current entry a directory/folder?
: dsize \ -- n
The file size in bytes of the file for the current
directory entry.
: dirsect0 \ -- sect
Return the starting sector of the current directory.
: dirhome \ --
Select the first entry in the current directory.
: freechain \ clus0 --
Writes zeros to a chain in the FAT table.
: _freesecs \ --
Frees the chain of the current file.
: _delete \ --
Deletes the current file.
: getcluster \ clus -- clus'
Gets the next free cluster number after this one and marks
it as the last.
: chain+ \ cl -- cl'
Appends a cluster to the end of the chain.
: shrink \ clus0 --
Shrinks a FAT chain and marks the last cluster.
: expand \ clus0 n --
Expands a FAT chain and marks the last cluster.
File names are checked against allowable characters. Dot (.) is allowable once to separate filename and ext fields. The widths of these fields may not exceed 8 and 3 characters respectively.
create goodchars \ -- addr
An array of packed bit flags: 1=allowed: 0..7, 8..9, ...127
: goodch \ char -- flag
Check if the character is allowable in a file/path name.
: goodstr \ caddr len limit -- flag
Check that string has only allowable chars and is not too long.
: name.ext \ a u -- a1 u1 a2 u2
Separate filename string into name and extension strings.
: goodname \ caddr len -- flag
Are filename and extension (could be in a path) valid?
A filename that contains one or more slashes (either '/' or' \') is assumed to be a file path ending in a filename. When one of these is encountered, the path string is stripped off and used it to set the file path. The current directory is not changed. If all of your files are in the same directory, you can use CWD and friends to set the current directory. Begin with a slash to start at the root directory.
: /parse \ addr len -- addr' len' a1 u1
Pick the file name off left end of path. The string a1/u1
contains the next directory element
The current file path is tracked by a path string. The file tree is navigated by selecting the cluster for the subdirectory and adding its name to the path. A ".." folder name trims the path name to go back a level. This path string is for display use.
Because this is not a fully thread-safe file system and only has a single "working directory" for all tasks/threads, you will need to be careful with external access systems such as HTTP, FTP and USB.
pathmax buffer: pathbuf \ -- addr
Path name buffer.
: nopath \ --
Empty the path name buffer.
: path \ -- caddr len
Return the current path string.
: bpath \ b --
Bump the pathname string length.
: pc+ \ char --
Add char to the path string.
: /? \ -- flag
Return true if the last+1 character is '/'.
: trimp \ --
Trim path to just before the last '/' character.
: addp \ caddr len --
Add string to path, separated by a '/' character.
: dirstart \ cluster --
Starts referencing a new directory at the given cluster.
: rootdir \ --
Start at the root directory.
: dirnest \ --
Start at the folder pointed to by the current directory entry.
: sel-folder \ --
Select the current directory entry as a folder.
: _test-file \ caddr len attr -- found?
Search in the current directory for an existing filename
matching none of the given* attribute bits. Return non-zero
if found. If found, the directory sector and entry are saved
in savedDirEnt and the directory pointers address the
found filename entry. The attribute bits settings are:
: test-file \ caddr len -- found?
Search for a file that is neither a directory nor a volume ID.
Upon exit when found, the directory pointers address the
found file.
: cd+ \ caddr len -- ior
Open new directory. CD+ changes the directory up or down
a level.
: $cwd \ addr len -- ior
Open a subdirectory given a file path. Ior=0 if okay.
: setdir \ addr len -- addr' len' ior
Select a subdirectory given a file path, stripping off the filename.
: wipeclus \ clus --
Fill a cluster with zeros, THROW on error.
: getdir \ -- ior
Finds the first directory entry that may be overwritten.
File support is ANS standard, after the stream model used by mainstream computing. File status is held in array of records:
|
The following data types are used:
fam |
"File Access Method", describes read/write permission etc. |
ior |
"IO Result", A return result from most IO calls, this value is 0 for success or non-zero as an error-code. |
fileid |
"File Identifier", a handle for a file. |
1 constant R/O \ -- fam
Get ReadOnly fam. This must be bit 0 to match DOS.
2 constant W/O \ -- fam
Get WriteOnly fam.
3 constant R/W \ -- fam
Get ReadWrite fam.
: bin \ fam -- fam'
Modify a file-access method to include BINARY.
The corresponding FAT attribute bits at byte 11 in each directory entry are:
|
6 cells constant bytes/handle \ -- len
Number of bytes needed for each handle. Must be an integer
number of cells for portability.
#files bytes/handle * buffer: filehandles \ -- addr
Array of file handle records.
cell +user handle \ -- addr
Holds file handle during some operations.
: +handle[] \ n -- addr
Given a handle, return the address in the handle record array.
Why not just use the address as the handle?
\ H.FAM must be first. : h.fam ( -- addr ) 0 +handle[] ; \ r/o, w/o, r/w, etc. : h.dev ( -- addr ) 1 +handle[] ; \ device of this file, 0..15 : h.dire ( -- addr ) 2 +handle[] ; \ directory entry 0..15 : h.dirs ( -- addr ) cell +handle[] ; \ directory sector : h.pos ( -- addr ) [ 2 cells ] literal +handle[] ; \ file position : h.clus0 ( -- addr ) [ 3 cells ] literal +handle[] ; \ starting cluster : h.sect ( -- addr ) [ 4 cells ] literal +handle[] ; \ current sector : h.len ( -- addr ) [ 5 cells ] literal +handle[] ; \ file length
: closeall \ --
Wipes out the file structure to ensure files are closed.
: h.clus! \ cluster --
Set the current file sector.
: h:dir \ --
Points the directory pointers at the file addressed by
current handle.
: after/before \ -- after before
Get the number of bytes before and after the current sector
position.
: _resize \ len --
Given a file size in bytes, allocate clusters in FAT for the
file.
: nexthan \ -- fileid ior
Find available file handle, and make it the current handle.
: (repo-file) \ u -- ior
Repositions the current file. Must not be past the end.
Unprotected.
: repo-file \ u -- ior
Repositions the current file. Must not be past the end.
protected.
: [dir \ -- ; R: -- i*x
Saves current directory information on the return stack
for later restoration by DIR].
This word depends on the return address being a single cell
on the Forth return stack.
: dir] \ -- ; R: i*x --
Restores directory information previously saved on the
return stack by [DIR.
This word depends on the return address being a single cell
on the Forth return stack.
: samesect? \ -- flag
Checks if the next read or write is in a new sector.
: sameclus? \ -- cluster same?
Checks if the next sector is in the same cluster.
: bumppos \ n -- overflow
Bump file position, check for wrap to next sector.
: bumpsec \ len --
Bump file position and maybe sector/cluster.
: read-1sec \ addr len -- addr' len' n
Read from current sector.
: _read-file \ baddr blen -- len ior
File read primitive.
: timestamp \ --
Adds the time and date to the current directory entry.
: copytime \ --
Copy the creation date.
: archive+ \ --
Sets the current directory entry's archive bit.
: filestamp \ --
Stamps the directory entry addressed by the current handle.
: stamp \ --
Mark the file as stamp-pending.
: newchain \ --
Begin a new chain.
: nextwsec \ --
Find next writable sector in file.
: write-1sec \ a u -- a' u'
Write 512 bytes or less to file.
create crlf \ -- addr
Holds a CR/LF pair for WRITE-LINE below.
: name>dir \ caddr len dirent --
Copy the given file name into the given directory entry.
: prepdir \ caddr len clus0 attribs --
Set up a new directory entry using the given name, cluster
and attributes. Note that attribs is in DOS form, not
in the form used by h.fam.
: _newfold \ addr len cluster --
add a new folder entry to the current folder, and step to the
next directory entry.
: es^ \ --
Set the current handle's entry and sector fields.
: ?open_err \ a b c flag err# -- a b c | -- -1 err# [exits caller]
If flag is false/0, just the first three parameters are
returned. If flag is true, the first three parameters
are discarded and -1 and the error number are returned
and exit is from the caller. Provided to reduce code space
and dependent on the return address being on the Forth
return address. The caller must not use local
variables.
: _open-file \ caddr len fam -- fileid ior
File open primitive. Performs no directory restoration.
This word will not open a directory.
: _create-file \ caddr len fam -- fileid ior
Create a file on disk, returning a 0 ior for success and
a file id. If the file already exists, it is truncated to
zero length. Performs no directory restoration.
: _mkdir \ c-addr u -- ior
C-addr/u is an 8.3 directory name with no directory
separators. MKDIR creates a new directory of that name
in the current directory. Directory removal is not properly
supported without the code in DelDirs.fth.
You can use DELETE-FILE to remove an empty directory;
but if the directory is not emptied the disk will be
corrupted.
Performs no directory restoration.
: _mkDirEx \ c-addr u -- ior
As -mkdir, but supports full pathnames.
: (read-file) \ caddr len fileid -- #read ior
Read data from a file. The number of characters actually
read is returned as #read, and ior is returned 0
for a successful read. Unprotected.
: (write-file) \ caddr len fileid -- ior
Write a block of memory to a file. Unprotected.
: (close-file) \ fileid -- ior
Close an open file. Unprotected.
: (read-line) \ caddr u1 fileid -- u2 flag ior
Read an line of text from a file into a buffer, without EOL.
Unprotected.
: (delete-file) \ caddr len -- ior
Delete a named file from disk, and return ior=0 on success.
Unprotected.
: (rename-file) \ caddr1 len1 caddr2 len2 -- ior
Rename a named file on the disk, and return ior=0 on success.
Unprotected.
: (initFATfs) \ -- ior
Initialize the FAT file system. Unprotected.
: (termFATfs) \ --
Shut down the FAT file system. Unprotected.
Semaphore FileSem \ --
Interlocks the file system for multitasking.
: +FileLock \ --
Wait until the file system is available and lock access
: -FileLock \ --
Unlock access to the file system.
The API layer is made safe for multitasking systems by a semaphore. Because the underlying hardware driver may THROW, e.g. for a fatal read/write error, these words include a CATCH.
: open-file \ caddr len fam -- fileid ior
Open an existing file on disk.
This word will not open a directory.
: create-file \ caddr len fam -- fileid ior
Create a file on disk, returning a 0 ior for success and
a file id. If the file already exists, it is truncated to
zero length.
: read-file \ caddr len fileid -- #read ior
Read data from a file. The number of characters actually
read is returned as #read, and ior is returned 0
for a successful read.
: write-file \ caddr len fileid -- ior
Write a block of memory to a file.
: close-file \ fileid -- ior
Close an open file.
: write-line \ caddr len fileid -- ior
Write data followed by CR/LF pair. IOR=0 for success.
: read-line \ caddr u1 fileid -- u2 flag ior
Read an line of text from a file into a buffer, without EOL.
The EOL marker may be either CR/LF (DOS) or LF (Unix).
Read the next line from the file specified by fileid into memory
at the address caddr. At most u1 characters are read.
Up to two line-terminating characters may be read into memory
at the end of the line, but are not included in the count u2.
The line buffer provided by caddr should be at least u1+2
characters long.
If the operation succeeds, flag is true and ior is zero. If a line terminator was received before u1 characters were read, then u2 is the number of characters, not including the line terminator, actually read (0 <= u2 <= u1). When u1 = u2, the line terminator has yet to be reached.
If the operation is initiated when the value returned by FILE-POSITION is equal to the value returned by FILE-SIZE for the file identified by fileid, flag is false, ior is zero, and u2 is zero. If ior is non-zero, an exception occurred during the operation and ior is the I/O result code.
An ambiguous condition exists if the operation is initiated when the value returned by FILE-POSITION is greater than the value returned by FILE-SIZE for the file identified by fileid, or if the requested operation attempts to read portions of the file not written.
At the conclusion of the operation, FILE-POSITION returns the next file position after the last character read.
: resize-file \ len-ud fileid -- ior
Set the size of the file to ud, an unsigned double number.
After using RESIZE-FILE, the result returned by
FILE-POSITION may be invalid.
: reposition-file \ len-ud fileid -- ior
Set file position, and return ior=0 on success.
See the ANS Forth document.
: file-position \ fileid -- len-ud ior
Return file position, and return ior=0 on success.
: file-size \ fileid -- len-ud ior
Get size in bytes of an open file as a double number,
and return ior=0 on success.
: delete-file \ caddr len -- ior
Delete a named file from disk, and return ior=0 on success.
: FileExist? \ c-addr u -- flag
Look to see if a specified file exists, returning TRUE
if the file exists.
: file-status \ caddr len -- x ior
Return the status of the file identified by the character
string c-addr/len. If the file exists, ior is zero;
otherwise ior is the implementation-defined I/O result
code. X contains implementation-defined information about
the file (always zero for FATfiler).
: rename-file \ caddr1 len1 caddr2 len2 -- ior
Rename the file named by the character string c1addr/len1
to the name in the character string caddr2/len2. Ior
is zero on success.
: mkdir \ c-addr u -- ior
C-addr/u is an 8.3 directory name with no directory
separators. MKDIR creates a new directory of that name
in the current directory. Directory removal is not supported
unless the code in DelDirs.fth is compiled.
You can use DELETE-FILE to remove a directory but this
is not recommended unless you know that the directory is
empty. Otherwise, you may end up with lost chains.
: mkDirEx \ c-addr u -- ior
As mkdir but accepts directory separators. Directories
can be created outside the current directory. Directory removal
is not supported unless the code in DelDirs.fth is compiled.
You can use DELETE-FILE to remove a directory but this
is not recommended unless you know that the directory is
empty. Otherwise, you may end up with lost chains.
: cwd \ "<dir>" -- ; CWD <dirname>
An equivalent to the DOS CD or Unix cwd command.
: pwd \ -- ; PWD
Displays the current working directory name.
Because this is not a fully thread-safe file system and only
has a single "working directory" for all tasks/threads, you
will need to be careful with external access systems such as
HTTP, FTP and USB.
: SyncDrive \ --
Force all updated sectors to the disk and empty the sector
cache. This operation is necessary when directories are
modified by a separate task, e.g. when USB makes direct sector
read/write accesses.
: initFATfs \ -- ior
Initialize the FAT file system.
: termFATfs \ --
Shut down the FAT file system.
This device allows files to be used with KEY, EMIT and friends. To avoid having to create a device for each file, one device is built that takes the file id/handle from the USER variable MyFID.
The application programmer is responsible for opening the file, setting the user variable and closing the file.
cell +user MyFID \ -- addr
User variable holding the file handle (0..n-1) in the low
16 bits. The four bytes are used as follows:
0/1 |
file handle |
2 |
character buffer for file read/write |
3 |
flags |
3.0 |
reserved |
3.1 |
set if EOF |
3.2 |
set after file error |
KEY? always returns true. After an EOF or file error, KEY always returns an LF character. This prevents words such as ACCEPT blocking on error.
: FileKey? \ -- flag
Returns true. Does not call PAUSE.
: FileKey \ -- char
The file version of KEY. Executes PAUSE if
LF is returned.
: FileType \ caddr len --
The file equivalent of TYPE. After any file error,
the string is discarded.
: FileEmit \ char --
The file equivalent of EMIT. Uses FileType.
: FileCr \ char --
The file equivalent of CR. Uses FileType and
calls PAUSE.
create FileCon \ -- addr ; OUT managed by upper driver
Generic I/O device for files.
: FileAccept \ c-addr +n1 -- +n2 ; read up to LEN chars into ADDR
As ACCEPT with no echoing or flow control.
: FileEOF? \ -- flag
Return true if the file is at EOF.
: FileErr? \ -- flag
Return true if the file has returned an error.
: ?SetFID \ fileid ior -- ior
Set MyFID according to the results of a file open
or create.
: OpenFileCon \ caddr len -- ior
Open the given file path in read-only mode as the current
task's file input device.
The path is given by caddr/len and the mode by fam.
The I/O pointers IPVEC and OPVEC are not set.
: CreateFileCon \ caddr len -- ior
Create the given file path in read/write mode as the current
task's file output device.
The path is given by caddr/len and the mode by fam.
The I/O pointers IPVEC and OPVEC are not set.
: CloseFileCon \ --
Close the file handle in MyFID.
FATspace? [if]
The code below will be compiled if the equate is non-zero.
: .FATtype \ --
Display FAT type.
: .Drive \ --
Display drive details. InitFATfs must have been
successfully run.
: TotalClusters \ -- n
Returns the
FATtest? [if]
The code below will be compiled if the equate is non-zero.
#512 buffer: SBscr \ -- addr
Scratch sector buffer.
-1 value hFile \ --
File handle for tests.
: go \ --
Start up the file system.
: testline \ n -- caddr len
A line of text to output.
: testw \ #lines "<filename>" --
Test file writing, use in the form:
#lines testw file.ext
: testr \ "<filename>" --
Test file reading with read-line. Use in the form:
testr file.ext
: ?eol \ caddr len -- caddr' len'
Strip the lst character from the line if it is CR or LF.
: rdLnCc \ caddr len -- len' ; 0=eof
Read a line from the file on a character by character basis.
The line terminator is a line feed character.
: testcr \ "<filename>" --
Test file reading character by character. Use in the form:
testcr file.ext
0 value <s> \ -- u
Last sector dumped.
: secdump \ u --
Display the contents of the given sector.
: ns \ --
Dump next sector.
: ps \ --
Dump previous sector.
: ss \ --
Dump same sector again.