D3: the machine knows where it is
cd moves it, dir lists the directory it is in, and the prompt says which one - but only when that is not the root, so a machine nobody has moved about on looks exactly as it always did and every recorded test that never says "cd" keeps its recorded prompt. A path beginning with a separator is measured from the root and anything else from where the machine is, so a bare name means a file in the current directory. NO PROGRAM HAD TO BE TOLD: the working directory lives in sbfs.asm beside the thing that resolves paths, because it is what a relative path MEANS. Keeping it in the shell would have meant either handing it down on every call or pasting it onto the front of every name, and the second of those is how a name that is already absolute gets ruined. Nothing stores the path. The working directory is an entry index and two bytes, and the text on the prompt is built each time by walking the chain of parents upward, writing names from the end of a buffer towards the front - which is the order they arrive in, and saves reversing them afterwards. sbfsFind splits into a walk and a check. "cd /" and "cd .." both end at the root quite legitimately, and had no way to say so through a routine whose only word for the root was "missing". Typing a program's name now tries two places in order: where you are, then /Apps. The first makes a program you are working on the one that runs; the second lets Snake work from anywhere. A word already beginning with a separator has said where to look, so only that place is tried. osChangeDir exists so that "a program may move about, and the shell puts the working directory back" is a thing that can happen rather than a promise about nothing. Both halves of that were unfalsifiable without it: with no way for a program to move, removing the restore changed no test. Wander is the program that moves - it goes where it is told and reads a file there by a bare name - and with it on the disk, removing the restore fails. The remembered file is dropped whenever what a relative path means changes: a cd, a program calling osChangeDir, a program exiting. Removing all of them fails the test and removing any one of them does not, because today every path into that cache belongs to a program that exits. It is kept in all three because the cost is a call and the failure is a file's blocks being handed out under another file's name. The cwd fixture holds two files called notes.txt saying different things, and a Say.sbx in /A that is really hello. Two copies of one program, or two copies of one file, would have passed with the whole of this deleted. 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
588e02aff5
commit
36ce9f6ccf
@@ -104,35 +104,95 @@ sbfsGeometry:
|
||||
|
||||
; ---- Finding something by path ----
|
||||
;
|
||||
; DP0 points at a path ending in a zero byte: names with '/' between them, walked from the
|
||||
; root. Q is zero if it was found, and then SbfsFileStart, SbfsFileBlocks and SbfsFileTail
|
||||
; DP0 points at a path ending in a zero byte: names with '/' between them. A path that
|
||||
; begins with a separator is walked from the root, and anything else from SbfsCwd, which
|
||||
; is where the machine currently is.
|
||||
;
|
||||
; Q is zero if it was found, and then SbfsFileStart, SbfsFileBlocks and SbfsFileTail
|
||||
; describe it, SbfsFoundFlags says what kind of thing it is, and DP3 is left on the entry
|
||||
; with SbfsBlock on the directory block it came out of - which is what deleting and
|
||||
; renaming need in order to change it and put it back.
|
||||
;
|
||||
; A BARE NAME IS A PATH OF ONE NAME, so everything written before there were directories
|
||||
; still works and still costs one walk of the directory.
|
||||
; still works and still costs one walk of the directory. It now means a name in the
|
||||
; working directory rather than a name in the root, which is the whole of what a working
|
||||
; directory is, and no caller had to be told.
|
||||
;
|
||||
; Each name is looked for among the entries whose parent is where the walk has got to.
|
||||
; There is no list of children anywhere: being a child is a fact written in the child, so
|
||||
; finding them means looking at all of them. That is the same walk the flat version did
|
||||
; with one more thing compared, which is why a flat disk costs what it always did - and on
|
||||
; a version one disk every entry says "the root", so the comparison is free and true.
|
||||
;
|
||||
; sbfsFind is sbfsWalk with one thing added: the root is not a file. The two are separate
|
||||
; because moving about wants the other answer - "cd /" and "cd .." both end at the root
|
||||
; quite legitimately, and would have no way to say so through a routine that calls it a
|
||||
; failure.
|
||||
|
||||
sbfsFind:
|
||||
CALL sbfsWalk
|
||||
BNQ sbfsFindNoWalk
|
||||
|
||||
; Did the walk get anywhere at all? The root is a place, but it is not a file.
|
||||
SETD.0 SbfsAt
|
||||
LDA.0
|
||||
INCD.0
|
||||
LDB.0
|
||||
OR
|
||||
BRQ sbfsFindRoot
|
||||
RSTA
|
||||
RSTB
|
||||
CCF
|
||||
ADD ; Q is zero: found.
|
||||
sbfsFindNoWalk:
|
||||
RET
|
||||
|
||||
sbfsFindRoot:
|
||||
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
|
||||
|
||||
; The walk starts at the root, which is zero: a parent is an entry index PLUS ONE, and
|
||||
; the root is not an entry.
|
||||
; 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.
|
||||
LDA.0
|
||||
INIB 0x2F
|
||||
CCF
|
||||
SUB
|
||||
BRQ sbfsWalkFromRoot
|
||||
|
||||
SETD.0 SbfsCwd
|
||||
SETD.1 SbfsAt
|
||||
CALL sbfsCopyWord
|
||||
|
||||
; Where the machine is, is a directory - it could not have been got to otherwise - but
|
||||
; nothing here has read its entry, so what describes it is whatever the last find left
|
||||
; behind. Say the one thing about it that the walk needs, and mark the rest as not to be
|
||||
; believed, exactly the way going up does.
|
||||
INIA 0x02
|
||||
SETD.0 SbfsFoundFlags
|
||||
STA.0
|
||||
RSTA
|
||||
SETD.0 SbfsFieldsValid
|
||||
STA.0
|
||||
BRI sbfsFindName
|
||||
|
||||
sbfsWalkFromRoot:
|
||||
SETD.0 SbfsAt
|
||||
RSTA
|
||||
STA.0
|
||||
INCD.0
|
||||
STA.0
|
||||
|
||||
; Nothing described yet. An empty path comes back as missing, which is right: the root
|
||||
; is not a file.
|
||||
; Nothing described yet. An empty path comes back as the root, which is right.
|
||||
RSTA
|
||||
SETD.0 SbfsFieldsValid
|
||||
STA.0
|
||||
@@ -224,13 +284,13 @@ sbfsFindUp:
|
||||
BRI sbfsFindName
|
||||
|
||||
sbfsFindEnd:
|
||||
; Did the walk get anywhere at all? The root is not a file.
|
||||
; Ending at the root is a perfectly good answer here, and there is nothing to describe.
|
||||
SETD.0 SbfsAt
|
||||
LDA.0
|
||||
INCD.0
|
||||
LDB.0
|
||||
OR
|
||||
BRQ sbfsFindMissing
|
||||
BRQ sbfsFindGood
|
||||
|
||||
SETD.0 SbfsFieldsValid
|
||||
LDA.0
|
||||
@@ -442,6 +502,21 @@ sbfsScanFound:
|
||||
ADD ; Q is zero: found.
|
||||
RET
|
||||
|
||||
; DP2 is on an entry. Q is zero if it lives in the directory the machine is in. The same
|
||||
; comparison sbfsMatchParent makes, against the other of the two places a walk can be.
|
||||
sbfsWalkHere:
|
||||
PSHD.2
|
||||
POPD.0
|
||||
DPUP.0 0d28
|
||||
SETD.2 SbfsCwd
|
||||
CALL sbfsSameByte
|
||||
BNQ sbfsWalkHereDone
|
||||
INCD.0
|
||||
INCD.2
|
||||
CALL sbfsSameByte
|
||||
sbfsWalkHereDone:
|
||||
RET
|
||||
|
||||
; DP2 is on an entry. Q is zero if it lives in the directory the walk is looking in.
|
||||
;
|
||||
; On a version one disk these two bytes are zero in every entry, and the walk starts at
|
||||
@@ -534,6 +609,30 @@ sbfsAtFound:
|
||||
PSHD.2
|
||||
POPD.3
|
||||
CALL sbfsTakeEntry
|
||||
|
||||
; And the name, which only this way of arriving at an entry needs: walking up a chain of
|
||||
; parents to write out where the machine is wants the name at every step. Copied here
|
||||
; rather than in sbfsTakeEntry, because every find in the system goes through that one
|
||||
; and none of them wants twenty two bytes moved on its behalf.
|
||||
PSHD.3
|
||||
POPD.0
|
||||
DPUP.0 0d06
|
||||
SETD.1 SbfsName
|
||||
INIA 0d22
|
||||
SETD.2 SbfsCount
|
||||
STA.2
|
||||
sbfsAtName:
|
||||
LDA.0
|
||||
STA.1
|
||||
INCD.0
|
||||
INCD.1
|
||||
LDA.2
|
||||
DECA
|
||||
STA.2
|
||||
BNA sbfsAtName
|
||||
RSTA
|
||||
STA.1 ; The twenty third byte, which makes it a string.
|
||||
|
||||
RSTA
|
||||
RSTB
|
||||
CCF
|
||||
@@ -697,6 +796,13 @@ sbfsWalkEntry:
|
||||
AND
|
||||
BRQ sbfsWalkScan
|
||||
|
||||
; And is it in the directory the machine is in? The entries of every directory on the
|
||||
; disk are mixed together in one array - being a child is a fact written in the child,
|
||||
; not a list kept anywhere - so a walk that wants one directory has to say which, and
|
||||
; everything else is stepped over on the way past.
|
||||
CALL sbfsWalkHere
|
||||
BNQ sbfsWalkScan
|
||||
|
||||
CALL sbfsWalkTake
|
||||
RSTA
|
||||
RSTB
|
||||
@@ -1770,6 +1876,19 @@ SbfsMatchLeft:
|
||||
0x00
|
||||
SbfsLeft:
|
||||
0x00
|
||||
; ---- Where the machine is ----
|
||||
;
|
||||
; The working directory, written the way a parent is written: an entry index plus one, so
|
||||
; zero is the root and a freshly booted machine is already there. A path that does not
|
||||
; begin with a separator is measured from here.
|
||||
;
|
||||
; It lives here rather than in the shell because it is what a relative path MEANS, and the
|
||||
; thing that resolves a path is here. Keeping it in the shell would mean either handing it
|
||||
; down on every call or having the shell paste it onto the front of every name, and the
|
||||
; second of those is how a name that is already absolute gets ruined.
|
||||
SbfsCwd:
|
||||
0x00 0x00
|
||||
|
||||
; ---- What walking a path keeps ----
|
||||
;
|
||||
; SbfsAt is where the walk has got to, written the way a parent is written: an entry index
|
||||
|
||||
Reference in New Issue
Block a user