From eaeb4731768886efe4918f9d6f6613e59ded1cb6 Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Sun, 6 Sep 2026 19:53:33 -0400 Subject: [PATCH] ls says in green what the shell will start Directories were already blue. Something the shell will run is green now, and it is asked by LOOKING rather than looked up. This was priced once as needing a runnable bit in the directory entry, set by the filesystem from a list of magic numbers it would have to be taught - declined twice, for putting format knowledge in the filesystem and giving two implementations a registry to keep in step. It costs nothing of the sort any more. The shell decides what to run by reading a file's first block, so "will this run" is a question with an answer already, and this asks the same one the shell would: SBEX for a program, "#!" for a script. Nothing is written down and nothing has to agree about anything. The price is a block read per file, which is exactly what the bit existed to avoid: a listing of thirty seven files went from 260,593 cycles to 635,321. It is paid in ls and not in dir on purpose - dir is the listing you audit and is built into the shell, this is the one you read and was loaded off the disk anyway. The fast one stays fast. plain.script is the proof on the test disk: it sits among a dozen scripts that are green and is not one, because it is the fixture with no shebang and the shell will not start it. The extension is decoration and the colour is the truth, which is the whole of what running by content means, finally visible. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/Apps/ls.asm | 92 ++++++++++++++++++++++++++++- Programs/CosmOS/README.md | 11 ++++ Tests/expected/cosmosCrossDisk.out | 2 +- Tests/expected/cosmosDrives.out | 2 +- Tests/expected/cosmosFault.out | 2 +- Tests/expected/cosmosFlip.out | 2 +- Tests/expected/cosmosGrid.out | 2 +- Tests/expected/cosmosLs.out | 20 +++---- Tests/expected/cosmosMonitor.out | 2 +- Tests/expected/cosmosMonitorRun.out | 2 +- Tests/expected/cosmosRun.out | 2 +- Tests/expected/cosmosSlowDisk.out | 2 +- Tests/expected/cosmosSpace.out | 2 +- Tests/expected/cosmosSprite.out | 2 +- Tests/expected/cosmosWalk.out | 2 +- 15 files changed, 124 insertions(+), 23 deletions(-) diff --git a/Programs/CosmOS/Apps/ls.asm b/Programs/CosmOS/Apps/ls.asm index 69a26cd..9e5beab 100644 --- a/Programs/CosmOS/Apps/ls.asm +++ b/Programs/CosmOS/Apps/ls.asm @@ -199,7 +199,8 @@ lsColour: ; ---- What it is, said in colour ---- ; ; The attribute reaches a terminal as well as the screen now, so this is one mechanism and - ; not two. A directory in blue and an unfinished save in red; everything else plain. + ; not two. A directory in blue, something that will run in green, an unfinished save in red, + ; and everything else plain. SETD.0 Kind LDA.0 BRA lsFileInk @@ -212,6 +213,27 @@ lsBlue: BRI lsInk lsFileInk: + ; ---- Whether it will run, asked by looking ---- + ; + ; This was priced once as needing a RUNNABLE BIT in the directory entry, set by the + ; filesystem from a list of magic numbers it would have to be taught - which was declined, + ; twice, for putting format knowledge in the filesystem and giving two implementations a + ; registry to keep in step. + ; + ; It costs nothing of the sort now. The shell decides what to run by READING the first block + ; of a file, so "will this run" is a question with an answer already, and asking it is the + ; same question the shell would ask. Nothing new is written down and nothing has to agree + ; about anything: if the shell learns a third kind of runnable file, this is wrong until + ; somebody adds two lines, and wrong in the direction of a listing that is less colourful. + ; + ; The price is a block read per file, which is what the bit existed to avoid. It is paid + ; here rather than in dir on purpose: dir is the listing you audit and is built into the + ; shell, and this is the one you read and is a program that was loaded off the disk anyway. + CALL runnable + BNQ lsPlain + INIA 0d2 + BRI lsInk +lsPlain: RSTA lsInk: OUTA 0x06 @@ -300,6 +322,67 @@ lengthDone: ADD RET +; ---- Will the shell start this? ---- +; +; Q is zero if it will. The same two things the shell itself looks for in a first block: SBEX +; for a program, "#!" for a script. A file too short to have a first block at all cannot be +; either, and osFileBlock saying no is that answer arriving for free. +runnable: + SETD.0 Name + SETD.1 Block + RSTA + RSTB + SWI osFileBlock + BNQ runnableNo + + ; The shebang first, because two bytes settle it. + SETD.0 Block + LDA.0 + INIB 0d35 ; '#' + CCF + SUB + BNQ runnableExec + INCD.0 + LDA.0 + INIB 0d33 ; '!' + CCF + SUB + BRQ runnableYes + +runnableExec: + SETD.0 Block + SETD.1 ExecText + INIA 0d4 + SETD.2 Left + STA.2 +runnableSame: + LDA.0 + LDB.1 + CCF + SUB + BNQ runnableNo + INCD.0 + INCD.1 + SETD.2 Left + LDA.2 + DECA + STA.2 + BNA runnableSame + +runnableYes: + RSTA + RSTB + CCF + ADD + RET + +runnableNo: + INIA 0x01 + RSTB + CCF + ADD + RET + ; A is how much of the cell the name took. Fills the rest of it with spaces. padOut: ; The cell less what the name took, and IN THAT ORDER. Written the other way round first, @@ -337,6 +420,8 @@ newLine: #Base 0x3000 +ExecText: +"SBEX" Slash: "/" Space: @@ -362,7 +447,12 @@ Seen: 0x00 Used: 0x00 +Left: + 0x00 Name: #Reserve 0d24 Given: #Reserve 0d64 +; A whole block, because osFileBlock writes one whether the file fills it or not. +Block: + #Reserve 0d256 diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index b2e5c93..282605d 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -724,6 +724,17 @@ sorting. Nothing here sorts; entries come back in the order the directory holds order arbitrary, down-and-across buys nothing and costs a division on a machine that cannot divide. If sorting ever arrives, that is the moment to change it. +**Something that will run is green**, and that is asked by looking rather than looked up. The +shell decides what to run by reading a file's first block, so "will this run" already has an +answer and this asks the same question the shell would: `SBEX` for a program, `#!` for a +script. It costs a block read per file, which is exactly the price a *runnable bit* in the +directory entry was proposed to avoid - and that bit was declined twice for putting format +knowledge in the filesystem and giving two implementations a registry to keep in step. Paying +the price here instead buys the same listing and writes nothing down. + +It is paid in `ls` and not in `dir` on purpose. Reading every file roughly doubles what a +listing costs; `dir` stays the fast one, and this one was loaded off the disk anyway. + **The width comes from the screen**, port `0x32`, which is 80 while CosmOS is running because CosmOS asks for the wide mode as it starts. diff --git a/Tests/expected/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index 33a9360..12dcd3a 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -49,7 +49,7 @@ pass.script 20 holds.script 87 crossed.txt 560 36 files, 2 directories -48 of 64 entries, 1887 blocks free +48 of 64 entries, 1886 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index d66459e..5b37c45 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -40,7 +40,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > drive 1 > dir other.txt 28 diff --git a/Tests/expected/cosmosFault.out b/Tests/expected/cosmosFault.out index 3645cfa..36337fe 100644 --- a/Tests/expected/cosmosFault.out +++ b/Tests/expected/cosmosFault.out @@ -56,7 +56,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosFlip.out b/Tests/expected/cosmosFlip.out index 98daf99..6f163b7 100644 --- a/Tests/expected/cosmosFlip.out +++ b/Tests/expected/cosmosFlip.out @@ -44,7 +44,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosGrid.out b/Tests/expected/cosmosGrid.out index cfa72f0..095fa3e 100644 --- a/Tests/expected/cosmosGrid.out +++ b/Tests/expected/cosmosGrid.out @@ -44,7 +44,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosLs.out b/Tests/expected/cosmosLs.out index 25c3f66..0a64be1 100644 --- a/Tests/expected/cosmosLs.out +++ b/Tests/expected/cosmosLs.out @@ -1,19 +1,19 @@ CosmOS > ls -greet.sbx hello.sbx Life.sbx Snake.sbx Keys.sbx -Say.sbx Where.sbx Break.sbx Grid.sbx Press.sbx -Mode.sbx Flip.sbx Sprite.sbx Depth.sbx Packages/ -Pad.sbx Crash.sbx vars.script blocks.script loops.script -tune.sbx Play.sbx notes.txt Apps/ hi.script -bad.script plain.script cross.script nonl.script outer.script -inner.script loop.script hush.script aloud.script args.script -pass.script holds.script +greet.sbx hello.sbx Life.sbx Snake.sbx Keys.sbx +Say.sbx Where.sbx Break.sbx Grid.sbx Press.sbx +Mode.sbx Flip.sbx Sprite.sbx Depth.sbx Packages/ +Pad.sbx Crash.sbx vars.script blocks.script loops.script +tune.sbx Play.sbx notes.txt Apps/ hi.script +bad.script plain.script cross.script nonl.script outer.script +inner.script loop.script hush.script aloud.script args.script +pass.script holds.script > cd /Apps /Apps> ls -Copy.sbx Say.sbx Where.sbx Walk.sbx ls.sbx Lander where.sh +Copy.sbx Say.sbx Where.sbx Walk.sbx ls.sbx Lander where.sh /Apps> cd / > ls /Packages/app.Lander -Lander.sbx splash.tune +Lander.sbx splash.tune > mkdir /empty made > cd /empty diff --git a/Tests/expected/cosmosMonitor.out b/Tests/expected/cosmosMonitor.out index f399cae..c1af395 100644 --- a/Tests/expected/cosmosMonitor.out +++ b/Tests/expected/cosmosMonitor.out @@ -132,7 +132,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosMonitorRun.out b/Tests/expected/cosmosMonitorRun.out index 8289430..62307f5 100644 --- a/Tests/expected/cosmosMonitorRun.out +++ b/Tests/expected/cosmosMonitorRun.out @@ -51,7 +51,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index 04396a6..d336479 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -40,7 +40,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > load load what? > load nosuch.sbx diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index 0de2747..2d1505d 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -38,7 +38,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > load Say.sbx loaded, starting at 5000 > run the disk took its time diff --git a/Tests/expected/cosmosSpace.out b/Tests/expected/cosmosSpace.out index 9e45035..e59216b 100644 --- a/Tests/expected/cosmosSpace.out +++ b/Tests/expected/cosmosSpace.out @@ -38,7 +38,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > drive 1 > dir f1.txt 1500 diff --git a/Tests/expected/cosmosSprite.out b/Tests/expected/cosmosSprite.out index b87b46c..df7f3c6 100644 --- a/Tests/expected/cosmosSprite.out +++ b/Tests/expected/cosmosSprite.out @@ -44,7 +44,7 @@ args.script 64 pass.script 20 holds.script 87 35 files, 2 directories -47 of 64 entries, 1890 blocks free +47 of 64 entries, 1889 blocks free > exit halted Execution halted. diff --git a/Tests/expected/cosmosWalk.out b/Tests/expected/cosmosWalk.out index 21b6968..f2c9560 100644 --- a/Tests/expected/cosmosWalk.out +++ b/Tests/expected/cosmosWalk.out @@ -43,7 +43,7 @@ f Copy.sbx 7 f Say.sbx 1 f Where.sbx 4 f Walk.sbx 1 -f ls.sbx 3 +f ls.sbx 4 f Lander 4 f where.sh 3 /Apps> cd /