The shell runs what it reads, not what a name ends in
A typed word had ".sbx" pasted on the end of it before anything went looking, which is why "notes.txt" sent the shell after a notes.txt.sbx that was never going to exist, and why a script could only be started with "do". The extension was what made a file reachable by name. Now the word as typed is asked for first and the word with the extension on it only after that misses. What comes back is dispatched on what is inside it: SBEX loads and starts, "#!" is read as lines. The loader already refuses anything that is not SBEX and the script reader already refuses anything without the shebang, so the two kinds of runnable file turn each other away and neither has to know the other exists. The suffix can only ever be a second guess, so a file that is really there always beats one that would have to be invented and every program already on a disk still starts by the short name people type for it. It costs a second walk of each directory when a word is not found in it. Tab completion offers a file under the name it actually has, and the suffix stripper is gone: a first word can now be any file at all, and offering only the ones ending .sbx would hide the scripts. The video capture windows moved out a hundred thousand cycles, because starting Lander now walks four names where it walked two. 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
4e61158b11
commit
fd962f0084
+45
-23
@@ -28,8 +28,9 @@ for itself.
|
|||||||
- Loadable Applications: Validate SBEX files, copy their Program and Data segments into
|
- 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
|
the addresses for which they were assembled, and start them at their declared entry
|
||||||
point.
|
point.
|
||||||
- Invocation By Name: A word the shell has no command for is looked for on the disk as
|
- Invocation By Name: A word the shell has no command for is looked for on the disk, and
|
||||||
`<name>.sbx`, and loaded and started if it is there. Built-in commands are tried first.
|
what is found is run according to what is inside it - a program is loaded and started, a
|
||||||
|
script is read as lines. Built-in commands are tried first.
|
||||||
- Resident Services: Applications can print strings and numbers, read lines, receive their
|
- 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
|
command arguments, read and write files, and return to the shell through named software
|
||||||
interrupts.
|
interrupts.
|
||||||
@@ -211,6 +212,10 @@ A `$` with nothing name-like after it is just a `$`.
|
|||||||
the same way it does at the prompt, because the only thing a script changes is where the next
|
the same way it does at the prompt, because the only thing a script changes is where the next
|
||||||
line comes from - the shell splits it, matches it and runs it without knowing the difference.
|
line comes from - the shell splits it, matches it and runs it without knowing the difference.
|
||||||
|
|
||||||
|
**Typing a script's name runs it too**, the same way typing a program's name does; `do` is how
|
||||||
|
a file is reached by its whole name, the way `load` is for a program. See Starting An
|
||||||
|
Application By Name.
|
||||||
|
|
||||||
```
|
```
|
||||||
#! script
|
#! script
|
||||||
; Build the system and put it where the machine will find it.
|
; Build the system and put it where the machine will find it.
|
||||||
@@ -327,7 +332,7 @@ CosmOS currently provides these built-in commands:
|
|||||||
| `cd [path]` | Go to a directory, or to the root with nothing after it. |
|
| `cd [path]` | Go to a directory, or to the root with nothing after it. |
|
||||||
| `mkdir <path>` | Make a directory. |
|
| `mkdir <path>` | Make a directory. |
|
||||||
| `rmdir <path>` | Remove one, if it is empty. |
|
| `rmdir <path>` | Remove one, if it is empty. |
|
||||||
| `<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. |
|
| `<name> [words]` | Any word the shell does not recognise is looked for on the disk, and started if it is found: loaded if it is a program, read as lines if it is a script. |
|
||||||
| `delete <file>` | Remove a file from the filesystem and release its blocks. |
|
| `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. |
|
| `rename <file> <to>` | Give a file a different name without moving its contents. |
|
||||||
| `set [name [value]]` | Give a name a value, or say what the names are. See Names For Things. |
|
| `set [name [value]]` | Give a name a value, or say what the names are. See Names For Things. |
|
||||||
@@ -422,18 +427,23 @@ program; anything after it is a file.
|
|||||||
|
|
||||||
| Where | What is offered |
|
| Where | What is offered |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| The first word | the fifteen commands, and programs - under the name you would type, with the extension taken off |
|
| The first word | the fifteen commands, and every file, under the name it actually has |
|
||||||
| After it | anything on the disk, under its real name |
|
| After it | anything on the disk, under its real name |
|
||||||
| Either, with a `/` in it | whatever is in the directory the word names |
|
| Either, with a `/` in it | whatever is in the directory the word names |
|
||||||
|
|
||||||
A directory answers with a separator on the end instead of a space, which says what it is and
|
A directory answers with a separator on the end instead of a space, which says what it is and
|
||||||
lets the next part be typed straight away.
|
lets the next part be typed straight away.
|
||||||
|
|
||||||
**Programs are looked for in the three places the shell would look to run one**: where you
|
**Files are looked for in the three places the shell would look to run one**: where you are,
|
||||||
are, `/Apps` on the disk you are on, and `/Apps` on drive 0. Offering something the shell
|
`/Apps` on the disk you are on, and `/Apps` on drive 0. Offering something the shell would not
|
||||||
would not find would be finishing a word into a thing that then does not work. A program that
|
find would be finishing a word into a thing that then does not work. A file that is in two of
|
||||||
is in two of those places is offered twice and so is never the only match, which costs it the
|
those places is offered twice and so is never the only match, which costs it the space after
|
||||||
space after it - the shell is comparing names, not deciding which file it would have run.
|
it - the shell is comparing names, not deciding which file it would have run.
|
||||||
|
|
||||||
|
A first word used to be offered with `.sbx` taken off, and anything without that ending was
|
||||||
|
not offered at all. That was right while the extension was what made a file reachable; now
|
||||||
|
that the shell decides by reading, hiding the files without one would hide scripts - which is
|
||||||
|
much of what a first word is.
|
||||||
|
|
||||||
Nothing typed and nothing matching both do nothing, quietly.
|
Nothing typed and nothing matching both do nothing, quietly.
|
||||||
|
|
||||||
@@ -640,22 +650,34 @@ directory's unused fields hold, the version, the free count.
|
|||||||
### Starting An Application By Name:
|
### Starting An Application By Name:
|
||||||
|
|
||||||
A word the shell has no command for is not immediately an error. Before saying so, the
|
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
|
shell looks for a file of that name and, if one is there, decides what to do with it by
|
||||||
one is there loads it and starts it exactly as `load` and `run` would. Whatever followed
|
what is inside it. Whatever followed the word reaches the program through `osArgument`, the
|
||||||
the word reaches the program through `osArgument`, the same way and by the same route as
|
same way and by the same route as whatever follows `run`.
|
||||||
whatever follows `run`.
|
|
||||||
|
|
||||||
Three properties of this are deliberate:
|
**The shell runs what it reads.** A file beginning `SBEX` is loaded and started exactly as
|
||||||
|
`load` and `run` would; a file beginning `#!` is read as lines exactly as `do` would. The
|
||||||
|
loader already refuses anything that is not `SBEX` and the script reader already refuses
|
||||||
|
anything without the shebang, so between them the two kinds of runnable thing turn each
|
||||||
|
other away and neither has to know the other exists. **The name says nothing about which
|
||||||
|
happened**, which is what makes `.sbx` a convention rather than a rule.
|
||||||
|
|
||||||
|
Four properties of this are deliberate:
|
||||||
|
|
||||||
**Built-in commands are tried first and always win.** The search happens only after the
|
**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`.
|
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
|
The commands that are worth trusting when the disk is the thing being doubted stay
|
||||||
trustworthy.
|
trustworthy.
|
||||||
|
|
||||||
**The extension is what makes a file reachable by name.** Typing `notes` looks for
|
**The word as typed is tried first, and only then the word with `.sbx` on the end.** The
|
||||||
`notes.sbx`, and typing `notes.txt` looks for `notes.txt.sbx`. A text file therefore
|
first is what makes a file reachable under the name it actually has - a script, a program
|
||||||
cannot be started by typing what it is called, whatever happens to be inside it. Only
|
somebody dropped the extension from, or a launcher. The second is what keeps every program
|
||||||
`load` reaches a file by its literal name.
|
already on a disk startable by the short name people have always typed for it. The suffix
|
||||||
|
can only ever be a second guess, so a file that is really there always wins over one that
|
||||||
|
would have to be invented, and typing `notes.txt` no longer sends the shell after a
|
||||||
|
`notes.txt.sbx` that was never going to exist.
|
||||||
|
|
||||||
|
It costs a second walk of each directory when a word is not found in it, which is the price
|
||||||
|
of the exact name being asked for first.
|
||||||
|
|
||||||
A path works here too, so `/Apps/Say hello` starts `/Apps/Say.sbx` and gives it `hello`.
|
A path works here too, so `/Apps/Say hello` starts `/Apps/Say.sbx` and gives it `hello`.
|
||||||
|
|
||||||
@@ -666,10 +688,10 @@ said where to look, so only that place is tried. Neither is stored anywhere, so
|
|||||||
nothing to configure and nothing to go stale - a search path somebody could set would need
|
nothing to configure and nothing to go stale - a search path somebody could set would need
|
||||||
somewhere to live between one boot and the next, and there is no such place yet.
|
somewhere to live between one boot and the next, and there is no such place yet.
|
||||||
|
|
||||||
**A file that is found but is broken says so.** If `notes.sbx` exists and is not an SBEX
|
**A file that is found but is neither says so.** If `notes.txt` exists and begins with
|
||||||
program, typing `notes` reports `not a program` rather than `I do not know: notes`.
|
neither `SBEX` nor `#!`, typing `notes.txt` reports `that is not a program or a script`
|
||||||
Reporting an unknown command about a file that is sitting on the disk would send somebody
|
rather than `I do not know: notes.txt`. Reporting an unknown command about a file that is
|
||||||
looking in the wrong place.
|
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.
|
Names are matched exactly, including case, because every other name on the filesystem is.
|
||||||
What limits the typed word is the buffer it is built in rather than the format: each name
|
What limits the typed word is the buffer it is built in rather than the format: each name
|
||||||
@@ -688,7 +710,7 @@ laid out in three directories:
|
|||||||
|
|
||||||
| Where | What |
|
| Where | What |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| `/Apps` | The programs. The second place the shell looks for a word it does not recognise, so anything here starts by name from anywhere on the disk. |
|
| `/Apps` | What you run. The second place the shell looks for a word it does not recognise, so anything here starts by name from anywhere on the disk - programs, and scripts too. |
|
||||||
| `/Source` | The things you name to the assembler: CosmOS itself, the assembler itself, and small programs to read. |
|
| `/Source` | The things you name to the assembler: CosmOS itself, the assembler itself, and small programs to read. |
|
||||||
| `/Lib` | The things those include. Everything here is named by an `#Include` somewhere and by nothing else, which is what makes it a library rather than a source. |
|
| `/Lib` | The things those include. Everything here is named by an `#Include` somewhere and by nothing else, which is what makes it a library rather than a source. |
|
||||||
|
|
||||||
|
|||||||
@@ -1744,12 +1744,11 @@ tabIsFirst:
|
|||||||
; The shell's own commands, only at the front of a line and only when no directory has been
|
; The shell's own commands, only at the front of a line and only when no directory has been
|
||||||
; named: nothing with a separator in it was ever going to be "dir".
|
; named: nothing with a separator in it was ever going to be "dir".
|
||||||
;
|
;
|
||||||
; And on the disk: programs at the front of a line, since that is all a first word can
|
; And on the disk: everything, wherever in the line it is. A first word used to be
|
||||||
; usefully be, and anything at all after it.
|
; narrowed to programs, back when a program was a file ending ".sbx"; now that the shell
|
||||||
|
; runs what it reads, a first word can be any file at all.
|
||||||
SETD.1 TabFirst
|
SETD.1 TabFirst
|
||||||
LDA.1
|
LDA.1
|
||||||
SETD.1 TabPrograms
|
|
||||||
STA.1
|
|
||||||
CALL tabRunSources
|
CALL tabRunSources
|
||||||
|
|
||||||
SETD.1 TabCount
|
SETD.1 TabCount
|
||||||
@@ -2261,22 +2260,15 @@ tabEntry:
|
|||||||
INCD.3
|
INCD.3
|
||||||
RSTA
|
RSTA
|
||||||
STA.3
|
STA.3
|
||||||
BRI tabEntryOffer
|
|
||||||
|
|
||||||
tabEntryFile:
|
tabEntryFile:
|
||||||
; A file. When the first word of a line is being finished it can only usefully be a
|
; A file, offered under the name it actually has - so nothing happens to it here at all.
|
||||||
; program, and the name to type for one is the name without its extension - so anything
|
; A first word used to be offered with ".sbx" taken off, and anything without that ending
|
||||||
; else is not offered at all rather than offered and useless.
|
; not offered, which was right while the extension was what made a file reachable by name.
|
||||||
SETD.1 TabPrograms
|
; THE SHELL NOW RUNS WHAT IT READS, so a script and a launcher start by name too, and
|
||||||
LDA.1
|
; hiding them would hide exactly the things a first word is most likely to be.
|
||||||
BRA tabEntryOffer
|
|
||||||
CALL tabStripSbx
|
|
||||||
BNQ tabEntryDone
|
|
||||||
|
|
||||||
tabEntryOffer:
|
|
||||||
SETD.3 TabCandidate
|
SETD.3 TabCandidate
|
||||||
CALL tabOffer
|
CALL tabOffer
|
||||||
tabEntryDone:
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
; DP0 names a string and DP1 where to put it. Copies up to what a name can be.
|
; DP0 names a string and DP1 where to put it. Copies up to what a name can be.
|
||||||
@@ -2308,62 +2300,6 @@ tabEnd:
|
|||||||
tabEndDone:
|
tabEndDone:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
; Takes ".sbx" off the end of TabCandidate. Q is zero if it was there, and one if it was not
|
|
||||||
; - which is how a file that is not a program is passed over.
|
|
||||||
tabStripSbx:
|
|
||||||
; How long the name is, counted rather than measured from a pointer, because what is
|
|
||||||
; wanted next is a NUMBER: four characters back from the end is only a place if there are
|
|
||||||
; four of them to go back over.
|
|
||||||
SETD.0 TabCandidate
|
|
||||||
RSTB
|
|
||||||
tabStripCount:
|
|
||||||
LDA.0
|
|
||||||
BRA tabStripCounted
|
|
||||||
INCD.0
|
|
||||||
INCB
|
|
||||||
BRI tabStripCount
|
|
||||||
tabStripCounted:
|
|
||||||
; The count is in B and wanted in A, and there is no instruction that moves one to the
|
|
||||||
; other: adding it to nothing is how a value crosses from B to A on this machine.
|
|
||||||
RSTA
|
|
||||||
CCF
|
|
||||||
ADD
|
|
||||||
MVQA
|
|
||||||
INIB 0d4
|
|
||||||
CCF
|
|
||||||
SUB
|
|
||||||
BRC tabStripNo ; Shorter than the extension, so it cannot end in it.
|
|
||||||
MVQA
|
|
||||||
SETD.3 TabCandidate
|
|
||||||
DPUA.3 ; Four from the end, which is where the extension would begin.
|
|
||||||
|
|
||||||
SETD.0 SbxText
|
|
||||||
tabStripMatch:
|
|
||||||
LDA.0
|
|
||||||
BRA tabStripYes
|
|
||||||
LDB.3
|
|
||||||
XOR
|
|
||||||
BNQ tabStripNo
|
|
||||||
INCD.0
|
|
||||||
INCD.3
|
|
||||||
BRI tabStripMatch
|
|
||||||
tabStripYes:
|
|
||||||
; It ended in the extension, so the name to type is what comes before it. DP3 was left on
|
|
||||||
; the zero by the comparison, so four back is where the dot was.
|
|
||||||
INIA 0d4
|
|
||||||
DPDA.3
|
|
||||||
RSTA
|
|
||||||
STA.3
|
|
||||||
RSTB
|
|
||||||
CCF
|
|
||||||
ADD ; Q is zero: it is a program.
|
|
||||||
RET
|
|
||||||
tabStripNo:
|
|
||||||
INIA 0x01
|
|
||||||
RSTB
|
|
||||||
CCF
|
|
||||||
ADD ; Q is one: it is not.
|
|
||||||
RET
|
|
||||||
|
|
||||||
; ---- The shell's own words ----
|
; ---- The shell's own words ----
|
||||||
;
|
;
|
||||||
@@ -3501,10 +3437,25 @@ promptUnknown:
|
|||||||
STA.0
|
STA.0
|
||||||
|
|
||||||
promptSearch:
|
promptSearch:
|
||||||
|
; ---- The name as typed, and only then the name with ".sbx" on it ----
|
||||||
|
;
|
||||||
|
; The exact word first is what makes a file reachable under the name it actually has: a
|
||||||
|
; script, a launcher, or a program somebody dropped the extension from. The word with the
|
||||||
|
; extension after it is what keeps every program already on a disk startable by the short
|
||||||
|
; name people have always typed for it.
|
||||||
|
;
|
||||||
|
; THE SUFFIX CAN ONLY EVER BE A SECOND GUESS. A file that is really there always wins over
|
||||||
|
; one that would have to be invented, so "notes.txt" stops sending the shell after a
|
||||||
|
; notes.txt.sbx that was never going to exist.
|
||||||
|
RSTA
|
||||||
|
SETD.0 NameSuffix
|
||||||
|
STA.0
|
||||||
|
|
||||||
|
promptSearchName:
|
||||||
CALL nameProgram
|
CALL nameProgram
|
||||||
SETD.0 NameOk
|
SETD.0 NameOk
|
||||||
LDA.0
|
LDA.0
|
||||||
BRA promptElsewhere ; Too long to be a path, so it is not the name of one.
|
BRA promptNextName ; Too long to be a path, so it is not the name of one.
|
||||||
|
|
||||||
CALL loadProgram
|
CALL loadProgram
|
||||||
SETD.0 LoadStatus
|
SETD.0 LoadStatus
|
||||||
@@ -3526,6 +3477,18 @@ promptNotLoaded:
|
|||||||
SETD.0 LoadStatus
|
SETD.0 LoadStatus
|
||||||
LDA.0
|
LDA.0
|
||||||
|
|
||||||
|
; ---- Not a program is not the end of it ----
|
||||||
|
;
|
||||||
|
; The file is there and it does not say SBEX. A script says what it is on its own first
|
||||||
|
; line, so the thing to do is read that rather than decide from the name that this could
|
||||||
|
; never have been runnable. THE SHELL RUNS WHAT IT READS, which is the whole point: the
|
||||||
|
; loader turns away anything that is not SBEX and scriptOpen turns away anything without
|
||||||
|
; the shebang, and between them nothing has to know what an extension means.
|
||||||
|
INIB 0d4
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BRQ promptAsScript
|
||||||
|
|
||||||
; No file of that name is not a fault. It is the ordinary case of a word this shell does
|
; 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 the only answer worth looking somewhere else for. Anything else
|
; not know, and it is the only answer worth looking somewhere else for. Anything else
|
||||||
; means a file of that name IS there and something is wrong with it, and answering
|
; means a file of that name IS there and something is wrong with it, and answering
|
||||||
@@ -3536,6 +3499,52 @@ promptNotLoaded:
|
|||||||
SUB
|
SUB
|
||||||
BNQ loadFailed
|
BNQ loadFailed
|
||||||
|
|
||||||
|
promptNextName:
|
||||||
|
; Nothing of that name in this place. The same place with the extension on, and then the
|
||||||
|
; next place.
|
||||||
|
SETD.0 NameSuffix
|
||||||
|
LDA.0
|
||||||
|
BNA promptElsewhere
|
||||||
|
INCA
|
||||||
|
STA.0
|
||||||
|
BRI promptSearchName
|
||||||
|
|
||||||
|
promptAsScript:
|
||||||
|
; ---- The drive goes back before a script opens ----
|
||||||
|
;
|
||||||
|
; The same handing back that a loaded program gets, and here it has to happen BEFORE the
|
||||||
|
; file is opened rather than after: a program is wholly in memory by then and a script is
|
||||||
|
; read a block at a time as it runs, so the lines in it must run on the disk the person was
|
||||||
|
; standing on. The name itself still says where the script lives, and reading it does not
|
||||||
|
; move anybody - see scriptKeepDrive.
|
||||||
|
SETD.0 SearchDrive
|
||||||
|
LDA.0
|
||||||
|
CALL sbfsUse
|
||||||
|
|
||||||
|
SETD.0 ProgramName
|
||||||
|
CALL scriptOpen
|
||||||
|
BRQ prompt ; It is open, and the next line read will come from it.
|
||||||
|
|
||||||
|
; Which of the two went wrong. There is a file, so "there is no such file" cannot happen.
|
||||||
|
MVQA
|
||||||
|
INIB 0x02
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BRQ promptNotRunnable
|
||||||
|
SETD.0 ScriptTooDeep
|
||||||
|
BRI fileComplain
|
||||||
|
|
||||||
|
promptNotRunnable:
|
||||||
|
; A file of that name IS there, and it is neither kind of runnable thing. Saying "I do not
|
||||||
|
; know" about it would send somebody looking for a file that is sitting right in front of
|
||||||
|
; them; what is wrong is the file, not the word.
|
||||||
|
SETD.0 NotRunnable
|
||||||
|
CALL printString
|
||||||
|
SETD.0 CommandLine
|
||||||
|
CALL printString
|
||||||
|
CALL newLine
|
||||||
|
BRI commandFailed
|
||||||
|
|
||||||
promptElsewhere:
|
promptElsewhere:
|
||||||
; Was that the last place there is?
|
; Was that the last place there is?
|
||||||
SETD.0 NamePrefix
|
SETD.0 NamePrefix
|
||||||
@@ -3814,13 +3823,18 @@ widthDone:
|
|||||||
|
|
||||||
; ---- Making a file name out of a typed word ----
|
; ---- 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
|
; Turns what was typed into the name of a file to go and look for. Which place to look in is
|
||||||
; unless it is already there, so that "Snake" and "Snake.sbx" both find the same file.
|
; NamePrefix, and whether to put ".sbx" on the end is NameSuffix - the search calls this once
|
||||||
|
; for each combination and the two answers are two different files to go and ask about.
|
||||||
;
|
;
|
||||||
; THE EXTENSION IS WHAT MAKES A FILE REACHABLE BY NAME. Typing "notes" looks for notes.sbx
|
; THE EXTENSION USED TO BE WHAT MADE A FILE REACHABLE BY NAME. It went on unconditionally, so
|
||||||
; and typing "notes.txt" looks for notes.txt.sbx, so a text file cannot be started by
|
; typing "notes" looked for notes.sbx and typing "notes.txt" looked for notes.txt.sbx, and no
|
||||||
; typing what it is called, whatever is inside it. Only load reaches a file by its whole
|
; text file, script or launcher could be started by typing what it is called. Now the word as
|
||||||
; name, which is why the monitor can still put any file at all in front of itself.
|
; typed is tried first and the extension is only a fallback for the programs that carry one.
|
||||||
|
;
|
||||||
|
; A word that already ends in ".sbx" is refused on the suffix pass rather than named twice:
|
||||||
|
; the exact pass has been there and looked, and asking the disk the same question again is a
|
||||||
|
; walk of a directory for an answer already known.
|
||||||
;
|
;
|
||||||
; NameOk is one if there is a path in ProgramName and zero if the word could not be made
|
; NameOk is one if there is a path in ProgramName and zero if the word could not be made
|
||||||
; into one. What limits it is the buffer, not the format: each NAME along a path is still
|
; into one. What limits it is the buffer, not the format: each NAME along a path is still
|
||||||
@@ -3879,8 +3893,16 @@ nameCopied:
|
|||||||
SETD.0 NameLeft
|
SETD.0 NameLeft
|
||||||
STB.0
|
STB.0
|
||||||
|
|
||||||
|
; The word exactly as typed, which is the first thing asked for and the only thing asked
|
||||||
|
; for when the extension is not wanted.
|
||||||
|
SETD.0 NameSuffix
|
||||||
|
LDA.0
|
||||||
|
BRA nameMade
|
||||||
|
|
||||||
; Only a word of four characters or more can already end in ".sbx". Stepping back four to
|
; 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.
|
; look at a shorter one would read whatever happens to sit in front of the buffer.
|
||||||
|
SETD.0 NameLeft
|
||||||
|
LDB.0
|
||||||
INIA 0d55
|
INIA 0d55
|
||||||
CCF
|
CCF
|
||||||
SUB
|
SUB
|
||||||
@@ -3892,7 +3914,7 @@ nameCopied:
|
|||||||
SETD.0 SbxSuffix
|
SETD.0 SbxSuffix
|
||||||
nameSuffixSame:
|
nameSuffixSame:
|
||||||
LDA.0
|
LDA.0
|
||||||
BRA nameMade ; The suffix ran out with all of it matched.
|
BRA nameDone ; All of it matched, so the exact pass already asked for this.
|
||||||
LDB.2
|
LDB.2
|
||||||
CCF
|
CCF
|
||||||
SUB
|
SUB
|
||||||
@@ -7513,6 +7535,10 @@ ScriptStopped:
|
|||||||
"stopped: that line did not work"
|
"stopped: that line did not work"
|
||||||
Unknown:
|
Unknown:
|
||||||
"I do not know: "
|
"I do not know: "
|
||||||
|
; A file of that name is there and it is neither a program nor a script, which is a different
|
||||||
|
; thing from a word this shell does not know and reads differently to whoever typed it.
|
||||||
|
NotRunnable:
|
||||||
|
"that is not a program or a script: "
|
||||||
Farewell:
|
Farewell:
|
||||||
"halted"
|
"halted"
|
||||||
DirectoryText:
|
DirectoryText:
|
||||||
@@ -7594,8 +7620,8 @@ DataWord:
|
|||||||
ExecMagic:
|
ExecMagic:
|
||||||
"SBEX"
|
"SBEX"
|
||||||
|
|
||||||
; What every program on the disk is called, and the four characters that make one
|
; What every program on the disk is called. It is a convention now rather than a rule: the
|
||||||
; reachable by typing its name.
|
; shell tries the word as typed first and only puts these four characters on afterwards.
|
||||||
SbxSuffix:
|
SbxSuffix:
|
||||||
".sbx"
|
".sbx"
|
||||||
LoadWhat:
|
LoadWhat:
|
||||||
@@ -7781,8 +7807,6 @@ ForName:
|
|||||||
ShellNameCount:
|
ShellNameCount:
|
||||||
0d22
|
0d22
|
||||||
|
|
||||||
SbxText:
|
|
||||||
".sbx"
|
|
||||||
AppsPath:
|
AppsPath:
|
||||||
"/Apps"
|
"/Apps"
|
||||||
VarNoSuch:
|
VarNoSuch:
|
||||||
@@ -7864,6 +7888,9 @@ NameOk:
|
|||||||
0x00
|
0x00
|
||||||
NamePrefix:
|
NamePrefix:
|
||||||
0x00
|
0x00
|
||||||
|
; Nought for the word exactly as typed, one for the word with ".sbx" put on the end.
|
||||||
|
NameSuffix:
|
||||||
|
0x00
|
||||||
NameLeft:
|
NameLeft:
|
||||||
0x00
|
0x00
|
||||||
LoadedEntry:
|
LoadedEntry:
|
||||||
@@ -8206,8 +8233,6 @@ TabCopyAt:
|
|||||||
0x00
|
0x00
|
||||||
TabFirst:
|
TabFirst:
|
||||||
0x00
|
0x00
|
||||||
TabPrograms:
|
|
||||||
0x00
|
|
||||||
; Whether the walk is looking for the answer or showing what the answers were.
|
; Whether the walk is looking for the answer or showing what the answers were.
|
||||||
TabShowing:
|
TabShowing:
|
||||||
0x00
|
0x00
|
||||||
|
|||||||
@@ -11,15 +11,27 @@ finished
|
|||||||
> dir
|
> dir
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
dir.sbx 156
|
dir.sbx 156
|
||||||
|
Greet 156
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
notes.sbx 21
|
notes.sbx 21
|
||||||
4 files
|
hello.sh 38
|
||||||
|
Apps <dir>
|
||||||
|
6 files, 1 directory
|
||||||
|
> Greet a program with no extension
|
||||||
|
it says: a program with no extension
|
||||||
|
finished
|
||||||
|
> hello.sh
|
||||||
|
> echo a script, started by its name
|
||||||
|
a script, started by its name
|
||||||
|
> away.sh
|
||||||
|
> echo a script from the system place
|
||||||
|
a script from the system place
|
||||||
> notes
|
> notes
|
||||||
not a program
|
that is not a program or a script: notes
|
||||||
> notes.sbx
|
> notes.sbx
|
||||||
not a program
|
that is not a program or a script: notes.sbx
|
||||||
> notes.txt
|
> notes.txt
|
||||||
I do not know: notes.txt
|
that is not a program or a script: notes.txt
|
||||||
> nosuchprogram
|
> nosuchprogram
|
||||||
I do not know: nosuchprogram
|
I do not know: nosuchprogram
|
||||||
> abcdefghijklmnopqr
|
> abcdefghijklmnopqr
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
CosmOS
|
CosmOS
|
||||||
> Cr[2;3HCrash [2;9Hzz
|
> Cr[2;3HCrash.sbx [2;13Hzz
|
||||||
Crash opcode | service | bank | device | blind
|
Crash opcode | service | bank | device | blind
|
||||||
finished
|
finished
|
||||||
> Sa[5;3HSay[5;6Hzz
|
> Sa[5;3HSay.sbx[5;10Hzz
|
||||||
I do not know: Sayzz
|
I do not know: Say.sbxzz
|
||||||
> cd Ap[7;3Hcd Apps/[7;11H
|
> cd Ap[7;3Hcd Apps/[7;11H
|
||||||
/Apps> echo where am I
|
/Apps> echo where am I
|
||||||
where am I
|
where am I
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ Say hello there
|
|||||||
Say.sbx spelled out in full
|
Say.sbx spelled out in full
|
||||||
run once more
|
run once more
|
||||||
dir
|
dir
|
||||||
|
Greet a program with no extension
|
||||||
|
hello.sh
|
||||||
|
away.sh
|
||||||
notes
|
notes
|
||||||
notes.sbx
|
notes.sbx
|
||||||
notes.txt
|
notes.txt
|
||||||
|
|||||||
+16
-3
@@ -487,8 +487,8 @@ printf 'and these are the very different notes in B\n' > notesB.txt
|
|||||||
"$ROOT/Programs/CosmOS/Apps/Wander.asm" -o "$WORK/Wander.sbx" >/dev/null
|
"$ROOT/Programs/CosmOS/Apps/Wander.asm" -o "$WORK/Wander.sbx" >/dev/null
|
||||||
"$TOOL" put "$DISKS/cwd.img" "$WORK/Wander.sbx" /Apps/Wander.sbx >/dev/null
|
"$TOOL" put "$DISKS/cwd.img" "$WORK/Wander.sbx" /Apps/Wander.sbx >/dev/null
|
||||||
|
|
||||||
# A disk for invoking a program by typing its name. Four files, each there to say one
|
# A disk for invoking a program by typing its name. Every file on it is there to say one
|
||||||
# thing about how a typed word turns into a file name.
|
# thing about how a typed word turns into a file that runs.
|
||||||
#
|
#
|
||||||
# dir.sbx is a working program under the name of a built-in command, which is the only way
|
# dir.sbx is a working program under the name of a built-in command, which is the only way
|
||||||
# to check that the built-ins really are tried first. If the search ever moved ahead of the
|
# to check that the built-ins really are tried first. If the search ever moved ahead of the
|
||||||
@@ -496,15 +496,28 @@ printf 'and these are the very different notes in B\n' > notesB.txt
|
|||||||
#
|
#
|
||||||
# notes.sbx is text under a program's name, so that a file that IS found and IS NOT a
|
# notes.sbx is text under a program's name, so that a file that IS found and IS NOT a
|
||||||
# program can be told apart from a word that names nothing. notes.txt is the same text
|
# program can be told apart from a word that names nothing. notes.txt is the same text
|
||||||
# under its own name, which no typed word can reach: "notes.txt" looks for notes.txt.sbx.
|
# under its own name - which the shell could not reach at all until it began trying the
|
||||||
|
# word as typed, because "notes.txt" only ever looked for notes.txt.sbx.
|
||||||
|
#
|
||||||
|
# Greet is a program with NO extension, and hello.sh is a script. Neither could be started
|
||||||
|
# by typing its name before the shell decided what to run by reading it, and between them
|
||||||
|
# they are the whole of that claim: SBEX loads, #! is read as lines, and the name says
|
||||||
|
# nothing about which happened. /Apps/away.sh is the same for a script found somewhere
|
||||||
|
# other than where you are standing.
|
||||||
"$TOOL" format "$DISKS/invoke.img" 64 2 >/dev/null
|
"$TOOL" format "$DISKS/invoke.img" 64 2 >/dev/null
|
||||||
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
|
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
|
||||||
"$ROOT/Programs/CosmOS/Apps/Say.asm" -o "$WORK/Say.sbx" >/dev/null
|
"$ROOT/Programs/CosmOS/Apps/Say.asm" -o "$WORK/Say.sbx" >/dev/null
|
||||||
"$TOOL" put "$DISKS/invoke.img" "$WORK/Say.sbx" >/dev/null
|
"$TOOL" put "$DISKS/invoke.img" "$WORK/Say.sbx" >/dev/null
|
||||||
"$TOOL" put "$DISKS/invoke.img" "$WORK/Say.sbx" dir.sbx >/dev/null
|
"$TOOL" put "$DISKS/invoke.img" "$WORK/Say.sbx" dir.sbx >/dev/null
|
||||||
|
"$TOOL" put "$DISKS/invoke.img" "$WORK/Say.sbx" Greet >/dev/null
|
||||||
printf 'this is not a program' > notes.txt
|
printf 'this is not a program' > notes.txt
|
||||||
"$TOOL" put "$DISKS/invoke.img" notes.txt >/dev/null
|
"$TOOL" put "$DISKS/invoke.img" notes.txt >/dev/null
|
||||||
"$TOOL" put "$DISKS/invoke.img" notes.txt notes.sbx >/dev/null
|
"$TOOL" put "$DISKS/invoke.img" notes.txt notes.sbx >/dev/null
|
||||||
|
printf '#!\necho a script, started by its name\n' > "$WORK/hello.sh"
|
||||||
|
"$TOOL" put "$DISKS/invoke.img" "$WORK/hello.sh" hello.sh >/dev/null
|
||||||
|
"$TOOL" mkdir "$DISKS/invoke.img" /Apps >/dev/null
|
||||||
|
printf '#!\necho a script from the system place\n' > "$WORK/away.sh"
|
||||||
|
"$TOOL" put "$DISKS/invoke.img" "$WORK/away.sh" /Apps/away.sh >/dev/null
|
||||||
|
|
||||||
# A disk for the assembler that runs on the machine. It holds a source file and the two
|
# A disk for the assembler that runs on the machine. It holds a source file and the two
|
||||||
# programs that check the front end - the reader on its own and the tokenizer on its own -
|
# programs that check the front end - the reader on its own and the tokenizer on its own -
|
||||||
|
|||||||
+9
-2
@@ -1690,8 +1690,15 @@ print(sum(1 for o in range(0, len(px), 3) if px[o:o + 3] == moon))
|
|||||||
# What is checked is that it is HIGHER LATER: two captures, the second further on, and the
|
# What is checked is that it is HIGHER LATER: two captures, the second further on, and the
|
||||||
# lander nearer the top in the second. A thruster that only fired once for a held button
|
# lander nearer the top in the second. A thruster that only fired once for a held button
|
||||||
# would let it fall between them instead, which is exactly what the console does.
|
# would let it fall between them instead, which is exactly what the console does.
|
||||||
|
#
|
||||||
|
# ONE AND 1.8 MILLION, and they were 800 thousand and 1.6 million. The shell tries a typed
|
||||||
|
# word as the name of a file before it tries it with ".sbx" on the end, so starting Lander
|
||||||
|
# now walks four names where it walked two, and at 800 thousand the program had not drawn
|
||||||
|
# yet - which reads as row -1 and fails, correctly, for a reason that has nothing to do with
|
||||||
|
# thrusters. The gap between the two captures is what the check is made of, and it is the
|
||||||
|
# same gap.
|
||||||
python3 -c "open('$BUILD/lander.pad','wb').write(b'\x00' * 40 + b'\x08' * 400)"
|
python3 -c "open('$BUILD/lander.pad','wb').write(b'\x00' * 40 + b'\x08' * 400)"
|
||||||
for when in 800000 1600000; do
|
for when in 1000000 1800000; do
|
||||||
timeout 30 "$EMU" --fast --cycles $when --keyboard "$BUILD/lander.keys" \
|
timeout 30 "$EMU" --fast --cycles $when --keyboard "$BUILD/lander.keys" \
|
||||||
--pad "$BUILD/lander.pad" --screen "$BUILD/held$when.ppm" \
|
--pad "$BUILD/lander.pad" --screen "$BUILD/held$when.ppm" \
|
||||||
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
||||||
@@ -1705,7 +1712,7 @@ def top(path):
|
|||||||
ship = bytes.fromhex('d8c048')
|
ship = bytes.fromhex('d8c048')
|
||||||
ys = [i // 320 for i in range(len(px) // 3) if px[i * 3:i * 3 + 3] == ship]
|
ys = [i // 320 for i in range(len(px) // 3) if px[i * 3:i * 3 + 3] == ship]
|
||||||
return min(ys) if ys else -1
|
return min(ys) if ys else -1
|
||||||
print(top('$BUILD/held800000.ppm'), top('$BUILD/held1600000.ppm'))
|
print(top('$BUILD/held1000000.ppm'), top('$BUILD/held1800000.ppm'))
|
||||||
" 2>/dev/null || echo "-1 -1")
|
" 2>/dev/null || echo "-1 -1")
|
||||||
EOT
|
EOT
|
||||||
[ "$EARLY" -gt 0 ] && [ "$LATE" -gt 0 ] && [ "$LATE" -lt "$EARLY" ] \
|
[ "$EARLY" -gt 0 ] && [ "$LATE" -gt 0 ] && [ "$LATE" -lt "$EARLY" ] \
|
||||||
|
|||||||
Reference in New Issue
Block a user