Add Copy and Compare, which stream in both directions at once
Copy joins the read and write streaming services: source and destination are both larger than Data Memory while the program owns one block. Compare reads two files through separate blocks and ignores the bytes past a short final block, which belong to neither file. Between them they exercise empty, exact-block, part-block and 84,000 byte files, and the host extracts the copy afterwards so that two native programs agreeing with each other is not the only oracle. Written by ChatGPT, as their headers record, along with the agree.sh section and the manifest entry that drive them. THIS SHOULD HAVE COME FIRST. The commit before it staged whole files rather than the hunks it meant, so its manifest already names these two programs while their source was still untracked - that commit will not build on its own. Left in place rather than rewritten, since the pair is right and only their order is wrong. NOTES.md is their review of the streaming work. The first item in it is fixed by the commit before this one; the rest are still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
a7d3e09d94
commit
54f5cfe8a4
@@ -0,0 +1,277 @@
|
||||
; Compare two files without asking either one to fit in Data Memory.
|
||||
;
|
||||
; Each occupied block is read into its own 256-byte buffer. The byte count returned for
|
||||
; the block is compared before its contents, and only those bytes are examined: bytes
|
||||
; after the end of a short final block belong to neither file and are allowed to differ.
|
||||
;
|
||||
; Written by ChatGPT for Anachronaut's SplitBit
|
||||
|
||||
#Include services.asm
|
||||
|
||||
#Program
|
||||
#Base 0x4000
|
||||
|
||||
start:
|
||||
SETD.0 Arguments
|
||||
INIB 0xFF
|
||||
SWI osArgument
|
||||
SETD.0 Arguments
|
||||
LDA.0
|
||||
BRA usage
|
||||
CALL textSplit
|
||||
SETD.0 TextRest
|
||||
LDD.0.0
|
||||
LDA.0
|
||||
BRA usage
|
||||
|
||||
SETD.0 Arguments
|
||||
SWI osFileInfo
|
||||
BNQ firstFailed
|
||||
SETD.0 FirstBlocks
|
||||
STD.3.0
|
||||
|
||||
SETD.0 TextRest
|
||||
LDD.0.0
|
||||
SWI osFileInfo
|
||||
BNQ secondFailed
|
||||
SETD.0 SecondBlocks
|
||||
STD.3.0
|
||||
|
||||
; A different number of occupied blocks is immediately a different file.
|
||||
SETD.0 FirstBlocks
|
||||
LDA.0
|
||||
SETD.1 SecondBlocks
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
BNQ different
|
||||
INCD.0
|
||||
INCD.1
|
||||
LDA.0
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
BNQ different
|
||||
|
||||
SETD.0 FirstBlocks
|
||||
SETD.1 RemainingBlocks
|
||||
CALL copyWord
|
||||
RSTA
|
||||
SETD.0 Index
|
||||
STA.0
|
||||
INCD.0
|
||||
STA.0
|
||||
|
||||
nextBlock:
|
||||
SETD.0 RemainingBlocks
|
||||
LDA.0
|
||||
INCD.0
|
||||
LDB.0
|
||||
OR
|
||||
BRQ alike
|
||||
|
||||
SETD.0 Arguments
|
||||
SETD.1 FirstBlock
|
||||
CALL readAtIndex
|
||||
BNQ firstReadFailed
|
||||
SETD.0 FirstCount
|
||||
STD.3.0
|
||||
|
||||
SETD.0 TextRest
|
||||
LDD.0.0
|
||||
SETD.1 SecondBlock
|
||||
CALL readAtIndex
|
||||
BNQ secondReadFailed
|
||||
SETD.0 SecondCount
|
||||
STD.3.0
|
||||
|
||||
; Equal occupied-block counts do not imply equal tails, so compare the valid byte count
|
||||
; returned for this block as well.
|
||||
SETD.0 FirstCount
|
||||
LDA.0
|
||||
SETD.1 SecondCount
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
BNQ different
|
||||
INCD.0
|
||||
INCD.1
|
||||
LDA.0
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
BNQ different
|
||||
|
||||
SETD.0 FirstCount
|
||||
SETD.1 BytesLeft
|
||||
CALL copyWord
|
||||
SETD.0 FirstBlock
|
||||
SETD.1 SecondBlock
|
||||
|
||||
compareByte:
|
||||
SETD.2 BytesLeft
|
||||
LDA.2
|
||||
INCD.2
|
||||
LDB.2
|
||||
OR
|
||||
BRQ blockSame
|
||||
LDA.0
|
||||
LDB.1
|
||||
CCF
|
||||
SUB
|
||||
BNQ different
|
||||
INCD.0
|
||||
INCD.1
|
||||
SETD.2 BytesLeft
|
||||
CALL takeByte
|
||||
BRI compareByte
|
||||
|
||||
blockSame:
|
||||
CALL stepIndex
|
||||
CALL takeBlock
|
||||
BRI nextBlock
|
||||
|
||||
; DP0 is the path and DP1 the destination buffer. Q and DP3 are the service answers.
|
||||
readAtIndex:
|
||||
SETD.2 Index
|
||||
LDA.2
|
||||
INCD.2
|
||||
LDB.2
|
||||
SWI osFileBlock
|
||||
RET
|
||||
|
||||
; DP0 names the source word and DP1 the destination word.
|
||||
copyWord:
|
||||
LDA.0
|
||||
STA.1
|
||||
INCD.0
|
||||
INCD.1
|
||||
LDA.0
|
||||
STA.1
|
||||
RET
|
||||
|
||||
stepIndex:
|
||||
SETD.0 Index
|
||||
INCD.0
|
||||
LDA.0
|
||||
INCA
|
||||
STA.0
|
||||
BNC stepDone
|
||||
DECD.0
|
||||
LDA.0
|
||||
INCA
|
||||
STA.0
|
||||
stepDone:
|
||||
RET
|
||||
|
||||
takeBlock:
|
||||
SETD.0 RemainingBlocks
|
||||
INCD.0
|
||||
LDA.0
|
||||
BRA blockBorrow
|
||||
DECA
|
||||
STA.0
|
||||
RET
|
||||
blockBorrow:
|
||||
INIA 0xFF
|
||||
STA.0
|
||||
DECD.0
|
||||
LDA.0
|
||||
DECA
|
||||
STA.0
|
||||
RET
|
||||
|
||||
; Decrement the big-endian sixteen-bit BytesLeft. A full block arrives as 0x0100, so an
|
||||
; eight-bit counter would compare none of it and call many different files equal.
|
||||
takeByte:
|
||||
INCD.2
|
||||
LDA.2
|
||||
BRA byteBorrow
|
||||
DECA
|
||||
STA.2
|
||||
RET
|
||||
byteBorrow:
|
||||
INIA 0xFF
|
||||
STA.2
|
||||
DECD.2
|
||||
LDA.2
|
||||
DECA
|
||||
STA.2
|
||||
RET
|
||||
|
||||
alike:
|
||||
SETD.0 SameText
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
different:
|
||||
SETD.0 DifferentText
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
usage:
|
||||
SETD.0 Usage
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
firstFailed:
|
||||
SETD.0 FirstError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
secondFailed:
|
||||
SETD.0 SecondError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
firstReadFailed:
|
||||
SETD.0 FirstReadError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
secondReadFailed:
|
||||
SETD.0 SecondReadError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
|
||||
#Data
|
||||
#Base 0x2000
|
||||
|
||||
Arguments:
|
||||
#Reserve 0d256
|
||||
FirstBlocks:
|
||||
0x00 0x00
|
||||
SecondBlocks:
|
||||
0x00 0x00
|
||||
RemainingBlocks:
|
||||
0x00 0x00
|
||||
Index:
|
||||
0x00 0x00
|
||||
FirstCount:
|
||||
0x00 0x00
|
||||
SecondCount:
|
||||
0x00 0x00
|
||||
BytesLeft:
|
||||
0x00 0x00
|
||||
FirstBlock:
|
||||
#Reserve 0d256
|
||||
SecondBlock:
|
||||
#Reserve 0d256
|
||||
|
||||
Usage:
|
||||
"compare: give me two files
|
||||
"
|
||||
FirstError:
|
||||
"compare: cannot find the first file
|
||||
"
|
||||
SecondError:
|
||||
"compare: cannot find the second file
|
||||
"
|
||||
FirstReadError:
|
||||
"compare: cannot read the first file
|
||||
"
|
||||
SecondReadError:
|
||||
"compare: cannot read the second file
|
||||
"
|
||||
SameText:
|
||||
"the same
|
||||
"
|
||||
DifferentText:
|
||||
"different
|
||||
"
|
||||
|
||||
#Include text.asm
|
||||
@@ -0,0 +1,269 @@
|
||||
; Copy one file to another without asking either file to fit in Data Memory.
|
||||
;
|
||||
; The two paths are the two words in the argument. Filesystem names can contain spaces,
|
||||
; but the CosmOS command line has no quoting yet, so this deliberately has the same rule
|
||||
; as the shell: a space separates things.
|
||||
;
|
||||
; osFileInfo reports how many disk blocks the source occupies, while osFileStart wants the
|
||||
; shape stored in an SBFS entry: whole blocks and a possible tail. Reading the last block
|
||||
; first recovers that distinction. The ordinary copy then walks forward one block at a
|
||||
; time, through one 256-byte buffer.
|
||||
;
|
||||
; Written by ChatGPT for Anachronaut's SplitBit
|
||||
|
||||
#Include services.asm
|
||||
|
||||
#Program
|
||||
#Base 0x4000
|
||||
|
||||
start:
|
||||
SETD.0 Arguments
|
||||
INIB 0xFF
|
||||
SWI osArgument
|
||||
SETD.0 Arguments
|
||||
LDA.0
|
||||
BRA usage
|
||||
CALL textSplit
|
||||
SETD.0 TextRest
|
||||
LDD.0.0
|
||||
LDA.0
|
||||
BRA usage
|
||||
|
||||
; How many occupied blocks the source has. Keep it as both the loop bound and the
|
||||
; distinction between an empty file and one whose last block must be inspected.
|
||||
SETD.0 Arguments
|
||||
SWI osFileInfo
|
||||
BNQ sourceFailed
|
||||
SETD.0 SourceBlocks
|
||||
STD.3.0
|
||||
PSHD.3
|
||||
POPB
|
||||
POPA
|
||||
OR
|
||||
BRQ emptySource
|
||||
|
||||
; Read the final occupied block. DP3 says how many bytes of it belong to the file:
|
||||
; 0x0100 for a whole block, or 0x0001 through 0x00FF for a tail.
|
||||
SETD.0 SourceBlocks
|
||||
LDD.3.0
|
||||
DECD.3
|
||||
SETD.0 Index
|
||||
STD.3.0
|
||||
SETD.0 Arguments
|
||||
SETD.1 Block
|
||||
SETD.2 Index
|
||||
LDA.2
|
||||
INCD.2
|
||||
LDB.2
|
||||
SWI osFileBlock
|
||||
BNQ readFailed
|
||||
SETD.0 LastCount
|
||||
STD.3.0
|
||||
|
||||
; A full final block means every occupied block is whole. A short final block means
|
||||
; there is one fewer whole block and its low-byte count is the tail.
|
||||
SETD.0 LastCount
|
||||
LDA.0
|
||||
BNA wholeEnding
|
||||
SETD.0 Index
|
||||
SETD.1 OutputWhole
|
||||
CALL copyWord
|
||||
SETD.0 LastCount
|
||||
INCD.0
|
||||
LDA.0
|
||||
SETD.1 OutputTail
|
||||
STA.1
|
||||
BRI sizeKnown
|
||||
|
||||
wholeEnding:
|
||||
SETD.0 SourceBlocks
|
||||
SETD.1 OutputWhole
|
||||
CALL copyWord
|
||||
RSTA
|
||||
SETD.0 OutputTail
|
||||
STA.0
|
||||
|
||||
sizeKnown:
|
||||
BRI startOutput
|
||||
|
||||
emptySource:
|
||||
RSTA
|
||||
SETD.0 OutputWhole
|
||||
STA.0
|
||||
INCD.0
|
||||
STA.0
|
||||
SETD.0 OutputTail
|
||||
STA.0
|
||||
|
||||
startOutput:
|
||||
SETD.0 TextRest
|
||||
LDD.0.0
|
||||
SETD.2 OutputWhole
|
||||
LDD.3.2
|
||||
SETD.2 OutputTail
|
||||
LDA.2
|
||||
SWI osFileStart
|
||||
BNQ startFailed
|
||||
|
||||
; Empty files have no blocks to transfer, but still need committing so that an existing
|
||||
; destination becomes an empty file.
|
||||
SETD.0 SourceBlocks
|
||||
SETD.1 RemainingBlocks
|
||||
CALL copyWord
|
||||
RSTA
|
||||
SETD.0 Index
|
||||
STA.0
|
||||
INCD.0
|
||||
STA.0
|
||||
|
||||
copyNext:
|
||||
SETD.0 RemainingBlocks
|
||||
LDA.0
|
||||
INCD.0
|
||||
LDB.0
|
||||
OR
|
||||
BRQ copyDone
|
||||
|
||||
SETD.0 Arguments
|
||||
SETD.1 Block
|
||||
SETD.2 Index
|
||||
LDA.2
|
||||
INCD.2
|
||||
LDB.2
|
||||
SWI osFileBlock
|
||||
BNQ readFailed
|
||||
|
||||
SETD.1 Block
|
||||
SETD.2 Index
|
||||
LDA.2
|
||||
INCD.2
|
||||
LDB.2
|
||||
SWI osFileWrite
|
||||
BNQ writeFailed
|
||||
|
||||
CALL stepIndex
|
||||
CALL takeBlock
|
||||
BRI copyNext
|
||||
|
||||
copyDone:
|
||||
SETD.2 OutputWhole
|
||||
LDD.3.2
|
||||
SETD.2 OutputTail
|
||||
LDA.2
|
||||
SWI osFileDone
|
||||
BNQ doneFailed
|
||||
SETD.0 Copied
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
|
||||
; DP0 names the source word and DP1 the destination word.
|
||||
copyWord:
|
||||
LDA.0
|
||||
STA.1
|
||||
INCD.0
|
||||
INCD.1
|
||||
LDA.0
|
||||
STA.1
|
||||
RET
|
||||
|
||||
; Increment the big-endian sixteen-bit Index.
|
||||
stepIndex:
|
||||
SETD.0 Index
|
||||
INCD.0
|
||||
LDA.0
|
||||
INCA
|
||||
STA.0
|
||||
BNC stepDone
|
||||
DECD.0
|
||||
LDA.0
|
||||
INCA
|
||||
STA.0
|
||||
stepDone:
|
||||
RET
|
||||
|
||||
; Decrement the big-endian sixteen-bit RemainingBlocks.
|
||||
takeBlock:
|
||||
SETD.0 RemainingBlocks
|
||||
INCD.0
|
||||
LDA.0
|
||||
BRA takeBorrow
|
||||
DECA
|
||||
STA.0
|
||||
RET
|
||||
takeBorrow:
|
||||
INIA 0xFF
|
||||
STA.0
|
||||
DECD.0
|
||||
LDA.0
|
||||
DECA
|
||||
STA.0
|
||||
RET
|
||||
|
||||
usage:
|
||||
SETD.0 Usage
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
sourceFailed:
|
||||
SETD.0 SourceError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
readFailed:
|
||||
SETD.0 ReadError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
startFailed:
|
||||
SETD.0 StartError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
writeFailed:
|
||||
SETD.0 WriteError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
doneFailed:
|
||||
SETD.0 DoneError
|
||||
SWI osPrintString
|
||||
SWI osExit
|
||||
|
||||
#Data
|
||||
#Base 0x2000
|
||||
|
||||
Arguments:
|
||||
#Reserve 0d256
|
||||
SourceBlocks:
|
||||
0x00 0x00
|
||||
RemainingBlocks:
|
||||
0x00 0x00
|
||||
Index:
|
||||
0x00 0x00
|
||||
LastCount:
|
||||
0x00 0x00
|
||||
OutputWhole:
|
||||
0x00 0x00
|
||||
OutputTail:
|
||||
0x00
|
||||
Block:
|
||||
#Reserve 0d256
|
||||
|
||||
Usage:
|
||||
"copy: give me a source and destination
|
||||
"
|
||||
SourceError:
|
||||
"copy: cannot find the source
|
||||
"
|
||||
ReadError:
|
||||
"copy: cannot read the source
|
||||
"
|
||||
StartError:
|
||||
"copy: cannot create the destination
|
||||
"
|
||||
WriteError:
|
||||
"copy: cannot write the destination
|
||||
"
|
||||
DoneError:
|
||||
"copy: cannot finish the destination
|
||||
"
|
||||
Copied:
|
||||
"copied
|
||||
"
|
||||
|
||||
#Include text.asm
|
||||
Reference in New Issue
Block a user