A program can see a directory

Every file service took a name a program already knew - read it, save it,
rename it, delete it, ask how big it is - and none of them could find out
what names there are. dir could list only because it lives in the shell
and calls the filesystem directly. So a file manager, a backup, and the
package manager still to come were each unwritable for want of this.

osDirFirst and osDirNext. DP0 says where to put the name and B how much
room, the same bargain osArgument and osWhereAmI offer.

Q ANSWERS THE KIND rather than a yes or no, so one value says both
whether there is an entry and what it is: 0 a file, 1 a directory, 2 a
save that stopped before it committed, 0xFF nothing more. A caller that
only wants names tests for 0xFF and ignores the rest.

The size is deliberately not in it. A walk hands back a name, and a
program that wants the size asks osFileInfo about that name - the
alternative being a record in memory whose shape both sides have to agree
on, which services.asm went out of its way to avoid for file sizes.

Walk.asm is the first program that can see a directory, and it asks
osFileInfo about each entry BETWEEN two steps of the walk. That is the
hazard rather than decoration: where a walk has got to and where the last
file asked about lives are both held by the system, and two things
sharing one position would show as a listing that stopped early or said a
name twice. Then the same walk in /Apps, since one that only ever ran at
the root would not have proved it walks where you are.

A directory is not asked about at all. osFileInfo answers for one
perfectly well and says nought blocks, which is true and reads as a size
- and nought is a size a file can genuinely have.

The lint baseline moves by one. The kind is decided by a chain of bit
tests in the shape dir already uses five hundred lines away, and arms of
a comparison chain each loading the same variable are the case this
project's own rule says not to collapse: the repetition is what lets a
new arm be dropped in anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-06 17:55:41 -04:00
co-authored by Claude Opus 5
parent b83ba5bf7a
commit 2ad8edf9bc
10 changed files with 375 additions and 2 deletions
+78
View File
@@ -6184,6 +6184,82 @@ fileForget:
; Blocks, not bytes, and that is forced rather than chosen: a file on a sixteen megabyte
; disk is up to twenty four bits long, which does not fit in a pointer. Blocks do, and the
; bytes in the last one come back from osFileBlock when the reader gets there.
; ---- Walking a directory on a program's behalf ----
;
; The one thing the filesystem could do that no program could ask for. dir has always been
; able to list because it lives in here; a loaded program had no way to find out what names
; exist at all, which left a file manager, a backup, and the package manager still to come
; all unable to be written.
;
; Two entry points into one routine, because the difference between them is a single call.
;
; Q ANSWERS THE KIND, so one value says both whether there is an entry and what it is: 0 a
; file, 1 a directory, 2 a save that stopped before it committed, 0xFF nothing more. A
; caller that only wants names tests for 0xFF and ignores the rest.
handleDirFirst:
SETD.2 DiskReady
LDA.2
BRA dirWalkNoMore
CALL sbfsFirst
BRI dirWalkGot
handleDirNext:
SETD.2 DiskReady
LDA.2
BRA dirWalkNoMore
CALL sbfsNext
dirWalkGot:
BNQ dirWalkNoMore
; The name first, because working out the kind wants the registers. B is still the room
; the caller asked for: a CALL puts it back, and nothing above has taken it.
PSHD.0
POPD.1
SETD.0 SbfsName
CALL copyText
; ---- What kind of thing it is ----
;
; Asked in the same order dir asks it. An unfinished save is looked at FIRST because it is
; the one thing here that is not really a file yet, and it is SHOWN rather than hidden:
; the bytes are all there under that name, so a program that can see it is a program that
; can rename it back.
SETD.2 SbfsFoundFlags
LDA.2
INIB 0x04
AND
BNQ dirWalkUnfinished
SETD.2 SbfsFoundFlags
LDA.2
INIB 0x02
AND
BNQ dirWalkDirectory
RSTA
BRI dirWalkAnswer
dirWalkDirectory:
INIA 0d1
BRI dirWalkAnswer
dirWalkUnfinished:
INIA 0d2
BRI dirWalkAnswer
dirWalkNoMore:
; A machine with no disk has nothing to walk, and says the same thing as a walk that has
; run out. There is no third answer worth telling apart: a caller that cannot list is a
; caller that lists nothing either way.
INIA 0xFF
dirWalkAnswer:
RSTB
CCF
ADD ; A is the answer, so Q becomes it.
SRET
handleFileInfo:
SETD.2 DiskReady
LDA.2
@@ -8652,6 +8728,8 @@ CommandLine:
osLastStatus handleLastStatus
osTakeScreen handleTakeScreen
osWhereAmI handleWhereAmI
osDirFirst handleDirFirst
osDirNext handleDirNext
osBootState handleBootState
osBootSettle handleBootSettle
Device 0x20 diskDone
+34
View File
@@ -208,3 +208,37 @@
; own would mean "Play mytune.tune", typed by somebody in their own directory, looked in
; Play's. The working directory stays the person's; this is how a program finds its own.
osWhereAmI 0d37
; ---- Seeing what is on the disk ----
;
; Everything above takes a name a program already knows. NOTHING HERE COULD FIND OUT WHAT
; NAMES THERE ARE - a machine whose programs can read, write, rename and delete files and
; cannot ask what files exist. dir could only list because it lives in the shell and calls
; the filesystem directly; no loaded program could list anything at all.
;
; DP0 says where to put the name and B how much room there is, counting the zero, the same
; bargain osArgument and osWhereAmI offer.
;
; Q ANSWERS THE KIND RATHER THAN A YES OR NO, which is one value carrying both "is there
; one" and "what is it":
;
; 0 a file
; 1 a directory
; 2 a save that stopped before it committed
; 0xFF there are no more
;
; ---- And the size is not in it ----
;
; A walk hands back a NAME, and a program that wants the size of what it found asks
; osFileInfo about that name. The alternative is a record in memory whose shape both sides
; have to agree on, which is exactly what this file went out of its way to avoid for file
; sizes - and most callers of this want names and nothing else.
;
; ---- One walk at a time, and the system holds it ----
;
; Where a walk has got to is the system's, the way an open write is. A program that starts a
; second walk before finishing the first gets the second; there is one position, not a handle
; per caller. That is the same bargain osFileStart makes and for the same reason: the state
; is small, and a program that stops in the middle leaves nothing behind to clean up.
osDirFirst 0d38
osDirNext 0d39