File device

This is the user manual for the file device of the Bedrock computer system.

This document is aimed at people who are learning about or writing programs for the Bedrock system. For people who are implementing the system from scratch, the file device specification will provide more relevant information.

Overview

The file device provides access to the filesystem for accessing files and listing directories.

Concepts

Bedrock file paths use the same format regardless of the underlying filesystem. File paths are UTF-8 encoded strings that are at most 255 bytes long and do not contain any byte from 00 to 1F. The / character is used as the path separator, and paths must begin with a separator and not end with a separator. The following is a list of some valid Bedrock-style file paths:

/
/tmp/new file.txt
/home/ben/Desktop
/C/Users/Ben/Desktop

A child entry in a folder can be selected by writing an index value to the address port while that folder is open. Once a child is selected, the child path and child type ports will return the name, path, and type of that child. The directory structure can be traversed by writing to the child type port to descend into the selected child, or writing to the type port to ascend to the parent folder.

Ports

Port Name Description Read Write
90 Open Open a file or folder.
91 Action Create, move, or delete an entry.
92 Head Read and write to the open file.
93 aliased aliased
94 Path Path of the open entry.
95 Type Type of the open entry.
96 Child path Path of the selected child entry.
97 Child type Type of the selected child entry.
98 Address Select file address or child entry.
99 continued continued
9A continued continued
9B continued continued
9C Length Length of the current entry.
9D continued continued
9E continued continued
9F continued continued

Open

Reading a byte from this port will return FF if a file or folder is open, or 00 otherwise. Writing each byte of a filepath to this port followed by a zero byte will attempt to open that file or folder.

See the opening a folder example.

Action

Reading a byte from this port will return FF if an error occured since the port was last read, or 00 otherwise. An error occurs when a read, write, open, resize, create, move, or delete action cannot be performed.

Writing each byte of a filepath to this port followed by a zero byte will attempt to perform an action. If no file or folder is open, a new file will be created at the written path. If a file or folder is open, it will be moved to the written path. If the written path is blank, the file or folder will be deleted instead.

See the creating a file example.

If a file is open, reading a byte from this port will return a byte from the the current address of the file, and writing a byte will write that byte to the current address of the file. Each read and write will increment the address port, so that successive reads and writes will access successive bytes of the file.

This port is followed by a port alias, allowing double values to be read or written with a single instruction.

See the reading and writing to files example.

Path

Reading from this port will return the next byte from the path of the open file or folder, ending with a zero byte. Writing a non-zero byte will start reading from the final path component, and writing a zero byte will restart from the beginning.

Type

Reading from this port will return FF if the open entry is a folder, or 00 otherwise. Writing any value to this port while an entry is open will open the parent folder of that entry, and writing while no entry is open will open the home folder.

Child path

Reading from this port will return the next byte from the path of the selected child entry, ending with a zero byte. Writing a non-zero byte will start reading from the final path component, and writing a zero byte will restart from the beginning.

A child entry is selected by writing to the address port.

Child type

Reading from this port will return FF if the selected child entry is a folder, or 00 otherwise. Writing any value to this port while a child entry is selected will open that entry.

A child entry is selected by writing to the address port.

Address

Reading from this port when a file is open will return the current file address, and writing will set the address.

Writing to this port when a folder is open will select the indexed entry of that folder as the selected child, which is used by the child path and child type ports.

Length

Reading from this port when a file is open will return the size of that file in bytes, and reading when a folder is open will return the number of entries in that folder.

Writing to this port when a file is open will resize that file.

Wake behaviour

This device will never wake the system from sleep.

Examples

Opening a folder

To open a folder, write the path of that folder to the open port followed by a zero byte:

%λ: JMSr: ;

λ:{"/"} JMS:open-folder HLT

@open-file @open-folder  ( path* -- )
  :90 JMS:write-string
  :00 STD:90 JMPr

@write-string  ( string* port -- )
  STA:~port JMP:~start &loop
    STD:[&port 00] INC* &start
    DUP* LDA DUP JCN:~loop
  POP POP* JMPr

Creating a file

To create a new file, write a zero to the open port to close any open files, and then write the path of the new line to the action port followed by a zero byte:

%λ: JMSr: ;

λ:{"/new_file.txt"} JMS:create-file HLT

@create-file  ( path* -- )
  :00 STD:90
  :91 JMS:write-string
  :00 STD:91 JMPr

@write-string  ( string* port -- )
  STA:~port JMP:~start &loop
    STD:[&port 00] INC* &start
    DUP* LDA DUP JCN:~loop
  POP POP* JMPr

Reading and writing to files

The head port is used to read and write to an open file. We first open a file at the chosen path, creating it if it doesn’t exist, and then we write bytes sequentially to the head port. To read the bytes back, we reset the file address to zero and then read the same number of bytes back from the head port:

%λ: JMSr: ;

*:path JMS:create-file
*:path JMS:open-file

:41 STD:92      ( file is 41            )
:42 STD:92      ( file is 41 42         )
*:4344 STD*:92  ( file is 41 42 43 44   )

*:0000 STD*:9A  ( reset address to zero )

LDD:92          ( stack is 41           )
LDD:92          ( stack is 41 42        )
LDD*:92 HLT     ( stack is 41 42 43 44  )

@path "/new_file.txt"

@create-file  ( path* -- )
  :00 STD:90
  :91 JMS:write-string
  :00 STD:91 JMPr

@open-file @open-folder  ( path* -- )
  :90 JMS:write-string
  :00 STD:90 JMPr

@write-string  ( string* port -- )
  STA:~port JMP:~start &loop
    STD:[&port 00] INC* &start
    DUP* LDA DUP JCN:~loop
  POP POP* JMPr

Listing folder contents

To list the contents of an open folder, find the number of child entries by reading from the length port, and then read the name of each child entry by writing an index to the address port and reading from the child path port:

%λ: JMSr: ;

λ:{"/"} JMS:open-folder
JMS:list-folder-contents HLT

@open-file @open-folder  ( path* -- )
  :90 JMS:write-string
  :00 STD:90 JMPr

@list-folder-contents  ( -- )
  LDD:95 JCN:{ JMPr }
  *:0000 STD*:98
  LDD*:9E *:0000 JMP:~start
  &loop
    DUP* STD*:9A :FF STD:96
    :96 JMS:print-device-string
    :0A STD:86
    INC* &start NQK* JCN:~loop
  POP* JMPr

@print-device-string  ( port -- )
  STA:~port JMP:~start &loop
    STD:86 &start
    LDD:[&port 00] DUP JCN:~loop
  POP JMPr

@write-string  ( string* port -- )
  STA:~port JMP:~start &loop
    STD:[&port 00] INC* &start
    DUP* LDA DUP JCN:~loop
  POP POP* JMPr