On Unix and Windows systems RETRO provides a set of words for working with files. As a pragmatic choice these are mostly modeled after the file functions in libc.

The file words are in the file: namespace.



You can open a file for various operations. The functionality allowed depends on the file access mode. Valid modes in RETRO are:

file:A    Open for appending; file pointer set to end of file file:R    Open for reading; file pointer set to start of file file:R+   Open for reading and writing file:W    Open for writing



To open a file, pass the file name and a file mode to file:open.

'/etc/motd file:R file:open

On a successful open this will return a file handle greater than zero.

Additionally, RETRO provides a few other forms for opening files.

To open a file for reading:

'/etc/motd file:open-for-reading

This will return the size of the file (as NOS) and the file handle (as TOS).

To open a file for writing:

'/tmp/test file:open-for-writing

This returns the file handle.

To open a file for append operations:

'/tmp/test file:open-for-append

As with file:open-for-reading, this returns both the size of the file and the file handle.



To close a file, pass the file handle to file:close.

'/etc/motd file:A file:open file:close



To read a byte from an open file, pass the file handle to the file:read word.

@FID file:read n:put

To read a line from a file, pass the file handle to the word file:read-line.

@FID file:read-line s:put

The line is read into a temporary string buffer. Move the text to a safe place if you aren't using it quickly or if the length of the line is bigger than the size of a temporary string.



To write a byte to a file, pass it and the file handle to file:write.

$h @FID file:write $e @FID file:write $l @FID file:write $l @FID file:write $o @FID file:write

Though cells are 32 or 64 bits in size, only the byte value will be written to the file.



You can delete a file by passing the file name to file:delete.

/tmp/test file:delete



Use file:exists? to detect the existance of a file. Pass it a file name and it will return TRUE if existing or FALSE if it does not.

'/etc/motd file:exists?

This will also return TRUE if the filename is a directory.



Use file:flush to flush the system caches for a file. Pass a file handle to this.

@FID file:flush



You can use file:seek to move the internal file pointer for a given file. Pass this the new location and a file.

#100 @FID file:seek

The location for the file pointer is a fixed offset from the start of the file, not a relative offset.



To find the current value of the file pointer within a file just pass the file handle to file:tell.

@FID file:tell

This returns a number that is the number of bytes into the file that the file pointer is currently at.



Use file:size to return the size of a file. Pass this a file handle and it will return the size of a file, or 0 if empty. If the file is a directory, it returns -1.

@FID file:size



If you want to read an entire file into memory you can use file:slurp. This takes the starting address of a memory region and the name of the file.

here '/etc/motd file:slurp

Take care that the memory buffer is large enough for the file being read or you will run into problems.



If you have a string that you want to write to a file, replacing any existing contents, you can use file:spew. This takes the string to write and a file name.

'hello_world '/tmp/test.txt file:spew



You can easily iterate over each line in a file using the word file:for-each-line. This will take a file name and a quote, read each line into a temporary string, then pass this string to the quote.

'/etc/motd [ s:put nl ] file:for-each-line