this should be a robust fix for the double-termination issue when compiling Force-Push: yes Change-Id: Ieaacdc232ea7e3036916d81139fc5c5a41087c64
161 lines
5.1 KiB
Text
161 lines
5.1 KiB
Text
~ ~~~~~~~~~~~~~~~~~~~~~~~
|
|
~ ~~ File manipulation ~~
|
|
~ ~~~~~~~~~~~~~~~~~~~~~~~
|
|
~
|
|
~ This file has high-level features for working with files and the
|
|
~ filesystem. There's a tension as to what belongs here vs. what belongs in
|
|
~ input.e or output.e, and it's likely there will be some refactoring as the
|
|
~ boundaries become clear.
|
|
|
|
|
|
~ (output point, filename -- output point)
|
|
: pack-file-contents
|
|
dup 0 0 sys-open
|
|
~ (output point, filename, open result code or file descriptor)
|
|
dup 0 > {
|
|
." Couldn't open " swap emitstring space
|
|
." because " space . ." ." newline
|
|
2 ndrop exit
|
|
} if
|
|
|
|
~ (output point, filename, file descriptor)
|
|
{
|
|
dup 3 pick 1024 sys-read
|
|
~ (output point, filename, file descriptor, read result code or length)
|
|
|
|
dup 0 > {
|
|
over sys-close drop
|
|
~ Ignore a failed close.
|
|
|
|
." Error while reading from " 3roll emitstring
|
|
." because " space . ." ." newline
|
|
drop exit
|
|
} if
|
|
|
|
dup 0 = {
|
|
over sys-close drop
|
|
~ Ignore a failed close.
|
|
|
|
3 ndrop exit
|
|
} if
|
|
|
|
4 roll + 3unroll
|
|
} forever ;
|
|
|
|
|
|
~ TODO probably make this more similar to pack-file-contents
|
|
~ (delimiter pointer, buffer size -- buffer address)
|
|
: read-to-buffer
|
|
dup allocate dup dup
|
|
~ (buffer size, buffer address, word start, output point)
|
|
{ key
|
|
~ Exit if it's a zero byte.
|
|
dup not {
|
|
~ Make sure to pack the zero to serve as a null terminator.
|
|
pack8
|
|
drop drop swap drop swap drop exit } if
|
|
|
|
~ If it's a space character, we need to check if we just consumed the
|
|
~ magic word, and do some handling to reset the word tracking.
|
|
dup is-space
|
|
{ ~ (buffer size, buffer address, word start, output point, key)
|
|
~ Tuck the key out of the way until we've done some stuff.
|
|
3unroll
|
|
|
|
~ Add a null terminator so we can use stringcmp
|
|
dup 0 swap 8!
|
|
|
|
~ Check for the magic word.
|
|
over 6 pick stringcmp 0 =
|
|
{ ~ It's magic, so exit.
|
|
~ Make sure to pack a zero to serve as a null terminator.
|
|
0 pack8
|
|
drop drop drop swap drop swap drop exit }
|
|
{ ~ It's not magic, so reset the word start. Of course whitespace is
|
|
~ not a word but this will help us keep track of things.
|
|
3roll pack8
|
|
swap drop dup } if-else }
|
|
{ ~ (buffer size, buffer address, word start, output point, key)
|
|
~ Tuck the key out of the way again.
|
|
3unroll
|
|
~ Check if the word just started and the previous character is space.
|
|
2dup = dup { drop dup @ is-space } if
|
|
{ ~ If so, this is the actual first character of the word.
|
|
drop swap pack8 dup }
|
|
{ ~ If not, leave the word start alone.
|
|
3roll pack8 } if-else } if-else } forever ;
|
|
|
|
|
|
~ In logical terms, this modifies an input buffer metadata structure
|
|
~ in-place to push a new, zeroed one into the start of the linked list formed
|
|
~ through the next-source field.
|
|
~
|
|
~ In physical terms, it works by allocating a new structure, copying the
|
|
~ fields of the existing one into it, and zeroing the existing one. That's
|
|
~ necessary because otherwise we'd need a mutable handle (a pointer to a
|
|
~ pointer) to update the start of the list, and there's no way to do that with
|
|
~ the main-input-buffer variable working the way it presently does.
|
|
~
|
|
~ (input buffer metadata pointer --)
|
|
: push-input-buffer
|
|
allocate-input-buffer-metadata
|
|
~ (original metadata pointer, new metadata pointer)
|
|
2dup 7 8 * memcopy
|
|
~ (original metadata pointer, new metadata pointer)
|
|
swap dup zero-input-buffer-metadata
|
|
input-buffer-next-source ! ;
|
|
|
|
|
|
~ This does the inverse of push-input-buffer. In the event that the
|
|
~ next-source field is null, it zeroes the buffer.
|
|
~
|
|
~ Note, however, that it doesn't deallocate the memory, because that's not
|
|
~ how memory allocation on the log works. If necessary, it can be deallocated
|
|
~ with "forget", though as usual that requires careful planning.
|
|
~
|
|
~ (input buffer metadata pointer --)
|
|
: pop-input-buffer
|
|
dup input-buffer-next-source @
|
|
~ (original metadata pointer, next source metadata pointer)
|
|
dup { swap 7 8 * memcopy }
|
|
{ drop zero-input-buffer-metadata } if-else ;
|
|
|
|
|
|
: default-buffer-size 1024 ;
|
|
|
|
~ (input buffer metadata pointer, file descriptor --)
|
|
: attach-input-buffer-to-file-descriptor
|
|
over buffer-file-descriptor !
|
|
~ (metadata pointer)
|
|
default-buffer-size allocate dup 2 pick buffer-physical-start !
|
|
~ (metadata pointer, buffer pointer)
|
|
over buffer-logical-start !
|
|
~ (metadata pointer)
|
|
default-buffer-size over buffer-physical-length !
|
|
0 over buffer-logical-length !
|
|
' refill-input-buffer-from-stream entry-to-execution-token
|
|
swap input-buffer-refill ! ;
|
|
|
|
|
|
~ Zero indicates success, nonzero indicates failure.
|
|
~
|
|
~ (filename -- *, success)
|
|
: include
|
|
dup 0 0 sys-open
|
|
dup 0 > {
|
|
." Couldn't open " swap emitstring space
|
|
." because " space . ." ." newline
|
|
drop 1 exit
|
|
} if
|
|
~ (file descriptor)
|
|
|
|
main-input-buffer dup push-input-buffer
|
|
swap attach-input-buffer-to-file-descriptor
|
|
|
|
{ peek -1 != } { interpret } while
|
|
|
|
main-input-buffer buffer-file-descriptor @ sys-close drop
|
|
~ Ignore a failed close.
|
|
|
|
main-input-buffer pop-input-buffer 0 ;
|
|
|