Start a program by typing its name
A word the shell has no command for is now looked for on the disk as "<name>.sbx", and if it is there it is loaded and started exactly as load and run would do it. Whatever followed the word reaches the program through osArgument by the same route as whatever follows run, so "Say hello there" and "Type notes.txt" work without either program knowing how it was started. load and run are unchanged and both stay. load is how the monitor puts an arbitrary file in front of itself, which typing a name deliberately cannot do: the extension is added rather than assumed, so "notes.txt" looks for notes.txt.sbx and a text file is unreachable by name whatever is inside it. Three things this had to get right: The built-ins are tried first and always win. The search hangs off the end of the dispatch chain, so a file called dir.sbx cannot become dir, and the commands worth trusting when the disk is what you are doubting stay trustworthy. The invoke disk carries a working dir.sbx so that this is checked rather than asserted. A file that is found but is broken says so. "not a program" and "I do not know" are different answers, and giving the second about a file sitting on the disk would send somebody looking in the wrong place. loadProgram therefore hands back a status as well as a message, since only "no file of that name" can fairly be reported as anything other than a fault. doLoad became that subroutine rather than being copied. It ends in RET instead of a jump to the prompt, and each way of failing sets its number and its text together so a new one cannot leave half of the answer behind. cosmosBreak moves because Break prints the pointers it was handed and those are the shell's leftovers, which a CALL now puts back. 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
dbe58db660
commit
2b0aeeefd4
@@ -20,6 +20,8 @@ for itself.
|
||||
- Loadable Applications: Validate SBEX files, copy their Program and Data segments into
|
||||
the addresses for which they were assembled, and start them at their declared entry
|
||||
point.
|
||||
- Invocation By Name: A word the shell has no command for is looked for on the disk as
|
||||
`<name>.sbx`, and loaded and started if it is there. Built-in commands are tried first.
|
||||
- Resident Services: Applications can print strings and numbers, read lines, receive their
|
||||
command arguments, read and write files, and return to the shell through named software
|
||||
interrupts.
|
||||
@@ -83,6 +85,7 @@ CosmOS currently provides these built-in commands:
|
||||
| `dir` | List the files on the mounted disk and their sizes. |
|
||||
| `load <file>` | Read and validate an SBEX application, then place its code and data where its header requests. |
|
||||
| `run [words]` | Start the loaded application and make the rest of the line available to it as an argument. |
|
||||
| `<name> [words]` | Any word the shell does not recognise is looked for on the disk as `<name>.sbx`, and loaded and started if it is there. |
|
||||
| `delete <file>` | Remove a file from the filesystem and release its blocks. |
|
||||
| `rename <file> <to>` | Give a file a different name without moving its contents. |
|
||||
| `monitor` | Enter monitor mode, in which the prompt becomes `*` and the commands below are also available. |
|
||||
@@ -115,9 +118,47 @@ For example:
|
||||
> run
|
||||
```
|
||||
|
||||
Loading and running are separate operations for now. A loaded program may be run again
|
||||
without being read from disk again, which is useful both as a monitor facility and as a
|
||||
test that CosmOS correctly restores its Stack and vector table after every run.
|
||||
Or, equivalently:
|
||||
|
||||
```text
|
||||
> Snake
|
||||
```
|
||||
|
||||
Loading and running remain separate operations, and both of them remain. A loaded program
|
||||
may be run again without being read from disk again, which is useful both as a monitor
|
||||
facility and as a test that CosmOS correctly restores its Stack and vector table after
|
||||
every run; and `load` is how the monitor puts an arbitrary file in front of itself, which
|
||||
is a thing typing a name deliberately cannot do.
|
||||
|
||||
### Starting An Application By Name:
|
||||
|
||||
A word the shell has no command for is not immediately an error. Before saying so, the
|
||||
shell adds `.sbx` to it unless it is already there, looks for a file of that name, and if
|
||||
one is there loads it and starts it exactly as `load` and `run` would. Whatever followed
|
||||
the word reaches the program through `osArgument`, the same way and by the same route as
|
||||
whatever follows `run`.
|
||||
|
||||
Three properties of this are deliberate:
|
||||
|
||||
**Built-in commands are tried first and always win.** The search happens only after the
|
||||
whole dispatch chain has failed to match, so a file named `dir.sbx` cannot become `dir`.
|
||||
The commands that are worth trusting when the disk is the thing being doubted stay
|
||||
trustworthy.
|
||||
|
||||
**The extension is what makes a file reachable by name.** Typing `notes` looks for
|
||||
`notes.sbx`, and typing `notes.txt` looks for `notes.txt.sbx`. A text file therefore
|
||||
cannot be started by typing what it is called, whatever happens to be inside it. Only
|
||||
`load` reaches a file by its literal name.
|
||||
|
||||
**A file that is found but is broken says so.** If `notes.sbx` exists and is not an SBEX
|
||||
program, typing `notes` reports `not a program` rather than `I do not know: notes`.
|
||||
Reporting an unknown command about a file that is sitting on the disk would send somebody
|
||||
looking in the wrong place.
|
||||
|
||||
Names are matched exactly, including case, because every other name on the filesystem is.
|
||||
A directory entry holds twenty two characters and four are spoken for by the extension, so
|
||||
eighteen is the longest a bare name can be; a longer word is reported as unknown, which is
|
||||
the truth, since no file of that name can exist.
|
||||
|
||||
CosmOS also boots without a disk. It reports that no filesystem was found, leaves the
|
||||
shell and memory monitor available, and refuses commands that require a mounted disk
|
||||
|
||||
@@ -185,8 +185,39 @@ promptSay:
|
||||
BRQ doAssemble
|
||||
|
||||
promptUnknown:
|
||||
; Nothing matched. Saying which word was not understood is worth the four instructions:
|
||||
; it tells somebody who mistyped what they actually typed.
|
||||
; Nothing built in matched, so the disk is asked before anybody is told they are wrong. A
|
||||
; word this shell does not know is very often the name of a program sitting right there,
|
||||
; and looking costs a walk of the directory.
|
||||
;
|
||||
; THE BUILT-IN COMMANDS ARE TRIED FIRST AND ALWAYS WIN. Nothing that turns up on a disk
|
||||
; can quietly become "dir" or "exit", which is what makes those two worth trusting at the
|
||||
; moment the disk is the thing being doubted.
|
||||
SETD.0 DiskReady
|
||||
LDA.0
|
||||
BRA promptSayUnknown ; No filesystem, so there is nothing to look through.
|
||||
|
||||
CALL nameProgram
|
||||
SETD.0 NameOk
|
||||
LDA.0
|
||||
BRA promptSayUnknown ; Too long to be a file name, so it is not the name of one.
|
||||
|
||||
CALL loadProgram
|
||||
SETD.0 LoadStatus
|
||||
LDA.0
|
||||
BRA runLoaded ; It loaded, and the machine is its now.
|
||||
|
||||
; No file of that name is not a fault. It is the ordinary case of a word this shell does
|
||||
; not know, and it is reported in those words. Anything else means a file of that name IS
|
||||
; there and something is wrong with it, and answering "I do not know: Snake" about a
|
||||
; Snake.sbx that is sitting on the disk would send somebody looking in the wrong place.
|
||||
INIB 0d2
|
||||
CCF
|
||||
SUB
|
||||
BNQ loadFailed
|
||||
|
||||
promptSayUnknown:
|
||||
; Saying which word was not understood is worth the four instructions: it tells somebody
|
||||
; who mistyped what they actually typed.
|
||||
SETD.0 Unknown
|
||||
CALL printString
|
||||
SETD.0 CommandLine
|
||||
@@ -329,6 +360,93 @@ widthDone:
|
||||
ADD
|
||||
RET
|
||||
|
||||
; ---- Making a file name out of a typed word ----
|
||||
;
|
||||
; Turns what was typed into the name of a file to go and look for. ".sbx" goes on the end
|
||||
; unless it is already there, so that "Snake" and "Snake.sbx" both find the same file.
|
||||
;
|
||||
; THE EXTENSION IS WHAT MAKES A FILE REACHABLE BY NAME. Typing "notes" looks for notes.sbx
|
||||
; and typing "notes.txt" looks for notes.txt.sbx, so a text file cannot be started by
|
||||
; typing what it is called, whatever is inside it. Only load reaches a file by its whole
|
||||
; name, which is why the monitor can still put any file at all in front of itself.
|
||||
;
|
||||
; NameOk is one if there is a name in ProgramName and zero if the word could not be made
|
||||
; into one. A directory entry holds twenty two characters and four of those are spoken for
|
||||
; by the extension, so eighteen is as long as a bare name can be. Being refused here reads
|
||||
; as an unknown command, which is the truth: no file of that name can exist.
|
||||
nameProgram:
|
||||
RSTA
|
||||
SETD.0 NameOk
|
||||
STA.0 ; Not a name until it turns out to be one.
|
||||
|
||||
SETD.0 CommandLine
|
||||
SETD.1 ProgramName
|
||||
INIB 0d22 ; How much of the twenty two is left.
|
||||
nameCopy:
|
||||
LDA.0
|
||||
BRA nameCopied
|
||||
STA.1
|
||||
INCD.0
|
||||
INCD.1
|
||||
DECB
|
||||
BNB nameCopy
|
||||
RET ; Twenty two characters and still going. Not a name.
|
||||
|
||||
nameCopied:
|
||||
; DP1 is on the byte after the word, which is where an extension would go, and B is what
|
||||
; is left. B is written down before anything else wants the registers.
|
||||
RSTA
|
||||
STA.1
|
||||
SETD.0 NameLeft
|
||||
STB.0
|
||||
|
||||
; Only a word of four characters or more can already end in ".sbx". Stepping back four to
|
||||
; look at a shorter one would read whatever happens to sit in front of the buffer.
|
||||
INIA 0d18
|
||||
CCF
|
||||
SUB
|
||||
BRC nameAppend
|
||||
|
||||
PSHD.1
|
||||
POPD.2
|
||||
DPDN.2 0d4
|
||||
SETD.0 SbxSuffix
|
||||
nameSuffixSame:
|
||||
LDA.0
|
||||
BRA nameMade ; The suffix ran out with all of it matched.
|
||||
LDB.2
|
||||
CCF
|
||||
SUB
|
||||
BNQ nameAppend
|
||||
INCD.0
|
||||
INCD.2
|
||||
BRI nameSuffixSame
|
||||
|
||||
nameAppend:
|
||||
SETD.0 NameLeft
|
||||
LDA.0
|
||||
INIB 0d4
|
||||
CCF
|
||||
SUB
|
||||
BRC nameDone ; Not four characters of room, so there is no name to be made.
|
||||
|
||||
; The suffix carries its own zero, so copying it to the end of the word ends the word.
|
||||
SETD.0 SbxSuffix
|
||||
nameSuffixCopy:
|
||||
LDA.0
|
||||
STA.1
|
||||
BRA nameMade
|
||||
INCD.0
|
||||
INCD.1
|
||||
BRI nameSuffixCopy
|
||||
|
||||
nameMade:
|
||||
INIA 0x01
|
||||
SETD.0 NameOk
|
||||
STA.0
|
||||
nameDone:
|
||||
RET
|
||||
|
||||
; ---- load ----
|
||||
;
|
||||
; Reads a program off the disk and puts it where its header asks to go. Nothing relocates
|
||||
@@ -337,17 +455,78 @@ widthDone:
|
||||
;
|
||||
; The whole file is staged at 0x8000 first and then blitted into place, because where the
|
||||
; pieces belong is not known until the header has been read, and the header is in the file.
|
||||
;
|
||||
; The command is a thin thing over loadProgram, which is a subroutine because typing a
|
||||
; program's name loads it too and neither caller should own the loading. What differs
|
||||
; between them is only what a fault means: "load Snake.sbx" on a disk without it has been
|
||||
; given a wrong name, and "Snake" on the same disk has typed a word this shell does not
|
||||
; know.
|
||||
|
||||
doLoad:
|
||||
SETD.0 DiskReady
|
||||
LDA.0
|
||||
BRA loadNoDisk
|
||||
|
||||
SETD.1 TextRest
|
||||
LDD.0.1
|
||||
LDA.0
|
||||
BRA loadNothingNamed
|
||||
|
||||
; The name exactly as typed. load is how a file is reached by its whole name, so nothing
|
||||
; is added to it and nothing is assumed about what it ends in.
|
||||
SETD.1 ProgramName
|
||||
INIB 0d23
|
||||
CALL copyText
|
||||
|
||||
CALL loadProgram
|
||||
SETD.0 LoadStatus
|
||||
LDA.0
|
||||
BNA loadFailed
|
||||
|
||||
SETD.0 LoadedText
|
||||
CALL printString
|
||||
SETD.0 LoadedEntry
|
||||
CALL printWordHex
|
||||
CALL newLine
|
||||
BRI prompt
|
||||
|
||||
loadFailed:
|
||||
SETD.1 LoadMessage
|
||||
LDD.0.1
|
||||
CALL printString
|
||||
CALL newLine
|
||||
BRI prompt
|
||||
|
||||
loadNothingNamed:
|
||||
SETD.0 LoadWhat
|
||||
CALL printString
|
||||
CALL newLine
|
||||
BRI prompt
|
||||
|
||||
; ---- loadProgram ----
|
||||
;
|
||||
; The name is in ProgramName. LoadStatus says what happened and LoadMessage names the text
|
||||
; for it, because a subroutine cannot hand anything back in a register that a RET puts
|
||||
; back, and here there are two things to hand back:
|
||||
;
|
||||
; 0 loaded, and LoadedEntry says where it starts
|
||||
; 1 no filesystem on the disk
|
||||
; 2 no file of that name
|
||||
; 3 the disk would not read it
|
||||
; 4 it is not a program
|
||||
; 5 a version of the format this loader does not know
|
||||
; 6 more vectors than there is room to keep
|
||||
;
|
||||
; Two is the one worth telling apart from the others. It is the only outcome where nothing
|
||||
; was wrong with the disk or with a file, and so the only one a caller can fairly report as
|
||||
; something other than a fault.
|
||||
|
||||
loadProgram:
|
||||
RSTA
|
||||
SETD.0 LoadStatus
|
||||
STA.0
|
||||
|
||||
SETD.0 DiskReady
|
||||
LDA.0
|
||||
BRA loadNoDisk
|
||||
|
||||
SETD.0 ProgramName
|
||||
CALL sbfsFind
|
||||
BNQ loadMissing
|
||||
|
||||
@@ -532,38 +711,40 @@ loadVectorsCopied:
|
||||
INIA 0x01
|
||||
SETD.0 LoadedOk
|
||||
STA.0
|
||||
RET ; LoadStatus is still the zero it was started at.
|
||||
|
||||
SETD.0 LoadedText
|
||||
CALL printString
|
||||
SETD.0 LoadedEntry
|
||||
CALL printWordHex
|
||||
CALL newLine
|
||||
BRI prompt
|
||||
|
||||
; Which of the seven happened, and where the words for it are. The two are set together so
|
||||
; that no caller has to know both, and so that adding a way to fail cannot leave one of
|
||||
; them behind.
|
||||
loadNoDisk:
|
||||
INIA 0d1
|
||||
SETD.0 NoDisk
|
||||
BRI loadComplain
|
||||
loadNothingNamed:
|
||||
SETD.0 LoadWhat
|
||||
BRI loadComplain
|
||||
loadTooManyVectors:
|
||||
SETD.0 TooManyVectors
|
||||
BRI loadComplain
|
||||
BRI loadRefuse
|
||||
loadMissing:
|
||||
INIA 0d2
|
||||
SETD.0 NoSuchFile
|
||||
BRI loadComplain
|
||||
BRI loadRefuse
|
||||
loadUnreadable:
|
||||
INIA 0d3
|
||||
SETD.0 Unreadable
|
||||
BRI loadComplain
|
||||
BRI loadRefuse
|
||||
loadNotProgram:
|
||||
INIA 0d4
|
||||
SETD.0 NotProgram
|
||||
BRI loadComplain
|
||||
BRI loadRefuse
|
||||
loadWrongVersion:
|
||||
INIA 0d5
|
||||
SETD.0 WrongVersion
|
||||
loadComplain:
|
||||
CALL printString
|
||||
CALL newLine
|
||||
BRI prompt
|
||||
BRI loadRefuse
|
||||
loadTooManyVectors:
|
||||
INIA 0d6
|
||||
SETD.0 TooManyVectors
|
||||
loadRefuse:
|
||||
SETD.1 LoadMessage
|
||||
STD.0.1
|
||||
SETD.1 LoadStatus
|
||||
STA.1
|
||||
RET
|
||||
|
||||
; ---- delete and rename ----
|
||||
;
|
||||
@@ -658,6 +839,11 @@ doRun:
|
||||
LDA.0
|
||||
BRA runNothing
|
||||
|
||||
; Where typing a program's name arrives, having loaded it on the way. The argument comes
|
||||
; out of TextRest either way: after "run" that is what followed the word, and after a
|
||||
; program's own name it is what followed the name, which is the same thing meaning the
|
||||
; same thing.
|
||||
runLoaded:
|
||||
MVSD.0
|
||||
SETD.1 SystemStack
|
||||
STD.0.1
|
||||
@@ -2538,10 +2724,11 @@ HelpText:
|
||||
"dir list what is on the disk
|
||||
load <file> read a program off the disk
|
||||
run [words] start what was loaded, and tell it those words
|
||||
delete <file> take it off the disk
|
||||
rename <file> <to> call it something else"
|
||||
<name> [words] load and start that program off the disk"
|
||||
HelpMoreText:
|
||||
"monitor look at memory, change it, and jump into it
|
||||
"delete <file> take it off the disk
|
||||
rename <file> <to> call it something else
|
||||
monitor look at memory, change it, and jump into it
|
||||
help this
|
||||
exit stop, or leave the monitor if you are in it"
|
||||
|
||||
@@ -2556,6 +2743,11 @@ DataWord:
|
||||
|
||||
ExecMagic:
|
||||
"SBEX"
|
||||
|
||||
; What every program on the disk is called, and the four characters that make one
|
||||
; reachable by typing its name.
|
||||
SbxSuffix:
|
||||
".sbx"
|
||||
LoadWhat:
|
||||
"load what?"
|
||||
NoSuchFile:
|
||||
@@ -2673,6 +2865,21 @@ DiskReady:
|
||||
0x00
|
||||
LoadedOk:
|
||||
0x00
|
||||
|
||||
; What loadProgram found, and the words for it. See loadProgram for what the numbers mean.
|
||||
LoadStatus:
|
||||
0x00
|
||||
LoadMessage:
|
||||
0x00 0x00
|
||||
|
||||
; The name of the file to load, which load copies out of the line as typed and a typed
|
||||
; program name is built into. Twenty two characters and the zero that ends them.
|
||||
ProgramName:
|
||||
#Reserve 0d23
|
||||
NameOk:
|
||||
0x00
|
||||
NameLeft:
|
||||
0x00
|
||||
LoadedEntry:
|
||||
0x00 0x00
|
||||
LoadCount:
|
||||
|
||||
Reference in New Issue
Block a user