A script is given words, and keeps them

"do build.sh cosmos.asm" looked for a file called "build.sh cosmos.asm",
because scriptOpen copied the whole rest of the line into the name. So a
script could be told nothing, and a launcher - a script whose entire job
is to hand on what it was told - could not exist.

Now the name is cut off the front and what follows is kept whole. $1 to
$9 are the words of it, walked out on demand, and $args is all of them.
Nothing is stored per parameter, so there is no limit on how many a
script may be handed and no second number to keep in step. Both ways of
starting a script pass them on: "do" and typing the name.

A word that was not given is an error that stops the script, like every
other name this shell does not know. Expanding it to nothing would let a
command run with an argument missing and then report success, which is
what stop-on-failure exists to prevent. $args is always set inside a
script, empty if it was given nothing, so "if same $args" can be asked.

---- And the count that describes the block was already wrong ----

Found while adding a field to it. The state one script keeps for another
is saved by a single copy of a fixed number of bytes, and that number was
71 against a block of 77: six bytes of line position had been added in
the middle of it years after the count was written. So the tail of every
saved script was never saved, and #quiet in a helper stayed behind in the
script that called it - the opposite of what this file's own comment
promises and the README documents.

The unsaved line position turned out not to matter, because a loop keeps
its own copy in the block record. Nothing said so. Three numbers describe
this block and all three now say so in a comment, and cosmosScriptNest
ends on a helper that goes quiet and a caller that must not stay that
way.

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 15:06:32 -04:00
co-authored by Claude Opus 5
parent 06af7e7fbb
commit d9ebc76cf5
25 changed files with 441 additions and 25 deletions
+177 -1
View File
@@ -133,6 +133,11 @@ bootNoDisk:
; to ignore it. A file that is THERE and is not a script is the other case entirely: somebody
; meant it to run.
bootStartup:
; Nobody typed this one, so there is nothing to give it.
SETD.2 NoText
SETD.1 ScriptArgsFrom
STD.2.1
SETD.0 StartupName
CALL scriptOpen
BRQ bootReady
@@ -2647,10 +2652,18 @@ varExpandNamed:
varExpandLookUp:
SETD.1 VarKeepLine
STD.0.1 ; Where the line has got to, across the search.
; A script's own names are asked about first, so that a parameter cannot be shadowed by
; something set at the prompt. Only inside a script: at the prompt "$1" is a name nobody
; set, and gets told so like any other.
CALL varScriptName
BRQ varExpandFound
SETD.0 VarName
CALL varFind
BNQ varExpandNoSuch
CALL varValueOf
varExpandFound:
SETD.1 VarKeepLine
LDD.0.1
@@ -2733,6 +2746,139 @@ varExpandLong:
CALL newLine
BRI commandFailed
; ---- The names a script gets for nothing ----
;
; "$args" is everything it was given, and "$1" to "$9" are the words of that, counted from
; one. Nothing is stored per parameter: the line it was given is kept whole and the word
; wanted is walked out of it, so there is no limit on how many a script may be handed and
; nothing to keep in step.
;
; A NAME ONE OF THESE MISSES IS AN ERROR, like every other name this shell does not know.
; "$2" in a script given one word says so and stops it, rather than quietly becoming nothing
; and letting a command run with an argument missing - which is the rule set.asm's own comment
; argues for at length, applied to the names a script did not have to set.
;
; Q is zero if VarName is one of them, and DP3 is left on the value. DP3 because a RET puts
; the others back, which is the same reason varValueOf answers there.
varScriptName:
SETD.1 ScriptDepth
LDA.1
BRA varScriptNo ; Not in a script, so these names mean nothing here.
SETD.0 VarName
SETD.1 ArgsWord
CALL textSame
BRQ varScriptAll
; One character, and that character a digit from one to nine. Testing the length first is
; what keeps "1st" from being read as "1".
SETD.0 VarName
INCD.0
LDA.0
BNA varScriptNo
SETD.0 VarName
LDA.0
INIB 0x31
CCF
SUB
BRC varScriptNo ; Below '1'. There is no word nought.
LDA.0
INIB 0x3A
CCF
SUB
BNC varScriptNo ; Above '9'.
LDA.0
INIB 0x30
CCF
SUB
MVQA ; Which word is wanted, one to nine.
CALL varScriptWord
RET
varScriptAll:
SETD.3 ScriptArgs
RSTA
RSTB
CCF
ADD ; Q is zero: it is one of them.
RET
varScriptNo:
INIA 0x01
RSTB
CCF
ADD
RET
; A is which word is wanted. Copies it out into VarWord and leaves DP3 on it, because the
; words are separated by spaces rather than ended by zeroes and everything downstream of here
; walks a string until it ends.
;
; Q is one if the script was not given that many, which reads as a name that is not set.
varScriptWord:
SETD.1 VarWordWanted
STA.1
SETD.0 ScriptArgs
varScriptSkip:
LDA.0
BRA varScriptShort ; The end, and the word wanted is past it.
INIB 0x20
CCF
SUB
BNQ varScriptWordAt ; Not a space, so a word begins here.
INCD.0
BRI varScriptSkip
varScriptWordAt:
SETD.1 VarWordWanted
LDA.1
DECA
STA.1
BRA varScriptTake ; Counted down to nought, so this is the one.
varScriptPast:
LDA.0
BRA varScriptShort
INIB 0x20
CCF
SUB
BRQ varScriptSkip ; The end of this word, so the next one is looked for.
INCD.0
BRI varScriptPast
varScriptTake:
SETD.1 VarWord
varScriptTakeChar:
LDA.0
BRA varScriptTaken
INIB 0x20
CCF
SUB
BRQ varScriptTaken
LDA.0
STA.1
INCD.0
INCD.1
BRI varScriptTakeChar
varScriptTaken:
RSTA
STA.1 ; The zero that makes it a string.
SETD.3 VarWord
RSTB
CCF
ADD ; Q is zero, A having been reset above.
RET
varScriptShort:
INIA 0x01
RSTB
CCF
ADD
RET
varExpandNoSuch:
SETD.0 VarNoSuch
CALL printString
@@ -3521,6 +3667,13 @@ promptAsScript:
LDA.0
CALL sbfsUse
; Whatever followed the word, which reaches a script the same way it reaches a program.
; The line was split before the dispatch chain ran, so this is already the rest of it.
SETD.1 TextRest
LDD.2.1
SETD.1 ScriptArgsFrom
STD.2.1
SETD.0 ProgramName
CALL scriptOpen
BRQ prompt ; It is open, and the next line read will come from it.
@@ -4898,6 +5051,17 @@ doScript:
LDA.0
BRA scriptNoName
; The file, and then whatever else was on the line. textSplit cuts the first word off in
; place and leaves TextRest on what follows, and a RET puts DP0 back - so afterwards DP0
; names just the file and TextRest names what the script is being given.
;
; Through DP2, because DP0 is the file and must still be it when scriptOpen is called.
CALL textSplit
SETD.1 TextRest
LDD.2.1
SETD.1 ScriptArgsFrom
STD.2.1
CALL scriptOpen
BRQ prompt ; It is open, and the next line read will come from it.
@@ -7598,7 +7762,7 @@ HelpCdText:
mkdir <path> make a directory
rmdir <path> remove an empty one"
HelpScriptText:
"do <file> run the lines in a file, which must start with #!
"do <file> [words] run the lines in a file, which must start with #!
echo [words] say them
clear empty the screen"
HelpMoreText:
@@ -7809,6 +7973,12 @@ ShellNameCount:
AppsPath:
"/Apps"
ArgsWord:
"args"
; An empty string, for a script the machine started rather than somebody typing, which was
; therefore given nothing.
NoText:
0x00
VarNoSuch:
"nothing is set called "
VarTooLong:
@@ -8249,6 +8419,12 @@ VarSlots:
#Reserve 0d512
VarSlot:
0x00
; One word of what a script was given, copied out so that it ends in a zero like every other
; value. A whole line of room, because one word can be the whole line.
VarWord:
#Reserve 0d128
VarWordWanted:
0x00
VarWanted:
0x00 0x00
VarKeepValue: