duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit d34f22b8a0f7c3b66c6aecc158b0e72995bdf53a
parent aed095e7171dab68aaec1575c71de62d626cf70b
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Mon, 26 Dec 2022 19:18:59 -0500

Reorganize docs

Diffstat:
Mfs/doc/arch.txt | 8++++----
Mfs/doc/cc/lib.txt | 10+++++-----
Mfs/doc/drive.txt | 27+++++++++++++--------------
Rfs/doc/uxn.txt -> fs/doc/emul/uxn.txt | 0
Dfs/doc/file.txt | 232-------------------------------------------------------------------------------
Rfs/doc/color.txt -> fs/doc/gr/color.txt | 0
Afs/doc/gr/rect.fs | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dfs/doc/grid.txt | 75---------------------------------------------------------------------------
Mfs/doc/index.txt | 9++++-----
Rfs/doc/alloc.txt -> fs/doc/lib/alloc.txt | 0
Dfs/doc/rect.fs | 56--------------------------------------------------------
Afs/doc/sys/file.txt | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afs/doc/sys/grid.txt | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rfs/doc/io.txt -> fs/doc/sys/io.txt | 0
Rfs/doc/loop.txt -> fs/doc/sys/loop.txt | 0
Rfs/doc/mouse.txt -> fs/doc/sys/mouse.txt | 0
Rfs/doc/ps2.txt -> fs/doc/sys/ps2.txt | 0
Rfs/doc/screen.fs -> fs/doc/sys/screen.fs | 0
Mfs/doc/usage.txt | 12++++++------
Mfs/gr/color.fs | 2--
Mfs/gr/rect.fs | 1-
Mfs/sys/file.fs | 1-
Mfs/sys/mouse.fs | 2--
Mfs/sys/screen.fs | 2--
24 files changed, 396 insertions(+), 405 deletions(-)

diff --git a/fs/doc/arch.txt b/fs/doc/arch.txt @@ -122,10 +122,10 @@ end of "boothi". You can call "init" in xcomp/init.fs, but by doing so, you'll monopolize the file handle that was opened for xcomp/init.fs. One of the things that your "init" word has to do is to set up ConsoleIn (see -doc/io), which until now is still on BootIn, a structure that reads the embedded -code from memory. That code stream is about to run out. If your system is -interactive, you'll typically want to load sys/rdln and have init call "rdln$" -which sets ConsoleIn to RdlnIn, which then makes the system interactive. +doc/sys/io), which until now is still on BootIn, a structure that reads the +embedded code from memory. That code stream is about to run out. If your system +is interactive, you'll typically want to load sys/rdln and have init call +"rdln$" which sets ConsoleIn to RdlnIn, which then makes the system interactive. The system is yours. diff --git a/fs/doc/cc/lib.txt b/fs/doc/cc/lib.txt @@ -41,8 +41,8 @@ int isdigit(char c) ### I/O -The I/O API is a simple layer over the system I/O described at doc/io. `hdl` is -a regular I/O handle. +The I/O API is a simple layer over the system I/O described at doc/sys/io. `hdl` +is a regular I/O handle. int fgetc(int hdl) --> IO :getc void fputc(char c, int hdl) --> IO :putc @@ -82,7 +82,7 @@ variable number of arguments which must match the number of formatting placeholder in `fmt`, *in reverse order* (this simplifies the implementation logic a lot). For example, `printf(3, 2, 1, "%b %w %d")` prints `01 0002 3`. -printf formatting arguments are described in doc/io. +printf formatting arguments are described in doc/sys/io. fscanf doesn't exist in sys/io yet and is only and CC stdlib. It supports only the `%d` placeholder. Like printf, it's funky in its arguments, but in the @@ -98,8 +98,8 @@ For example, `sscanf("%d %d %d", "5 6 7")` results in PS receiveing elements to PS. printf and scanf each have `f` and `s` variants. Without a variant, printing and -scanning is done through StdOut and StdIn (see doc/io). The `f` variant allow us -to choose another target I/O handle. +scanning is done through StdOut and StdIn (see doc/sys/io). The `f` variant +allow us to choose another target I/O handle. For the `s` variant, we have a static buffer wrapped around a `MemFile` that is used. The resulting string is a memory in that buffer and is overwritten at each diff --git a/fs/doc/drive.txt b/fs/doc/drive.txt @@ -1,26 +1,25 @@ # Drive API -The sys/drive subsystem offers a unified API to read and write to mass storage. -It does so in blocks of bytes of a definite size which we call "sector". -Sectors in the Drive API are organized in a linear manner (LBA, Logical Block +TODO: the Drive struct is defined in xcomp/bootlo and I can't think of an +adequate place for this documentation. For now, it's here. + +The Drive struct offers a unified API to read and write to mass storage. It +does so in blocks of bytes of a definite size which we call "sector". Sectors +in the Drive API are organized in a linear manner (LBA, Logical Block Addressing). If the underlying mass storage driver interfaces with a CHS -(cylinder, head, sector) system, it's the driver's responsibility to convert -LBA to CHS. +(cylinder, head, sector) system, it's the driver's responsibility to convert LBA +to CHS. -The drive API exposes the features of the underlying driver through a specific -data structure, called a Drive, which is 12 bytes in length in the form of 3 -fields of 4 bytes: +Fields: -secsz -:sec@ -:sec! +secsz an integer describing, in bytes, the size of sectors read and written + by the driver. It's often 512 bytes. -secsz is an integer describing, in bytes, the size of sectors read and written -by the driver. It's often 512 bytes. +Methods: :sec@ ( sec dst drv -- ) Read sector "sec" in memory address "dst", which needs to be a buffer at least - "drvsecsz" in size. "drv" is a pointer to a Drive structure. + "secsz" in size. "drv" is a pointer to a Drive structure. :sec! ( sec src drv -- ) Write sector "sec" from memory address "src". diff --git a/fs/doc/uxn.txt b/fs/doc/emul/uxn.txt diff --git a/fs/doc/file.txt b/fs/doc/file.txt @@ -1,232 +0,0 @@ -# File subsystem - -The file subsystem allows the system to interact with filesystems. - -Files and directories all live within filesystems. More than one filesystem can -be active at once and each of these filesystems is designated by a letter. For -example, the boot filesystem is always "A". There's a maximum of 26 active -filesystems. - -Filesystems contain files and directories. A file is a blob of data that exists -within a directory. A directory is a container for files and other directories. -Each filesystem has one root directory. - -Files and directories are referred to with strings of characters that we call -"paths". Those paths begin with a filesystem identifier, followed by name of -directory and file. A directory name can be followed by a "/" character to -indicate that we want to refer to one of its children. - -There is also the concept of an "active" directory. When paths don't start with -a drive letter, the path is relative to this active directory. A path starting -with "/" refers to the root directory of the active directory's filesystem. The -initial active directory is the boot filesystem's root directory (A:). - -Examples: - -A: root of filesystem A -A:foo.txt file "foo.txt" inside A's root directory -B:foo/bar.fs file "bar.fs" inside "foo" directory inside B's root -bar.fs file "bar.fs" in active directory -/foo.fs file "foo.fs" in active filesystem's root directory - -## Filesystem API - -When the code refers to a filesystem, it does so through a definite structure: - -drv -- Drive pointer (see doc/drive) - -:child ( dirid name fs -- id ) - Enumerate the contents of directory "dirid" and look for name "name". If - found, returns the ID of the child (either a file or directory), otherwise, - return 0. See below for the concept of "ID". - -:info ( id fs -- info ) - Returns a FSInfo structure (described below) corresponding to the specified - ID. This structure is a singleton and is only valid until the next :info call. - -:open ( id fs -- hdl ) - Open file at path and return a handle through which other file-related word - identify the target file. Once a file isn't used anymore, it should be - closed with :close. Aborts on error. - -:iter ( w id fs -- ) - Iterate through all children of directory "id", ignoring "." and ".." entries. - For each child iterated upon, call word "w" which has the signature - "id fs --", "id" being the ID of the child. - -:newfile ( dirid name fs -- id ) - Create a new empty file named "name" in "dirid" and return the ID of the new - file. Aborts on error. - -:newdir ( dirid name fs -- id ) - Create a new directory named "name" in "dirid" and return the ID of the new - directory. Aborts on error. - -... followed by whatever data the FS implementation needs. - -In each method, "fs" refers to a filesystem, a pointer to the structure decribed -above. - -Additionally, the Filesystem struct also has these convenience methods which are -independent of the underlying implementation: - -:?newfile ( dirid name fs -- id ) - Create a new file if it doesn't exist. If it exists, return its ID. - -:?newdir ( dirid name fs -- id ) - Create a new directory if it doesn't exist. If it exists, return its ID. - -## File API - -The File API is a specialization of the I/O API (doc/io) for accessing files in -a filesystem. It also works with "handles", which we call a File handle. Of -course, it starts with the I/O prelude, but then adds its own prelude: - -(I/O prelude) -:seek - -These words have the following meaning: - -:seek ( pos hdl -- ) - Place the handle at offset "pos" (in bytes). - -## FSInfo API - -The structure returned by ":info" above goes as follows: - -name -- a pointer to a string -size -- size of the file, or 0 for a directory -dir? -- whether the element is a directory - -## Path API - -The Path structure represents a path from any of the currently mounted -filesystems. It has 2 fields: "fs", which is a pointer to a Filesystem struct -and "id", which is the FS ID corresponding to the path. Path allocations are -managed through a small "rolling" buffer, which means that if you want to hold -on to a Path reference a little longer, you should copy it elsewhere. - -:new ( fs id -- path ) - Allocate a new Path reference with the specified fields - -:find ( str -- path-or-0 ) - Find FS ID corresponding to path and return Path reference or 0 if not found. - -:find# ( str -- path ) - Like :find, but errors out if not found. - -:fload ( self -- ) - Open specified path and interpret it as Forth source. - -:floaded? ( self -- f ) - Returns whether this particular path has ever been loaded with :fload. - -:chdir ( self -- ) - Change current directory to path. In subsequent path finds, if the path - doesn't start with "/", the search will start from this directory. - Aborts if path is not found. - -:open ( self -- file ) -:info ( self -- file ) -:child ( name self -- path-or-0 ) -:iter ( w self -- ) - Convenience proxies to the corresponding methods in the Filesystem API. - -:iterdirs ( w self -- ) - Calls :iter but filters the call to 'w' to directories only. On top of this, - an additional "info" argument is passed to 'w', making its signature - "id fs info -- " - -:iterfiles ( w self -- ) - Same as :iterdirs, but for files. - -## Global variables - -The File subsystem has 2 important global variables: - -bootfs is a pointer to the Filesystem structure from which the system was -booted. It's used only until the File subsystem is initialized. - -curpath is a Path bind that points to the "current directory". It is initialized -to the root directory of bootfs but can be changed with Path :chdir. - -## Paths - -Paths uniquely identify a directory or a file on the current set of mounted -filesystems. Paths can take 3 forms: absolute, FS relative and relative. - -Absolute paths begin with a drive letter ("A" is the boot drive, "B" is the -second one, etc.) followed by ":", followed by a relative path. Example: - -a:lib/str.fs - -FS relative are path relative to the currently "active" filesystem, that is, the -filesystem that contains the "current directory". Such paths begin by a "/" -followed by a relative path. Example: - -/lib/str.fs - -Relative paths are paths relative to the "current directory". These paths begin -directly with a name. Example for a "current directory" set to "/lib": - -str.fs - -## File ID design considerations - -When we refer to a file or directory ID, we refer to a single 32-bit number -uniquely identifying the file or directory in the volume. From this number, we -must be able to find the file or directory in the volume so that we can open it -or enumerate it. The ID of the root directory is always zero. - -That IDs are 32-bit make their manipulation straightforward. One might fear that -32 bits are not enough to identify all elements of big filesystems. - -On many filesystems, 32 bits are enough. For example, in ext4, inodes always fit -32 bits, even in 64-bit mode. - -For FAT32, it's another matter. The straightforward way to derive an ID from an -element is to return the offset of its DirEntry and divide it by 32. This means -that this ID scheme could only address 64GB volumes. - -This would mean that the File API would be broken on a subset of filesystems. -Does it mean that Dusk couldn't read them? No, only that file/dir enumeration -would have to go through FS-specific tools. I think that this inconvenience is -worth it if it means an overall simpler API. - -## Path literals - -There are 2 words for Path/File shortcuts: p" and f". - -p" foo" is a shortcut for S" foo" curpath :find# and f" foo" is a shortcut for -p" foo" Path :open. - -## MemFile - -MemFile is a structure that extends File and provides read/write/seek -capabilities to a memory buffer. It extends File with those words: - -:new ( sz -- hdl ) - Allocate a new buffer of size "sz" and return it. - -:buf( ( hdl -- a ) - Address of the buffer. - -:)buf ( hdl -- a ) - Address following the last byte of the buffer. - -:ptr ( hdl -- a ) - Address corresponding to current position. - -## File loading shortcuts - -Feeding the Forth intepreter with the contents of a file is something you'll -want to do fairly often, which might not sit well with the verbosity of Path's -API. A shortcut to finding a Path and then loading it is "f<<". This word, -followed by a path to load in the input stream, with call :fload on that path. - -It happens frequently that some piece of code depends on some other so we want -to load these files first. However, some units are depended upon by more than -one units and we don't want to load these pieces of code twice. To this end, -whenever a file is loaded, we record its ID in a linked list to remember we -loaded it. If you use the "?f<<" word instead of "f<<", the specified file will -be loaded only if it wasn't already loaded. diff --git a/fs/doc/color.txt b/fs/doc/gr/color.txt diff --git a/fs/doc/gr/rect.fs b/fs/doc/gr/rect.fs @@ -0,0 +1,56 @@ +# Rectangles + +Provides a Rect structure that helps with operations on rectangles. + +## API + +Fields: + +x +y +width +height + +:new ( x y width height -- rect ) + Allocate a new rectangle with specified values. + +:tmpnew ( x y width height -- rect ) + Allocate new rectangle in system scratchpad (doc/lib/alloc). + +:topleft ( self -- x y ) + Top-left point of the rectangle. + +:bottomright ( self -- x y ) + Bottom-right point of the rectangle. + +:= ( other self -- f ) + Whether the rectangle has the same field values as "other". + +:null? ( self -- f ) + Whether the rectangle has a 0 width or height. + +:haspoint? ( x y self -- f ) + Whether coordinates "x,y" are inside the rectangle. + +:hasrect? ( other self -- f ) + Wether rectangle "other" is entirely contained (can be equal) in rectangle + "self". + +:intersects? ( other self -- f ) + Whether one part of "other" intersects with "self" (can be contained). + +:intersection ( other self -- rect ) + Yields a rectangle (created with :tmpnew) that represents the intersection of + "other" and "self". If there is no intersection, will yield a null rectangle. + +:copy ( other self -- ) + Copy values in all fields of "other" into "self". + +:move ( x y self -- ) + Move "self"'s top-left point to "x,y". + +:resize ( width height self -- ) + Resize "self" to "width,height". + +:print ( self -- ) + Print a human readable representation of "self". diff --git a/fs/doc/grid.txt b/fs/doc/grid.txt @@ -1,75 +0,0 @@ -# Grid subsystem - -The grid is a matrix of characters that represents what is seen on a screen. It -has a fixed number of columns (COLS) and lines (LINES) and maintains a current -position (pos) as a single number encoded as "y*COLS+x". - -The grid is implemented as a IO structure extending ByteWriter (see doc/io). Its -"pos" field is the "cursor" position on the screen and the IO screen represents -the terminal screen: whenever a byte is written to it through the IO methods, -the character is written at cursor position and that cursor is advanced by one. - -If a NL character ($0a) is written to it, the grid skips to the next line. If a -BS character ($08) is written to it, the cursor goes back one character. - -In newline conditions (NL character or wrapping around the end of line), we -clear the next line and move the cursor there. If we're at the end of the -screen, we scroll if the underlying driver allows it. Otherwise, we wrap around -to the top. - -The grid subsystem defines the Grid structure as well as a "grid" structbind to -it. During initialization, what you'll want to do is create an instance of the -Grid from the driver and bind it to "grid". - -## Spit mode - -Sometimes, we want to write things to screen that are at a position other than -the cursor and we don't want to update the cursor while writing there. Moreover, -we don't want the special handling of the regular mode (newline handling). One -such example is the ":dbgnum1!" word. - -In these cases, you'll want to enable the "spit" mode with ":spiton", do your -thing, then go back to regular mode with ":spitoff". - -## Driver implementation - -To implement the grid, we need an underlying driver to extend it and implement -its methods, namely: - -:cell! ( c pos -- ) - Set content of the cell at "pos" to character "c". - -:cursor! ( pos -- ) - Move cursor to "pos". - -:newln ( oldln -- newln ) - Prepare new line under line number "newln" and return the line number of that - prepared line as "newln". Normally, "newln" is "oldln+1", but if scrolling is - involved, then "newln" will be "oldln". - -## API - -:pcell! ( c self -- ) - Set content of the cell at current pos to character "c". - -:clrline ( ln self -- ) - Set all cells in line number "ln" to spaces. - -:linefeed ( self -- ) - Clear a new line below the current one, scrolling if needed, then set pos to - the beginning of that line - -:spiton ( pos self -- ) - Enable "spit mode" starting at position "pos". This doesn't affect regular - position. - -:spitoff ( self -- ) - Disable "spit mode". - -:dbgnum1! ( n self -- ) - Spit "n", formatted with ".x", at the top right corner of the screen. Useful - for debugging purposes. To debug live numbers, you can combine this with - sys/loop. - -:dbgnum2! ( n self -- ) - Same as :dbgnum1!, but one slot to the left. diff --git a/fs/doc/index.txt b/fs/doc/index.txt @@ -13,6 +13,10 @@ If you're reading this from a Dusk system, then you're ready to read doc/usage. ## Contents of this documentation +Documentation about specific units have the same path in the documentation as +they have in the system and are not listed below. For example, for documentation +about sys/io, you'll want to open doc/sys/io. + usage General usage guide dict Dictionary of system word install Deploy Dusk to another machine @@ -21,11 +25,6 @@ dirs Directory structure arch Architecture details impl Implementation details code Code conventions -io I/O API -drive Drive API -file File API -alloc Memory allocation API -ps2 PS/2 subsystem x86 i386 implementation details asm/ Assemblers documentation cc/ C compiler documentation diff --git a/fs/doc/alloc.txt b/fs/doc/lib/alloc.txt diff --git a/fs/doc/rect.fs b/fs/doc/rect.fs @@ -1,56 +0,0 @@ -# Rectangles - -Provides a Rect structure that helps with operations on rectangles. - -## API - -Fields: - -x -y -width -height - -:new ( x y width height -- rect ) - Allocate a new rectangle with specified values. - -:tmpnew ( x y width height -- rect ) - Allocate new rectangle in system scratchpad (doc/alloc). - -:topleft ( self -- x y ) - Top-left point of the rectangle. - -:bottomright ( self -- x y ) - Bottom-right point of the rectangle. - -:= ( other self -- f ) - Whether the rectangle has the same field values as "other". - -:null? ( self -- f ) - Whether the rectangle has a 0 width or height. - -:haspoint? ( x y self -- f ) - Whether coordinates "x,y" are inside the rectangle. - -:hasrect? ( other self -- f ) - Wether rectangle "other" is entirely contained (can be equal) in rectangle - "self". - -:intersects? ( other self -- f ) - Whether one part of "other" intersects with "self" (can be contained). - -:intersection ( other self -- rect ) - Yields a rectangle (created with :tmpnew) that represents the intersection of - "other" and "self". If there is no intersection, will yield a null rectangle. - -:copy ( other self -- ) - Copy values in all fields of "other" into "self". - -:move ( x y self -- ) - Move "self"'s top-left point to "x,y". - -:resize ( width height self -- ) - Resize "self" to "width,height". - -:print ( self -- ) - Print a human readable representation of "self". diff --git a/fs/doc/sys/file.txt b/fs/doc/sys/file.txt @@ -0,0 +1,232 @@ +# File subsystem + +The file subsystem allows the system to interact with filesystems. + +Files and directories all live within filesystems. More than one filesystem can +be active at once and each of these filesystems is designated by a letter. For +example, the boot filesystem is always "A". There's a maximum of 26 active +filesystems. + +Filesystems contain files and directories. A file is a blob of data that exists +within a directory. A directory is a container for files and other directories. +Each filesystem has one root directory. + +Files and directories are referred to with strings of characters that we call +"paths". Those paths begin with a filesystem identifier, followed by name of +directory and file. A directory name can be followed by a "/" character to +indicate that we want to refer to one of its children. + +There is also the concept of an "active" directory. When paths don't start with +a drive letter, the path is relative to this active directory. A path starting +with "/" refers to the root directory of the active directory's filesystem. The +initial active directory is the boot filesystem's root directory (A:). + +Examples: + +A: root of filesystem A +A:foo.txt file "foo.txt" inside A's root directory +B:foo/bar.fs file "bar.fs" inside "foo" directory inside B's root +bar.fs file "bar.fs" in active directory +/foo.fs file "foo.fs" in active filesystem's root directory + +## Filesystem API + +When the code refers to a filesystem, it does so through a definite structure: + +drv -- Drive pointer (see doc/drive) + +:child ( dirid name fs -- id ) + Enumerate the contents of directory "dirid" and look for name "name". If + found, returns the ID of the child (either a file or directory), otherwise, + return 0. See below for the concept of "ID". + +:info ( id fs -- info ) + Returns a FSInfo structure (described below) corresponding to the specified + ID. This structure is a singleton and is only valid until the next :info call. + +:open ( id fs -- hdl ) + Open file at path and return a handle through which other file-related word + identify the target file. Once a file isn't used anymore, it should be + closed with :close. Aborts on error. + +:iter ( w id fs -- ) + Iterate through all children of directory "id", ignoring "." and ".." entries. + For each child iterated upon, call word "w" which has the signature + "id fs --", "id" being the ID of the child. + +:newfile ( dirid name fs -- id ) + Create a new empty file named "name" in "dirid" and return the ID of the new + file. Aborts on error. + +:newdir ( dirid name fs -- id ) + Create a new directory named "name" in "dirid" and return the ID of the new + directory. Aborts on error. + +... followed by whatever data the FS implementation needs. + +In each method, "fs" refers to a filesystem, a pointer to the structure decribed +above. + +Additionally, the Filesystem struct also has these convenience methods which are +independent of the underlying implementation: + +:?newfile ( dirid name fs -- id ) + Create a new file if it doesn't exist. If it exists, return its ID. + +:?newdir ( dirid name fs -- id ) + Create a new directory if it doesn't exist. If it exists, return its ID. + +## File API + +The File API is a specialization of the I/O API (doc/sys/io) for accessing files +in a filesystem. It also works with "handles", which we call a File handle. Of +course, it starts with the I/O prelude, but then adds its own prelude: + +(I/O prelude) +:seek + +These words have the following meaning: + +:seek ( pos hdl -- ) + Place the handle at offset "pos" (in bytes). + +## FSInfo API + +The structure returned by ":info" above goes as follows: + +name -- a pointer to a string +size -- size of the file, or 0 for a directory +dir? -- whether the element is a directory + +## Path API + +The Path structure represents a path from any of the currently mounted +filesystems. It has 2 fields: "fs", which is a pointer to a Filesystem struct +and "id", which is the FS ID corresponding to the path. Path allocations are +managed through a small "rolling" buffer, which means that if you want to hold +on to a Path reference a little longer, you should copy it elsewhere. + +:new ( fs id -- path ) + Allocate a new Path reference with the specified fields + +:find ( str -- path-or-0 ) + Find FS ID corresponding to path and return Path reference or 0 if not found. + +:find# ( str -- path ) + Like :find, but errors out if not found. + +:fload ( self -- ) + Open specified path and interpret it as Forth source. + +:floaded? ( self -- f ) + Returns whether this particular path has ever been loaded with :fload. + +:chdir ( self -- ) + Change current directory to path. In subsequent path finds, if the path + doesn't start with "/", the search will start from this directory. + Aborts if path is not found. + +:open ( self -- file ) +:info ( self -- file ) +:child ( name self -- path-or-0 ) +:iter ( w self -- ) + Convenience proxies to the corresponding methods in the Filesystem API. + +:iterdirs ( w self -- ) + Calls :iter but filters the call to 'w' to directories only. On top of this, + an additional "info" argument is passed to 'w', making its signature + "id fs info -- " + +:iterfiles ( w self -- ) + Same as :iterdirs, but for files. + +## Global variables + +The File subsystem has 2 important global variables: + +bootfs is a pointer to the Filesystem structure from which the system was +booted. It's used only until the File subsystem is initialized. + +curpath is a Path bind that points to the "current directory". It is initialized +to the root directory of bootfs but can be changed with Path :chdir. + +## Paths + +Paths uniquely identify a directory or a file on the current set of mounted +filesystems. Paths can take 3 forms: absolute, FS relative and relative. + +Absolute paths begin with a drive letter ("A" is the boot drive, "B" is the +second one, etc.) followed by ":", followed by a relative path. Example: + +a:lib/str.fs + +FS relative are path relative to the currently "active" filesystem, that is, the +filesystem that contains the "current directory". Such paths begin by a "/" +followed by a relative path. Example: + +/lib/str.fs + +Relative paths are paths relative to the "current directory". These paths begin +directly with a name. Example for a "current directory" set to "/lib": + +str.fs + +## File ID design considerations + +When we refer to a file or directory ID, we refer to a single 32-bit number +uniquely identifying the file or directory in the volume. From this number, we +must be able to find the file or directory in the volume so that we can open it +or enumerate it. The ID of the root directory is always zero. + +That IDs are 32-bit make their manipulation straightforward. One might fear that +32 bits are not enough to identify all elements of big filesystems. + +On many filesystems, 32 bits are enough. For example, in ext4, inodes always fit +32 bits, even in 64-bit mode. + +For FAT32, it's another matter. The straightforward way to derive an ID from an +element is to return the offset of its DirEntry and divide it by 32. This means +that this ID scheme could only address 64GB volumes. + +This would mean that the File API would be broken on a subset of filesystems. +Does it mean that Dusk couldn't read them? No, only that file/dir enumeration +would have to go through FS-specific tools. I think that this inconvenience is +worth it if it means an overall simpler API. + +## Path literals + +There are 2 words for Path/File shortcuts: p" and f". + +p" foo" is a shortcut for S" foo" curpath :find# and f" foo" is a shortcut for +p" foo" Path :open. + +## MemFile + +MemFile is a structure that extends File and provides read/write/seek +capabilities to a memory buffer. It extends File with those words: + +:new ( sz -- hdl ) + Allocate a new buffer of size "sz" and return it. + +:buf( ( hdl -- a ) + Address of the buffer. + +:)buf ( hdl -- a ) + Address following the last byte of the buffer. + +:ptr ( hdl -- a ) + Address corresponding to current position. + +## File loading shortcuts + +Feeding the Forth intepreter with the contents of a file is something you'll +want to do fairly often, which might not sit well with the verbosity of Path's +API. A shortcut to finding a Path and then loading it is "f<<". This word, +followed by a path to load in the input stream, with call :fload on that path. + +It happens frequently that some piece of code depends on some other so we want +to load these files first. However, some units are depended upon by more than +one units and we don't want to load these pieces of code twice. To this end, +whenever a file is loaded, we record its ID in a linked list to remember we +loaded it. If you use the "?f<<" word instead of "f<<", the specified file will +be loaded only if it wasn't already loaded. diff --git a/fs/doc/sys/grid.txt b/fs/doc/sys/grid.txt @@ -0,0 +1,76 @@ +# Grid subsystem + +The grid is a matrix of characters that represents what is seen on a screen. It +has a fixed number of columns (COLS) and lines (LINES) and maintains a current +position (pos) as a single number encoded as "y*COLS+x". + +The grid is implemented as a IO structure extending ByteWriter (see doc/sys/io). +Its "pos" field is the "cursor" position on the screen and the IO screen +represents the terminal screen: whenever a byte is written to it through the IO +methods, the character is written at cursor position and that cursor is advanced +by one. + +If a NL character ($0a) is written to it, the grid skips to the next line. If a +BS character ($08) is written to it, the cursor goes back one character. + +In newline conditions (NL character or wrapping around the end of line), we +clear the next line and move the cursor there. If we're at the end of the +screen, we scroll if the underlying driver allows it. Otherwise, we wrap around +to the top. + +The grid subsystem defines the Grid structure as well as a "grid" structbind to +it. During initialization, what you'll want to do is create an instance of the +Grid from the driver and bind it to "grid". + +## Spit mode + +Sometimes, we want to write things to screen that are at a position other than +the cursor and we don't want to update the cursor while writing there. Moreover, +we don't want the special handling of the regular mode (newline handling). One +such example is the ":dbgnum1!" word. + +In these cases, you'll want to enable the "spit" mode with ":spiton", do your +thing, then go back to regular mode with ":spitoff". + +## Driver implementation + +To implement the grid, we need an underlying driver to extend it and implement +its methods, namely: + +:cell! ( c pos -- ) + Set content of the cell at "pos" to character "c". + +:cursor! ( pos -- ) + Move cursor to "pos". + +:newln ( oldln -- newln ) + Prepare new line under line number "newln" and return the line number of that + prepared line as "newln". Normally, "newln" is "oldln+1", but if scrolling is + involved, then "newln" will be "oldln". + +## API + +:pcell! ( c self -- ) + Set content of the cell at current pos to character "c". + +:clrline ( ln self -- ) + Set all cells in line number "ln" to spaces. + +:linefeed ( self -- ) + Clear a new line below the current one, scrolling if needed, then set pos to + the beginning of that line + +:spiton ( pos self -- ) + Enable "spit mode" starting at position "pos". This doesn't affect regular + position. + +:spitoff ( self -- ) + Disable "spit mode". + +:dbgnum1! ( n self -- ) + Spit "n", formatted with ".x", at the top right corner of the screen. Useful + for debugging purposes. To debug live numbers, you can combine this with + sys/loop. + +:dbgnum2! ( n self -- ) + Same as :dbgnum1!, but one slot to the left. diff --git a/fs/doc/io.txt b/fs/doc/sys/io.txt diff --git a/fs/doc/loop.txt b/fs/doc/sys/loop.txt diff --git a/fs/doc/mouse.txt b/fs/doc/sys/mouse.txt diff --git a/fs/doc/ps2.txt b/fs/doc/sys/ps2.txt diff --git a/fs/doc/screen.fs b/fs/doc/sys/screen.fs diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt @@ -404,11 +404,11 @@ to add some complexity on the I/O front: the need to have redirectable and abstract I/Os for applications and the need to have a console that reads line by line. -In the middle of the boot process, sys/io is loaded (see doc/io). This subsystem -introduces the StdIn and StdOut structures (with their "stdin" ( -- c ) and -"stdout" ( c -- ) proxies) and, by default, plugs new ConsoleIn and ConsoleOut -structures into them. These structures simply plug themselves into "key" and -"emit". +In the middle of the boot process, sys/io is loaded (see doc/sys/io). This +subsystem introduces the StdIn and StdOut structures (with their "stdin" ( -- c +) and "stdout" ( c -- ) proxies) and, by default, plugs new ConsoleIn and +ConsoleOut structures into them. These structures simply plug themselves into +"key" and "emit". From that point on, the system interpret loop feeds itself from "stdin". "emit" and "stdout" become synonymous, the latter being preferred. "emit" becomes the @@ -422,6 +422,6 @@ a whole line is ready to be interpreted, that is fed to stdin. ## Loading files Dusk's interpreter can be fed with the contents of files through various words -such as :fload, f<< and ?f<<. Refer to doc/file. +such as :fload, f<< and ?f<<. Refer to doc/sys/file. If you want to compile C source files, you'll want to look at doc/cc. diff --git a/fs/gr/color.fs b/fs/gr/color.fs @@ -1,5 +1,3 @@ -\ Color encodings. see doc/color - $01 const COLOR_RGB24 : r8g8b8>rgb24 ( r8 g8 b8 -- n ) swap 8 lshift or swap 16 lshift or ; diff --git a/fs/gr/rect.fs b/fs/gr/rect.fs @@ -1,4 +1,3 @@ -\ Rectangles. see doc/rect require /sys/scratch.fs struct[ Rect diff --git a/fs/sys/file.fs b/fs/sys/file.fs @@ -1,4 +1,3 @@ -\ File subsystem, see doc/file 0 S" sys" bootfs Filesystem :child S" io.fs" bootfs Filesystem :child bootfs swap fload diff --git a/fs/sys/mouse.fs b/fs/sys/mouse.fs @@ -1,5 +1,3 @@ -\ Mouse subsystem. see doc/mouse - struct[ Mouse $01 const BTN_LEFT $02 const BTN_RIGHT diff --git a/fs/sys/screen.fs b/fs/sys/screen.fs @@ -1,5 +1,3 @@ -\ Screen subsystem. see doc/screen - struct[ Screen sfield width sfield height