From 4cc6393f5bb54ebee7bbe542cd680c14973f9a6d Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Mon, 31 Aug 2026 15:35:11 -0400 Subject: [PATCH] Name a drive in a path "1:/notes", or "1:" on its own for wherever that drive already was. Done in sbfsWalk, which is where every path in the system arrives - eight callers between the shell, the config reader and the filesystem - so it works for anything that takes a path rather than for whichever commands somebody remembered to change. NAMING A DRIVE GOES THERE AND STAYS THERE. Switching for the length of one command and switching back reads better and cannot work: a path resolves to a start block and a length, and those mean nothing without the drive they were read from. A load that resolved on drive 1 and then read its blocks on drive 0 would read the right blocks of the wrong disk. A name beginning with a digit is still a name. The colon is the whole of what tells them apart, and /2things is on the fixture disk to keep it that way. Two bugs, and the second is the interesting one. SUB sets carry on a BORROW, so a character below '0' leaves it set - and the test for "not a digit" branched on clear. Every prefix was ignored. Then the leading-separator test reads the first character through DP0, which sbfsPathDrive could not move because RET puts DP0 back the way it found it. It advanced SbfsPathAt and DP0 still pointed at the digit, so every prefixed path was judged relative and walked from the named drive's working directory. IT ONLY SHOWED WHEN THAT DRIVE WAS STANDING SOMEWHERE OTHER THAN ITS ROOT, because a relative walk from the root is an absolute one - so "cd 1:/2things" worked from a fresh boot and failed after "cd 1:/notes". The test does it in that order for that reason. Copying between two disks is still not one command: each path resolves on its own drive and the drive stays where the last path left it. That wants Copy to change drives between blocks. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/README.md | 24 +++++-- Programs/CosmOS/Source/sbfs.asm | 108 +++++++++++++++++++++++++++++ SplitBit Test Manual.md | 2 +- Tests/expected/cosmosDrivePath.out | 9 +++ Tests/expected/cosmosDrives.out | 3 +- Tests/input/cosmosDrivePath.in | 11 +++ Tests/makedisks.sh | 3 + Tests/manifest | 4 ++ 8 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 Tests/expected/cosmosDrivePath.out create mode 100644 Tests/input/cosmosDrivePath.in diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index 1949520..ebb2e4f 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -820,10 +820,26 @@ than one disk exists. That is the whole reason this was affordable. The version is not among them. It is checked at mount and thrown away, because a version one disk's zero parent already reads as "in the root", which is where all of its files are. -**Paths do not name a drive yet.** `drive 1` then a path is how you reach the other disk, so -copying between two of them is not possible in one command. A prefix like `1:/notes` is the -obvious next thing and it touches the path walker, which is why it is not in the same change -as the record. +**A path may name a drive**, as a digit and a colon on the front: `1:/notes`, or `1:` on its +own for wherever that drive already was. It is handled where every path in the system arrives, +so it works for anything that takes one rather than for whichever commands somebody remembered. + +**Naming a drive goes there and stays there.** Switching for the length of one command and +switching back reads better in a listing and cannot work: what a path resolves to is a start +block and a length, and those mean nothing without the drive they were read from. A `load` +that resolved on drive 1 and then read its blocks on drive 0 would read the right blocks of +the wrong disk. + +**A name that begins with a digit is still a name**, because the colon is the whole of what +tells the two apart. `2things` is a directory; `2:` is a drive. + +A drive the machine cannot read makes the whole path unfindable, and says so as `no such +file` - which it is, since there is nowhere for the rest of it to be. + +**Copying between two disks is still not one command.** Each path resolves on its own drive +and the drive stays where the last path left it, so a copy would read from one and write to +the other with only one of them selected. That wants the copy itself to change drives between +blocks, which is a change to `Copy` rather than to paths. ### Bank Numbers Are One Namespace: diff --git a/Programs/CosmOS/Source/sbfs.asm b/Programs/CosmOS/Source/sbfs.asm index a0d50e6..0f9b5e6 100644 --- a/Programs/CosmOS/Source/sbfs.asm +++ b/Programs/CosmOS/Source/sbfs.asm @@ -414,12 +414,118 @@ sbfsFindRoot: ADD RET +; ---- Is there a drive on the front of this path, and can we go there? ---- +; +; A digit and a colon. Q is zero if the path is usable, whether or not one was there; Q is one +; if a drive was named and it is not one this machine can read, which makes the whole path +; unfindable - because it is. +; +; NAMING A DRIVE GOES THERE AND STAYS THERE. The alternative was to switch for the operation +; and switch back, which reads better in a listing and cannot work: what a path resolves to is +; a start block and a length, and those mean nothing without the drive they were read from. A +; load that resolved on drive 1 and then read on drive 0 would read the right blocks of the +; wrong disk. +sbfsPathDrive: + SETD.1 SbfsPathAt + LDD.0.1 + LDA.0 + INIB 0d48 ; '0' + CCF + SUB + BRC sbfsPathNoDrive ; Borrowed, so it is below '0' and not a digit. + MVQA + INIB 0d10 + CCF + SUB + BNC sbfsPathNoDrive ; Ten or more, so not a digit either. + + ; The character after it has to be a colon, or this is a name that begins with a digit. + ; DP1 is still SbfsPathAt, from the top of this routine. + LDD.0.1 + INCD.0 + LDA.0 + INIB 0d58 ; ':' + CCF + SUB + BNQ sbfsPathNoDrive + + ; It is a drive. Is it one this machine has, with something readable in it? + LDD.0.1 + LDA.0 + INIB 0d48 + CCF + SUB + MVQA + SETD.1 SbfsPathWanted + STA.1 + CALL sbfsDriveBit + MVQA + SETD.1 SbfsMounted + LDB.1 + AND + BRQ sbfsPathBadDrive + + SETD.1 SbfsPathWanted + LDA.1 + CALL sbfsUse + + ; Past the digit and the colon. What follows is an ordinary path, and a bare "1:" is an + ; empty one - which walks to where that drive already was. + SETD.1 SbfsPathAt + LDD.0.1 + INCD.0 + INCD.0 + STD.0.1 + +sbfsPathNoDrive: + RSTA + RSTB + CCF + ADD + RET + +sbfsPathBadDrive: + RSTA + INIB 0d1 + CCF + ADD + RET + ; The walk itself. Q is zero if the whole path was walked, and SbfsAt says where it ended - ; which may be the root, and that is an answer rather than a failure. sbfsWalk: SETD.1 SbfsPathAt STD.0.1 + ; ---- A drive in front of the path ---- + ; + ; Done here because this is where every path in the system arrives - eight callers between + ; the shell, the config reader and this file - so naming a drive works everywhere at once + ; rather than in whichever commands somebody remembered. + CALL sbfsPathDrive + BNQ sbfsWalkNoDrive + + ; ---- And DP0 has to be told ---- + ; + ; sbfsPathDrive moved SbfsPathAt past the digit and the colon, but RET put DP0 back the way + ; it found it - so the test below for a leading separator was reading the DIGIT and calling + ; every prefixed path relative. It only showed when the drive being named was standing + ; somewhere other than its root, because a relative walk from the root is an absolute one. + SETD.1 SbfsPathAt + LDD.0.1 + BRI sbfsWalkPath + +; A drive that this machine cannot read makes the path unfindable, because it is: there is +; nowhere for the rest of it to be. +sbfsWalkNoDrive: + RSTA + INIB 0d1 + CCF + ADD + RET + +sbfsWalkPath: + ; Where it starts. A path beginning with a separator is measured from the root, which is ; zero because a parent is an entry index PLUS ONE and the root is not an entry. ; Anything else is measured from wherever the machine already is. @@ -3381,6 +3487,8 @@ SbfsDriveCount: 0x00 SbfsDriveAt: 0x00 +SbfsPathWanted: + 0x00 SbfsFileStart: 0x00 0x00 diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index e112c50..250b27e 100644 --- a/SplitBit Test Manual.md +++ b/SplitBit Test Manual.md @@ -79,7 +79,7 @@ from `make`, not from here. ### 1. Recorded output `Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares -everything it printed against a file in `Tests/expected`. 180 tests, of which 118 run, 35 +everything it printed against a file in `Tests/expected`. 181 tests, of which 119 run, 35 only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image given at all. diff --git a/Tests/expected/cosmosDrivePath.out b/Tests/expected/cosmosDrivePath.out new file mode 100644 index 0000000..dc1862f --- /dev/null +++ b/Tests/expected/cosmosDrivePath.out @@ -0,0 +1,9 @@ +CosmOS +> /notes> 1 +/notes> > 0 +> /2things> 1 +/2things> > /2things> 1 +/2things> no such file +/2things> halted +Execution halted. +[exit 0] diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index bd0ee99..0f02d1a 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -20,7 +20,8 @@ loop.script 35 17 files > > other.txt 28 notes -1 file, 1 directory +2things +1 file, 2 directories > /notes> > /notes> > /notes> drive: this machine has no such drive /notes> halted Execution halted. diff --git a/Tests/input/cosmosDrivePath.in b/Tests/input/cosmosDrivePath.in new file mode 100644 index 0000000..c4f63db --- /dev/null +++ b/Tests/input/cosmosDrivePath.in @@ -0,0 +1,11 @@ +cd 1:/notes +drive +cd 0:/ +drive +cd 1:/2things +drive +cd / +cd 2things +drive +cd 9:/ +exit diff --git a/Tests/makedisks.sh b/Tests/makedisks.sh index 17036dd..4fca8f5 100755 --- a/Tests/makedisks.sh +++ b/Tests/makedisks.sh @@ -124,6 +124,9 @@ printf 'this is not a program' > notes.txt printf 'this lives on the other disk' > other.txt "$TOOL" put "$DISKS/other.img" other.txt >/dev/null "$TOOL" mkdir "$DISKS/other.img" /notes >/dev/null +# A name that begins with a digit, because a drive prefix is a digit and a colon and the +# colon is the whole of what tells them apart. Without it this would be drive 2. +"$TOOL" mkdir "$DISKS/other.img" /2things >/dev/null # ---- Scripts, including the ones that are meant to go wrong ---- # diff --git a/Tests/manifest b/Tests/manifest index 894512f..4a5c0c8 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -820,6 +820,10 @@ driveSelectTest | testPrograms/driveSelectTest.asm | run | - # and not the other would still look right once. A drive this machine has not got is # refused. cosmosDrives | CosmOS/Source/cosmos.asm | run | cosmosDrives.in | 60000000 | disks/cosmos.img+disks/other.img +# And a drive named in the path rather than by a command. Handled where every path in the +# system arrives, so it works for anything that takes one. A name beginning with a digit is +# still a name: the colon is the whole of what tells the two apart. +cosmosDrivePath | CosmOS/Source/cosmos.asm | run | cosmosDrivePath.in | 60000000 | disks/cosmos.img+disks/other.img printDecimalTest | testPrograms/printDecimalTest.asm | xfail | - | - printDigitTest | testPrograms/printDigitTest.asm | xfail | - | - printHexTest | testPrograms/printHexTest.asm | xfail | - | -