; 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 RSTA 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 INIA 0d2 SWI osExit sourceFailed: SETD.0 SourceError SWI osPrintString INIA 0d1 SWI osExit readFailed: SETD.0 ReadError SWI osPrintString INIA 0d1 SWI osExit startFailed: SETD.0 StartError SWI osPrintString INIA 0d1 SWI osExit writeFailed: SETD.0 WriteError SWI osPrintString INIA 0d1 SWI osExit doneFailed: SETD.0 DoneError SWI osPrintString INIA 0d1 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