Add Type and More, and the file stream they are built on

Two applications that read a file too big for Data Memory: Type prints one,
More pages it. Both sit on fileStream.asm, which wraps osFileInfo and
osFileBlock into open-and-next so an application walks a file's blocks without
repeating the service calls.

The disk fixture is deliberately awkward: readable.txt crosses several blocks
and carries no zero byte to be mistaken for an end marker, and empty.txt says
that zero blocks is a valid file rather than an error.

These three files were written by ChatGPT, as their headers record.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-08-24 17:15:53 -04:00
co-authored by Claude Opus 5
parent 4fd8bf7b3f
commit dbe58db660
10 changed files with 544 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
; Read a text file one screen at a time.
;
; Twenty two lines are shown before a prompt. Space advances another screen, Return one
; line, and q gives the machine back to CosmOS. This is forward-only on purpose: the file
; stream holds one block and never asks the whole document to fit in memory.
;
; Written by ChatGPT for Anachronaut's SplitBit
#Include services.asm
#Program
#Base 0x2000
start:
SETD.0 Name
INIB 0d29
SWI osArgument
SETD.0 Name
LDA.0
BRA noName
CALL fileStreamOpen
BNQ openFailed
CALL fullPage
nextBlock:
CALL fileStreamNext
BNQ readFailed
PSHD.3
POPB
POPA
SETD.2 Remaining
STA.2
INCD.2
STB.2
OR
BRQ finished
SETD.1 FileStreamBlock
SETD.2 Remaining
printLoop:
LDA.1
OUTA 0x00
INIB 0x0A
XOR
BNQ bytePrinted
SETD.3 LinesLeft
LDA.3
DECA
STA.3
BNA bytePrinted
CALL pause
BNQ finished
bytePrinted:
INCD.1
CALL fileStreamTakeRemaining
BRQ nextBlock
BRI printLoop
; Ask for one key without asking for Return. The console is put back immediately,
; including on q and end of redirected input.
pause:
SETD.0 MorePrompt
SWI osPrintString
INIA 0x01
OUTA 0x02
INA 0x00
PSHA ; Keep the key while A is used to restore line mode.
RSTA
OUTA 0x02
POPA
SETD.0 ClearPrompt
SWI osPrintString
INIB 0x71 ; q
XOR
BRQ pauseQuit
INIB 0xFF ; end of redirected input
XOR
BRQ pauseQuit
INIB 0x0A ; Return: one more line.
XOR
BRQ oneLine
INIB 0x20 ; Space: one more screen.
XOR
BNQ pause ; Ignore every other key.
CALL fullPage
RSTA
RSTB
OR
RET
oneLine:
SETD.3 LinesLeft
INIA 0x01
STA.3
RSTA
RSTB
OR
RET
pauseQuit:
RSTA
INIB 0x01
OR
RET
fullPage:
SETD.3 LinesLeft
INIA 0d22
STA.3
RET
noName:
SETD.0 Usage
SWI osPrintString
SWI osExit
openFailed:
SETD.0 OpenError
SWI osPrintString
BRI printError
readFailed:
SETD.0 ReadError
SWI osPrintString
printError:
RSTA
MVQB
SWI osPrintNumber
SETD.0 NewLine
SWI osPrintString
finished:
SWI osExit
#Data
#Base 0x1000
Usage:
"more: give me a file name
"
OpenError:
"more: cannot find the file, error "
ReadError:
"more: cannot read the file, error "
NewLine:
0x0A 0x00
MorePrompt:
"-- more --"
ClearPrompt:
0x0A 0x00
Name:
#Reserve 0d29
Remaining:
0x00 0x00
LinesLeft:
0x00
#Include fileStream.asm
+80
View File
@@ -0,0 +1,80 @@
; Print a text file without asking it to fit in Data Memory.
; fileStream.asm owns finding the file and walking its blocks. Type owns only what makes
; it Type: send each byte to the console until the stream says there are no more.
;
; Written by ChatGPT for Anachronaut's SplitBit
#Include services.asm
#Program
#Base 0x2000
start:
SETD.0 Name
INIB 0d29
SWI osArgument
SETD.0 Name
LDA.0
BRA noName
CALL fileStreamOpen
BNQ openFailed
nextBlock:
CALL fileStreamNext
BNQ readFailed
PSHD.3
POPB
POPA
SETD.2 Remaining
STA.2
INCD.2
STB.2
OR
BRQ finished
SETD.1 FileStreamBlock
SETD.2 Remaining
printLoop:
LDA.1
OUTA 0x00
INCD.1
CALL fileStreamTakeRemaining
BRQ nextBlock
BRI printLoop
noName:
SETD.0 Usage
SWI osPrintString
SWI osExit
openFailed:
SETD.0 OpenError
SWI osPrintString
BRI printError
readFailed:
SETD.0 ReadError
SWI osPrintString
printError:
RSTA
MVQB
SWI osPrintNumber
SETD.0 NewLine
SWI osPrintString
finished:
SWI osExit
#Data
#Base 0x1000
Usage:
"type: give me a file name
"
OpenError:
"type: cannot find the file, error "
ReadError:
"type: cannot read the file, error "
NewLine:
0x0A 0x00
Name:
#Reserve 0d29
Remaining:
0x00 0x00
#Include fileStream.asm
+2
View File
@@ -138,6 +138,8 @@ from every assembly file in it. Several are old programs written for the bare ma
| Break | Stops itself twice with SWI osBreak, so that the registers can be seen changing between one stop and the next. |
| Edit | A line editor. |
| Stream | Reads an 84,000 byte file through a buffer of 256, which is what says a file bigger than Data Memory can be read at all. |
| Type | Prints a named text file a block at a time, including one too large to fit in Data Memory. |
| More | A forward-only pager. Space advances a screen, Return one line, and q stops. |
### The Monitor:
+141
View File
@@ -0,0 +1,141 @@
; Read a named file from beginning to end, one block at a time.
;
; DP0 = filename
; CALL fileStreamOpen Q = 0, or the osFileInfo error
; CALL fileStreamNext Q = 0, or the osFileBlock error
; DP3 = bytes in FileStreamBlock; zero means EOF
;
; This is application-side machinery built on CosmOS services, not a filesystem and not
; yet an OS stream. Open remembers the address of the caller's filename, which must remain
; valid until the one stream is finished.
;
; Written by ChatGPT for Anachronaut's SplitBit
#Program
fileStreamOpen:
SETD.3 FileStreamName
STD.0.3
SWI osFileInfo
BNQ fileStreamReturn
PSHD.3
POPB
POPA
SETD.3 FileStreamBlocks
STA.3
INCD.3
STB.3
SETD.3 FileStreamIndex
RSTA
STA.3
INCD.3
STA.3
fileStreamReturn:
RET
fileStreamNext:
SETD.3 FileStreamBlocks
LDA.3
INCD.3
LDB.3
OR
BRQ fileStreamEnd
SETD.3 FileStreamName
LDD.0.3
SETD.1 FileStreamBlock
SETD.3 FileStreamIndex
LDA.3
INCD.3
LDB.3
SWI osFileBlock
BNQ fileStreamReturn
; DP3 is the service's return value and also the pointer this routine uses for all of
; its bookkeeping. Keep the value before touching the pointer, then restore it at the
; one successful return below.
PSHD.3
POPB
POPA
SETD.3 FileStreamCount
STA.3
INCD.3
STB.3
; Index++.
SETD.3 FileStreamIndex
INCD.3
LDA.3
INCA
STA.3
BNC fileStreamTakeBlock
DECD.3
LDA.3
INCA
STA.3
fileStreamTakeBlock:
; Blocks--.
SETD.3 FileStreamBlocks
INCD.3
LDA.3
BRA fileStreamBlocksBorrow
DECA
STA.3
BRI fileStreamReadReturn
fileStreamBlocksBorrow:
INIA 0xFF
STA.3
DECD.3
LDA.3
DECA
STA.3
fileStreamReadReturn:
SETD.3 FileStreamCount
LDD.3.3
RET
fileStreamEnd:
; There is no reset-pointer instruction. Two zero bytes through the Stack are the
; literal construction of a zero Data Pointer.
RSTA
PSHA
PSHA
POPD.3
RET
; DP2 names a big-endian sixteen-bit byte count. Decrement it, returning Q = 0 when it
; reached zero and nonzero while bytes remain. This is shared because correctly counting
; a full 0x0100-byte block is the least interesting part of both applications to duplicate.
fileStreamTakeRemaining:
INCD.2
LDA.2
BRA fileStreamRemainingBorrow
DECA
STA.2
DECD.2
LDB.2
INCD.2
LDA.2
OR
RET
fileStreamRemainingBorrow:
INIA 0xFF
STA.2
DECD.2
LDA.2
DECA
STA.2
LDB.2
INCD.2
LDA.2
OR
RET
#Data
FileStreamName:
0x00 0x00
FileStreamBlocks:
0x00 0x00
FileStreamIndex:
0x00 0x00
FileStreamCount:
0x00 0x00
FileStreamBlock:
#Reserve 0d256
+89
View File
@@ -0,0 +1,89 @@
CosmOS
> loaded, starting at 2000
> first line
second line
line 00: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 01: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 02: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 03: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 04: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 05: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 06: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 07: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 08: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 09: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 10: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 11: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 12: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 13: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 14: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 15: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 16: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 17: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 18: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 19: ABCDEFGHIJKLMNOPQRSTUVWXYZ
-- more --
finished
> first line
second line
line 00: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 01: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 02: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 03: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 04: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 05: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 06: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 07: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 08: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 09: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 10: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 11: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 12: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 13: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 14: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 15: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 16: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 17: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 18: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 19: ABCDEFGHIJKLMNOPQRSTUVWXYZ
-- more --
line 20: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 21: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 22: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 23: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 24: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 26: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 27: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 28: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 29: ABCDEFGHIJKLMNOPQRSTUVWXYZ
finished
> first line
second line
line 00: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 01: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 02: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 03: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 04: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 05: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 06: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 07: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 08: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 09: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 10: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 11: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 12: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 13: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 14: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 15: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 16: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 17: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 18: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 19: ABCDEFGHIJKLMNOPQRSTUVWXYZ
-- more --
line 20: ABCDEFGHIJKLMNOPQRSTUVWXYZ
-- more --
finished
> halted
Execution halted.
[exit 0]
+43
View File
@@ -0,0 +1,43 @@
CosmOS
> loaded, starting at 2000
> first line
second line
line 00: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 01: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 02: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 03: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 04: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 05: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 06: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 07: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 08: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 09: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 10: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 11: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 12: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 13: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 14: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 15: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 16: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 17: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 18: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 19: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 20: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 21: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 22: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 23: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 24: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 26: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 27: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 28: ABCDEFGHIJKLMNOPQRSTUVWXYZ
line 29: ABCDEFGHIJKLMNOPQRSTUVWXYZ
finished
> finished
> type: cannot find the file, error 2
finished
> type: give me a file name
finished
> halted
Execution halted.
[exit 0]
+6
View File
@@ -0,0 +1,6 @@
load More.sbx
run readable.txt
qrun readable.txt
run readable.txt
qexit
+6
View File
@@ -0,0 +1,6 @@
load Type.sbx
run readable.txt
run empty.txt
run missing.txt
run
exit
+16
View File
@@ -161,6 +161,22 @@ awk 'BEGIN { for (i = 0; i < 50; i++) printf "small %05d\n", i }' > small.txt
"$ROOT/Programs/CosmOS/Apps/Stream.asm" -o "$WORK/Stream.sbx" >/dev/null
"$TOOL" put "$DISKS/stream.img" "$WORK/Stream.sbx" >/dev/null
# A disk for Type. The first file crosses several blocks and deliberately has no zero byte
# for the application to mistake for an end marker. The second proves that zero blocks is
# a valid empty file rather than an error.
"$TOOL" format "$DISKS/type.img" 64 2 >/dev/null
printf 'first line\nsecond line\n' > readable.txt
awk 'BEGIN { for (i = 0; i < 30; i++) printf "line %02d: ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", i }' >> readable.txt
: > empty.txt
"$TOOL" put "$DISKS/type.img" readable.txt >/dev/null
"$TOOL" put "$DISKS/type.img" empty.txt >/dev/null
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
"$ROOT/Programs/CosmOS/Apps/Type.asm" -o "$WORK/Type.sbx" >/dev/null
"$TOOL" put "$DISKS/type.img" "$WORK/Type.sbx" >/dev/null
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
"$ROOT/Programs/CosmOS/Apps/More.asm" -o "$WORK/More.sbx" >/dev/null
"$TOOL" put "$DISKS/type.img" "$WORK/More.sbx" >/dev/null
# A disk for the assembler that runs on the machine. It holds a source file and the two
# programs that check the front end - the reader on its own and the tokenizer on its own -
# because a fault in either of those would otherwise turn up much later as a mysterious
+10
View File
@@ -316,6 +316,14 @@ cosmosServices | CosmOS/Source/cosmos.asm | run | cosmosFil
# notice the file moved - and that one would otherwise pass, since the blocks are still
# there and still hold the same bytes.
cosmosStream | CosmOS/Source/cosmos.asm | run | cosmosStream.in | - | disks/stream.img
# A useful application made out of the streaming primitive: print a named text file without
# requiring it to fit in Data Memory. The fixture crosses block boundaries, includes a full
# 256-byte block, and also checks empty, missing, and absent filename cases.
cosmosType | CosmOS/Source/cosmos.asm | run | cosmosType.in | - | disks/type.img
# The same stream with interaction layered on it. Three runs exercise q, a whole screen
# with Space, and one line with Return. The input is intentionally packed so that the one
# byte the pager consumes leaves the next shell command immediately behind it.
cosmosMore | CosmOS/Source/cosmos.asm | run | cosmosMore.in | - | disks/type.img
# The assembler's front end, checked in two pieces before anything is built on it.
#
# cosmosSource reads a source file and prints it back. The file crosses a block boundary,
@@ -340,6 +348,8 @@ app-Break | CosmOS/Apps/Break.asm | assemble | -
app-Edit | CosmOS/Apps/Edit.asm | assemble | - | -
app-Files | CosmOS/Apps/Files.asm | assemble | - | -
app-Stream | CosmOS/Apps/Stream.asm | assemble | - | -
app-Type | CosmOS/Apps/Type.asm | assemble | - | -
app-More | CosmOS/Apps/More.asm | assemble | - | -
# The assembler that runs on the machine, and its parts. Checked on their own so that a
# failure reads as "it does not assemble" rather than as a broken disk image.
asm-Asm | CosmOS/Assembler/Asm.asm | assemble | - | -