Tab reaches the disk
Paths and programs, which is the half that makes it worth having. The first word of a line is a command or a PROGRAM, offered under the name somebody would type - the extension taken off - and anything after it is a file, offered as it really is. A separator anywhere in the word says which directory to look in. 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. The answer ending in one is also what stops a space being added, so that is one test rather than a flag. PROGRAMS ARE LOOKED FOR WHERE THE SHELL WOULD LOOK to run one: where you are, /Apps on the disk you are on, and /Apps on drive 0. Offering something the shell would not find would be finishing a word into a thing that then does not work. Drive 0's is skipped when that is already the drive, or every program in it would be offered twice and nothing would ever be the only match. Walking somebody else's directory means standing in it, which is the only way to walk one here, so where the person was and which drive they were on are put down first and restored whatever happens. Three bugs, all found by running it: THE DIRECTORY TEST WAS INVERTED. dir asks the same question the same way round four hundred lines further up, which is what made it obvious once looked at. THE /Apps WALK OVERWROTE THE TYPED PATH. The whole search runs a second time to list the matches, and by then TabDir said "/Apps" - so a word that had named nowhere went looking in the wrong place and listed nothing at all. Two ways into the walk now, and the typed path is never written over. AND LISTING ONLY KNEW ABOUT COMMANDS, because it was a second copy of the walk. It is the same walk with a flag now: finding the answer and showing the matches are the same question asked twice. Also cosmosMonitor, which had been RE-BLESSED INTO MEANINGLESSNESS by the wall move. It disassembles a loaded program, at an address the input names - and that address moved a page while the recording was simply re-recorded to whatever came out, which was a page of zeroes. It is pointed at 5000 again. 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
bb065fe221
commit
3c76934a9a
@@ -315,14 +315,31 @@ should be on it, and the shell decides.
|
|||||||
|
|
||||||
### Finishing A Word:
|
### Finishing A Word:
|
||||||
|
|
||||||
Tab finishes the **first** word of a line against the shell's own commands. One match goes in
|
Tab finishes the word being typed. One match goes in with a space after it, because a word
|
||||||
with a space after it, because a word that can only be one thing is finished. Several are
|
that can only be one thing is finished. Several are folded into their longest common prefix
|
||||||
folded into their longest common prefix and that goes in, which is the most that can be said
|
and that goes in, which is the most that can be said without guessing which was meant - and
|
||||||
without guessing which was meant - and if that adds nothing, because what is typed is already
|
if that adds nothing, because what is typed is already as far as they all agree, the matches
|
||||||
as far as they all agree, the matches are listed and the line put back underneath.
|
are listed and the line put back underneath.
|
||||||
|
|
||||||
Nothing typed and nothing matching both do nothing, quietly. Finishing an argument rather
|
**What it can be depends on where in the line it is.** The first word is a command or a
|
||||||
than a command is not built yet.
|
program; anything after it is a file.
|
||||||
|
|
||||||
|
| Where | What is offered |
|
||||||
|
| -- | -- |
|
||||||
|
| The first word | the fifteen commands, and programs - under the name you would type, with the extension taken off |
|
||||||
|
| After it | anything on the disk, under its real name |
|
||||||
|
| 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
|
||||||
|
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
|
||||||
|
are, `/Apps` on the disk you are on, and `/Apps` on drive 0. Offering something the shell
|
||||||
|
would not find would be finishing a word into a thing that then does not work. A program that
|
||||||
|
is in two of those places is offered twice and so is never the only match, which costs it the
|
||||||
|
space after it - the shell is comparing names, not deciding which file it would have run.
|
||||||
|
|
||||||
|
Nothing typed and nothing matching both do nothing, quietly.
|
||||||
|
|
||||||
**This is the same wall the history was behind.** A shell that never sees a keystroke has no
|
**This is the same wall the history was behind.** A shell that never sees a keystroke has no
|
||||||
moment at which somebody has typed half a word - the terminal hands over finished lines - so
|
moment at which somebody has typed half a word - the terminal hands over finished lines - so
|
||||||
|
|||||||
@@ -1538,7 +1538,7 @@ tabComplete:
|
|||||||
tabBack:
|
tabBack:
|
||||||
SETD.1 TabWordAt
|
SETD.1 TabWordAt
|
||||||
LDA.1
|
LDA.1
|
||||||
BRA tabIsFirst ; The start of the line is the start of the word, and of the line.
|
BRA tabAtLineStart ; The start of the line is the start of the word, and of the line.
|
||||||
DECA
|
DECA
|
||||||
CALL tabCharAt
|
CALL tabCharAt
|
||||||
MVQA
|
MVQA
|
||||||
@@ -1551,10 +1551,19 @@ tabBack:
|
|||||||
STA.1
|
STA.1
|
||||||
BRI tabBack
|
BRI tabBack
|
||||||
|
|
||||||
|
tabAtLineStart:
|
||||||
|
INIA 0x01
|
||||||
|
SETD.1 TabFirst
|
||||||
|
STA.1
|
||||||
|
BRI tabIsFirst
|
||||||
|
|
||||||
tabFoundStart:
|
tabFoundStart:
|
||||||
; There is a space behind the word, so something may be in front of that space. Only a run
|
; There is a space behind the word, so something may be in front of that space. Only a run
|
||||||
; of spaces means this is still the first word; anything else is an argument, and finishing
|
; of spaces means this is still the first word - and which word it is decides what the word
|
||||||
; one of those is not built yet.
|
; could BE: a command or a program at the front of a line, a file anywhere after it.
|
||||||
|
INIA 0x01
|
||||||
|
SETD.1 TabFirst
|
||||||
|
STA.1
|
||||||
SETD.1 TabWordAt
|
SETD.1 TabWordAt
|
||||||
LDA.1
|
LDA.1
|
||||||
SETD.1 TabLeft
|
SETD.1 TabLeft
|
||||||
@@ -1569,8 +1578,10 @@ tabFirstCheck:
|
|||||||
MVQA
|
MVQA
|
||||||
INIB 0x20
|
INIB 0x20
|
||||||
XOR
|
XOR
|
||||||
BNQ tabDone ; Not a space, so a word came before this one.
|
BRQ tabFirstCheck
|
||||||
BRI tabFirstCheck
|
RSTA
|
||||||
|
SETD.1 TabFirst
|
||||||
|
STA.1 ; A word came before this one, so this is an argument.
|
||||||
|
|
||||||
tabIsFirst:
|
tabIsFirst:
|
||||||
; How much of it is typed. Nothing at all is not a question anybody asked - it would offer
|
; How much of it is typed. Nothing at all is not a question anybody asked - it would offer
|
||||||
@@ -1592,7 +1603,22 @@ tabIsFirst:
|
|||||||
SETD.1 TabBestLen
|
SETD.1 TabBestLen
|
||||||
STA.1
|
STA.1
|
||||||
|
|
||||||
CALL tabTryNames
|
; A path in the word says which directory to look in, and narrows what is being matched to
|
||||||
|
; the part after the last separator.
|
||||||
|
CALL tabSplit
|
||||||
|
|
||||||
|
; ---- What this word could be ----
|
||||||
|
;
|
||||||
|
; 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".
|
||||||
|
;
|
||||||
|
; And on the disk: programs at the front of a line, since that is all a first word can
|
||||||
|
; usefully be, and anything at all after it.
|
||||||
|
SETD.1 TabFirst
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabPrograms
|
||||||
|
STA.1
|
||||||
|
CALL tabRunSources
|
||||||
|
|
||||||
SETD.1 TabCount
|
SETD.1 TabCount
|
||||||
LDA.1
|
LDA.1
|
||||||
@@ -1641,11 +1667,24 @@ tabPutDone:
|
|||||||
XOR
|
XOR
|
||||||
BNQ tabAmbiguous
|
BNQ tabAmbiguous
|
||||||
|
|
||||||
; Only one thing it can be, so it is finished and a space says so.
|
; Only one thing it can be, so it is finished and a space says so - unless it is a
|
||||||
|
; directory, which answered with a separator on the end and is somewhere to carry on typing
|
||||||
|
; rather than something to have finished.
|
||||||
|
SETD.3 TabBest
|
||||||
|
SETD.1 TabBestLen
|
||||||
|
LDA.1
|
||||||
|
DECA
|
||||||
|
DPUA.3
|
||||||
|
LDA.3
|
||||||
|
INIB 0x2F
|
||||||
|
XOR
|
||||||
|
BRQ tabSaidDirectory
|
||||||
|
|
||||||
INIA 0x20
|
INIA 0x20
|
||||||
SETD.1 EditChar
|
SETD.1 EditChar
|
||||||
STA.1
|
STA.1
|
||||||
CALL editPut
|
CALL editPut
|
||||||
|
tabSaidDirectory:
|
||||||
CALL editRedraw
|
CALL editRedraw
|
||||||
BRI tabDone
|
BRI tabDone
|
||||||
|
|
||||||
@@ -1663,6 +1702,20 @@ tabAmbiguous:
|
|||||||
tabDone:
|
tabDone:
|
||||||
BRI editKey
|
BRI editKey
|
||||||
|
|
||||||
|
; Everywhere a candidate can come from, in the order they are tried. Run once to find the
|
||||||
|
; answer and again to show the matches, which is why it is a routine and not a run of code.
|
||||||
|
tabRunSources:
|
||||||
|
SETD.1 TabFirst
|
||||||
|
LDA.1
|
||||||
|
BRA tabNoNames
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDA.1
|
||||||
|
BNA tabNoNames
|
||||||
|
CALL tabTryNames
|
||||||
|
tabNoNames:
|
||||||
|
CALL tabTryFiles
|
||||||
|
RET
|
||||||
|
|
||||||
; A holds an offset into the line. Q is the character there.
|
; A holds an offset into the line. Q is the character there.
|
||||||
tabCharAt:
|
tabCharAt:
|
||||||
SETD.1 EditBase
|
SETD.1 EditBase
|
||||||
@@ -1725,6 +1778,15 @@ tabOfferMatch:
|
|||||||
BRI tabOfferMatch
|
BRI tabOfferMatch
|
||||||
|
|
||||||
tabOfferTake:
|
tabOfferTake:
|
||||||
|
; ---- Folded in, or shown ----
|
||||||
|
;
|
||||||
|
; The same walk answers both questions, because they are the same question asked twice:
|
||||||
|
; what matches. Listing used to be a second copy of the walk that knew only about the
|
||||||
|
; shell's own words, so the files it should have been showing were never there.
|
||||||
|
SETD.1 TabShowing
|
||||||
|
LDA.1
|
||||||
|
BNA tabOfferPrint
|
||||||
|
|
||||||
; The first match is the answer. Every one after it cuts the answer back to where the two
|
; The first match is the answer. Every one after it cuts the answer back to where the two
|
||||||
; stop agreeing, which is all that can be said without guessing which was meant.
|
; stop agreeing, which is all that can be said without guessing which was meant.
|
||||||
SETD.1 TabCount
|
SETD.1 TabCount
|
||||||
@@ -1738,6 +1800,15 @@ tabOfferTake:
|
|||||||
BRI tabOfferSkip
|
BRI tabOfferSkip
|
||||||
tabOfferFirst:
|
tabOfferFirst:
|
||||||
CALL tabTake
|
CALL tabTake
|
||||||
|
BRI tabOfferSkip
|
||||||
|
|
||||||
|
tabOfferPrint:
|
||||||
|
SETD.1 TabStart
|
||||||
|
LDD.0.1
|
||||||
|
CALL printString
|
||||||
|
INIA 0x20
|
||||||
|
OUTA 0x00
|
||||||
|
OUTA 0x00 ; Two spaces between them, and A already holds one.
|
||||||
|
|
||||||
tabOfferSkip:
|
tabOfferSkip:
|
||||||
; Past the end of this candidate, from wherever the comparison stopped.
|
; Past the end of this candidate, from wherever the comparison stopped.
|
||||||
@@ -1813,6 +1884,355 @@ tabNarrowCut:
|
|||||||
tabNarrowDone:
|
tabNarrowDone:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
|
||||||
|
; ---- Splitting the word at its last separator ----
|
||||||
|
;
|
||||||
|
; "Apps/Sn" is a directory to look in and a name to match, and everything downstream depends
|
||||||
|
; on getting that split right. What comes back is TabDir holding the directory part - empty
|
||||||
|
; when there is no separator, meaning where the machine already is - and TabWordAt and
|
||||||
|
; TabWordLen narrowed to the name part, so that matching and inserting go on working on the
|
||||||
|
; part of the word they were always about.
|
||||||
|
tabSplit:
|
||||||
|
RSTA
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
STA.1
|
||||||
|
|
||||||
|
; Backwards, so the LAST separator is the one found.
|
||||||
|
SETD.1 TabWordLen
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabAt
|
||||||
|
STA.1
|
||||||
|
tabSplitBack:
|
||||||
|
SETD.1 TabAt
|
||||||
|
LDA.1
|
||||||
|
BRA tabSplitNone ; No separator anywhere in it.
|
||||||
|
DECA
|
||||||
|
STA.1
|
||||||
|
SETD.1 TabWordAt
|
||||||
|
LDB.1
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
MVQA
|
||||||
|
CALL tabCharAt
|
||||||
|
MVQA
|
||||||
|
INIB 0x2F
|
||||||
|
XOR
|
||||||
|
BNQ tabSplitBack
|
||||||
|
|
||||||
|
; Found one. The directory part is everything up to and including it, which is what makes
|
||||||
|
; "/Source/" and "Source/" both say what they mean.
|
||||||
|
SETD.1 TabAt
|
||||||
|
LDA.1
|
||||||
|
INCA
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
STA.1
|
||||||
|
|
||||||
|
SETD.2 TabDir
|
||||||
|
RSTA
|
||||||
|
SETD.1 TabCopyAt
|
||||||
|
STA.1
|
||||||
|
tabSplitCopy:
|
||||||
|
SETD.1 TabCopyAt
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDB.1
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BNC tabSplitCopied
|
||||||
|
SETD.1 TabWordAt
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabCopyAt
|
||||||
|
LDB.1
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
MVQA
|
||||||
|
CALL tabCharAt
|
||||||
|
MVQA
|
||||||
|
STA.2
|
||||||
|
INCD.2
|
||||||
|
SETD.1 TabCopyAt
|
||||||
|
LDA.1
|
||||||
|
INCA
|
||||||
|
STA.1
|
||||||
|
BRI tabSplitCopy
|
||||||
|
tabSplitCopied:
|
||||||
|
RSTA
|
||||||
|
STA.2 ; The zero that ends it.
|
||||||
|
|
||||||
|
; And the word being matched is what comes after the separator.
|
||||||
|
SETD.1 TabWordAt
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDB.1
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
MVQA
|
||||||
|
SETD.1 TabWordAt
|
||||||
|
STA.1
|
||||||
|
SETD.1 TabWordLen
|
||||||
|
LDA.1
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDB.1
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
MVQA
|
||||||
|
SETD.1 TabWordLen
|
||||||
|
STA.1
|
||||||
|
RET
|
||||||
|
tabSplitNone:
|
||||||
|
SETD.0 TabDir
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ---- What is on the disk ----
|
||||||
|
;
|
||||||
|
; Every entry of the directory the word names that begins with the rest of the word. A
|
||||||
|
; directory is offered with a separator after it, which says what it is and lets the next
|
||||||
|
; part be typed straight away - and, because the answer then ends in one, is also what stops
|
||||||
|
; a space being put after it.
|
||||||
|
;
|
||||||
|
; WHERE THE MACHINE IS COMES BACK. This walks somebody else's directory by standing in it,
|
||||||
|
; which is the only way to walk one here, so where they were and which drive they were on are
|
||||||
|
; put down first and restored whatever happens.
|
||||||
|
tabTryFiles:
|
||||||
|
SETD.0 DiskReady
|
||||||
|
LDA.0
|
||||||
|
BRA tabFilesNone
|
||||||
|
|
||||||
|
INA 0x24
|
||||||
|
SETD.1 TabWasDrive
|
||||||
|
STA.1
|
||||||
|
SETD.0 SbfsCwd
|
||||||
|
SETD.1 TabWasCwd
|
||||||
|
CALL sbfsCopyWord
|
||||||
|
|
||||||
|
CALL tabWalkNamed
|
||||||
|
|
||||||
|
; ---- And the places a program is looked for ----
|
||||||
|
;
|
||||||
|
; The first word of a line is a command or a program, and the shell looks for a program in
|
||||||
|
; three places: where you are, the system's own place for them on the disk you are on, and
|
||||||
|
; that same place on drive 0. Tab offers what the shell would find, or it would finish a
|
||||||
|
; word into something that then would not run.
|
||||||
|
;
|
||||||
|
; ONLY WHEN NO DIRECTORY WAS NAMED. "Apps/Sn" means that directory and nowhere else.
|
||||||
|
SETD.1 TabFirst
|
||||||
|
LDA.1
|
||||||
|
BRA tabFilesBack
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDA.1
|
||||||
|
BNA tabFilesBack
|
||||||
|
|
||||||
|
CALL tabWalkApps
|
||||||
|
|
||||||
|
; And drive 0's, unless that is the drive we are already on - in which case it is the same
|
||||||
|
; directory, and offering everything in it twice would mean nothing was ever the only
|
||||||
|
; match.
|
||||||
|
SETD.1 TabWasDrive
|
||||||
|
LDA.1
|
||||||
|
BRA tabFilesBack
|
||||||
|
RSTA
|
||||||
|
CALL sbfsUse
|
||||||
|
CALL tabWalkApps
|
||||||
|
BRI tabFilesBack
|
||||||
|
|
||||||
|
; ---- Everything in a directory, offered ----
|
||||||
|
;
|
||||||
|
; Two ways in, because there are two kinds of place to look: the one the word named, and the
|
||||||
|
; system's own place for programs. THE FIRST MUST NOT BE OVERWRITTEN BY THE SECOND - an
|
||||||
|
; earlier version wrote "/Apps" into TabDir, and since the whole walk runs a second time to
|
||||||
|
; list the matches, that second run looked in /Apps for a word which had named nowhere, and
|
||||||
|
; showed nothing at all.
|
||||||
|
;
|
||||||
|
; Where the machine stands is moved and put back by the caller, which is what makes calling
|
||||||
|
; either of these more than once safe.
|
||||||
|
tabWalkApps:
|
||||||
|
SETD.0 TabWasCwd
|
||||||
|
SETD.1 SbfsCwd
|
||||||
|
CALL sbfsCopyWord
|
||||||
|
SETD.0 AppsPath
|
||||||
|
BRI tabWalkTo
|
||||||
|
|
||||||
|
tabWalkNamed:
|
||||||
|
SETD.0 TabWasCwd
|
||||||
|
SETD.1 SbfsCwd
|
||||||
|
CALL sbfsCopyWord
|
||||||
|
|
||||||
|
SETD.1 TabDirLen
|
||||||
|
LDA.1
|
||||||
|
BRA tabFilesHere ; No directory named, so it is this one.
|
||||||
|
|
||||||
|
SETD.0 TabDir
|
||||||
|
tabWalkTo:
|
||||||
|
CALL sbfsWalk
|
||||||
|
BNQ tabWalkNothing ; No such path, and nothing to offer out of it.
|
||||||
|
|
||||||
|
; The root is not an entry, so it has no flags to ask - and it is the one place that can be
|
||||||
|
; walked to without there being anything to have asked.
|
||||||
|
SETD.0 SbfsAt
|
||||||
|
LDA.0
|
||||||
|
INCD.0
|
||||||
|
LDB.0
|
||||||
|
OR
|
||||||
|
BRQ tabFilesGo
|
||||||
|
SETD.0 SbfsFoundFlags
|
||||||
|
LDA.0
|
||||||
|
INIB 0x02
|
||||||
|
AND
|
||||||
|
BRQ tabWalkNothing ; Not a directory, so there is nothing in it.
|
||||||
|
tabFilesGo:
|
||||||
|
SETD.0 SbfsAt
|
||||||
|
SETD.1 SbfsCwd
|
||||||
|
CALL sbfsCopyWord
|
||||||
|
|
||||||
|
tabFilesHere:
|
||||||
|
CALL sbfsFirst
|
||||||
|
BRI tabFilesCheck
|
||||||
|
tabFilesStep:
|
||||||
|
CALL sbfsNext
|
||||||
|
tabFilesCheck:
|
||||||
|
BNQ tabWalkNothing
|
||||||
|
CALL tabEntry
|
||||||
|
BRI tabFilesStep
|
||||||
|
tabWalkNothing:
|
||||||
|
RET
|
||||||
|
|
||||||
|
tabFilesBack:
|
||||||
|
SETD.0 TabWasCwd
|
||||||
|
SETD.1 SbfsCwd
|
||||||
|
CALL sbfsCopyWord
|
||||||
|
SETD.1 TabWasDrive
|
||||||
|
LDA.1
|
||||||
|
CALL sbfsUse
|
||||||
|
tabFilesNone:
|
||||||
|
RET
|
||||||
|
|
||||||
|
; The entry the walk is standing on, offered under the name somebody would type for it.
|
||||||
|
tabEntry:
|
||||||
|
SETD.0 SbfsName
|
||||||
|
SETD.1 TabCandidate
|
||||||
|
CALL tabCopyName
|
||||||
|
|
||||||
|
SETD.0 SbfsFoundFlags
|
||||||
|
LDA.0
|
||||||
|
INIB 0x02
|
||||||
|
AND
|
||||||
|
BRQ tabEntryFile ; The bit SET is what says directory - see dir, which asks the
|
||||||
|
; same question the same way round.
|
||||||
|
|
||||||
|
; A directory, and the separator goes on the end of it.
|
||||||
|
SETD.3 TabCandidate
|
||||||
|
CALL tabEnd
|
||||||
|
INIA 0x2F
|
||||||
|
STA.3
|
||||||
|
INCD.3
|
||||||
|
RSTA
|
||||||
|
STA.3
|
||||||
|
BRI tabEntryOffer
|
||||||
|
|
||||||
|
tabEntryFile:
|
||||||
|
; A file. When the first word of a line is being finished it can only usefully be a
|
||||||
|
; program, and the name to type for one is the name without its extension - so anything
|
||||||
|
; else is not offered at all rather than offered and useless.
|
||||||
|
SETD.1 TabPrograms
|
||||||
|
LDA.1
|
||||||
|
BRA tabEntryOffer
|
||||||
|
CALL tabStripSbx
|
||||||
|
BNQ tabEntryDone
|
||||||
|
|
||||||
|
tabEntryOffer:
|
||||||
|
SETD.3 TabCandidate
|
||||||
|
CALL tabOffer
|
||||||
|
tabEntryDone:
|
||||||
|
RET
|
||||||
|
|
||||||
|
; DP0 names a string and DP1 where to put it. Copies up to what a name can be.
|
||||||
|
tabCopyName:
|
||||||
|
RSTB
|
||||||
|
tabCopyNext:
|
||||||
|
LDA.0
|
||||||
|
BRA tabCopyDone
|
||||||
|
STA.1
|
||||||
|
INCD.0
|
||||||
|
INCD.1
|
||||||
|
INCB
|
||||||
|
INIA 0d40
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BRQ tabCopyDone
|
||||||
|
BRI tabCopyNext
|
||||||
|
tabCopyDone:
|
||||||
|
RSTA
|
||||||
|
STA.1
|
||||||
|
RET
|
||||||
|
|
||||||
|
; DP3 names a string. Leaves DP3 on its zero.
|
||||||
|
tabEnd:
|
||||||
|
LDA.3
|
||||||
|
BRA tabEndDone
|
||||||
|
INCD.3
|
||||||
|
BRI tabEnd
|
||||||
|
tabEndDone:
|
||||||
|
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 ----
|
||||||
;
|
;
|
||||||
; Fifteen strings packed end to end, each ending in the zero that says where the next one
|
; Fifteen strings packed end to end, each ending in the zero that says where the next one
|
||||||
@@ -1842,7 +2262,13 @@ tabNamesDone:
|
|||||||
; editor's idea of where things are hangs off those two registers.
|
; editor's idea of where things are hangs off those two registers.
|
||||||
tabList:
|
tabList:
|
||||||
CALL newLine
|
CALL newLine
|
||||||
CALL tabListNames
|
INIA 0x01
|
||||||
|
SETD.1 TabShowing
|
||||||
|
STA.1
|
||||||
|
CALL tabRunSources
|
||||||
|
RSTA
|
||||||
|
SETD.1 TabShowing
|
||||||
|
STA.1
|
||||||
CALL newLine
|
CALL newLine
|
||||||
CALL sayPrompt
|
CALL sayPrompt
|
||||||
|
|
||||||
@@ -1858,82 +2284,6 @@ tabList:
|
|||||||
CALL editRedraw
|
CALL editRedraw
|
||||||
BRI editKey
|
BRI editKey
|
||||||
|
|
||||||
tabListNames:
|
|
||||||
SETD.1 ShellNameCount
|
|
||||||
LDA.1
|
|
||||||
SETD.1 TabLeft
|
|
||||||
STA.1
|
|
||||||
SETD.3 ShellNames
|
|
||||||
tabListNext:
|
|
||||||
SETD.1 TabLeft
|
|
||||||
LDA.1
|
|
||||||
BRA tabListDone
|
|
||||||
DECA
|
|
||||||
STA.1
|
|
||||||
CALL tabShow
|
|
||||||
BRI tabListNext
|
|
||||||
tabListDone:
|
|
||||||
RET
|
|
||||||
|
|
||||||
; DP3 names a candidate. Prints it if it begins with what was typed, and leaves DP3 past its
|
|
||||||
; zero either way, the same bargain tabOffer makes.
|
|
||||||
tabShow:
|
|
||||||
SETD.1 TabStart
|
|
||||||
STD.3.1
|
|
||||||
SETD.1 TabWordLen
|
|
||||||
LDA.1
|
|
||||||
SETD.1 TabSeen
|
|
||||||
STA.1
|
|
||||||
RSTA
|
|
||||||
SETD.1 TabAt
|
|
||||||
STA.1
|
|
||||||
tabShowMatch:
|
|
||||||
SETD.1 TabSeen
|
|
||||||
LDA.1
|
|
||||||
BRA tabShowIt
|
|
||||||
DECA
|
|
||||||
STA.1
|
|
||||||
LDA.3
|
|
||||||
BRA tabShowSkip
|
|
||||||
SETD.1 TabHold
|
|
||||||
STA.1
|
|
||||||
SETD.1 TabWordAt
|
|
||||||
LDA.1
|
|
||||||
SETD.1 TabAt
|
|
||||||
LDB.1
|
|
||||||
CCF
|
|
||||||
ADD
|
|
||||||
MVQA
|
|
||||||
CALL tabCharAt
|
|
||||||
MVQA
|
|
||||||
SETD.1 TabHold
|
|
||||||
LDB.1
|
|
||||||
XOR
|
|
||||||
BNQ tabShowSkip
|
|
||||||
INCD.3
|
|
||||||
SETD.1 TabAt
|
|
||||||
LDA.1
|
|
||||||
INCA
|
|
||||||
STA.1
|
|
||||||
BRI tabShowMatch
|
|
||||||
|
|
||||||
tabShowIt:
|
|
||||||
SETD.1 TabStart
|
|
||||||
LDD.0.1
|
|
||||||
CALL printString
|
|
||||||
INIA 0x20
|
|
||||||
OUTA 0x00
|
|
||||||
OUTA 0x00 ; Two spaces between them, and A already holds one.
|
|
||||||
|
|
||||||
tabShowSkip:
|
|
||||||
LDA.3
|
|
||||||
BRA tabShowPast
|
|
||||||
INCD.3
|
|
||||||
BRI tabShowSkip
|
|
||||||
tabShowPast:
|
|
||||||
INCD.3
|
|
||||||
RET
|
|
||||||
|
|
||||||
; ---- A command that did not work ----
|
; ---- A command that did not work ----
|
||||||
;
|
;
|
||||||
; The one place a failure is recorded, so that the thing reading lines out of a file can
|
; The one place a failure is recorded, so that the thing reading lines out of a file can
|
||||||
@@ -6104,6 +6454,11 @@ MonitorName:
|
|||||||
ShellNameCount:
|
ShellNameCount:
|
||||||
0d15
|
0d15
|
||||||
|
|
||||||
|
SbxText:
|
||||||
|
".sbx"
|
||||||
|
AppsPath:
|
||||||
|
"/Apps"
|
||||||
|
|
||||||
; Where the machine is, written out for the prompt, and where in the buffer it begins.
|
; Where the machine is, written out for the prompt, and where in the buffer it begins.
|
||||||
; Built from the end backwards, so it starts somewhere in the middle.
|
; Built from the end backwards, so it starts somewhere in the middle.
|
||||||
CwdText:
|
CwdText:
|
||||||
@@ -6457,6 +6812,30 @@ TabStart:
|
|||||||
; The answer so far: the first match, cut back by every one after it to where they agree.
|
; The answer so far: the first match, cut back by every one after it to where they agree.
|
||||||
TabBest:
|
TabBest:
|
||||||
#Reserve 0d64
|
#Reserve 0d64
|
||||||
|
; The word being matched, as somebody would type it: a name with its extension taken off, or
|
||||||
|
; a directory with a separator put on.
|
||||||
|
TabCandidate:
|
||||||
|
#Reserve 0d48
|
||||||
|
; The part of the word up to and including its last separator, which is the directory to look
|
||||||
|
; in. Empty means where the machine already is.
|
||||||
|
TabDir:
|
||||||
|
#Reserve 0d64
|
||||||
|
TabDirLen:
|
||||||
|
0x00
|
||||||
|
TabCopyAt:
|
||||||
|
0x00
|
||||||
|
TabFirst:
|
||||||
|
0x00
|
||||||
|
TabPrograms:
|
||||||
|
0x00
|
||||||
|
; Whether the walk is looking for the answer or showing what the answers were.
|
||||||
|
TabShowing:
|
||||||
|
0x00
|
||||||
|
; Where the machine was standing before a directory was walked on its behalf.
|
||||||
|
TabWasCwd:
|
||||||
|
0x00 0x00
|
||||||
|
TabWasDrive:
|
||||||
|
0x00
|
||||||
|
|
||||||
; ---- What the fault screen is saying ----
|
; ---- What the fault screen is saying ----
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ from `make`, not from here.
|
|||||||
### 1. Recorded output
|
### 1. Recorded output
|
||||||
|
|
||||||
`Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares
|
`Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares
|
||||||
everything it printed against a file in `Tests/expected`. 198 tests, of which 136 run, 35
|
everything it printed against a file in `Tests/expected`. 199 tests, of which 137 run, 35
|
||||||
only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image
|
only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image
|
||||||
given at all.
|
given at all.
|
||||||
|
|
||||||
|
|||||||
@@ -9,27 +9,27 @@ there is no such bank
|
|||||||
loaded, starting at 5000
|
loaded, starting at 5000
|
||||||
* b program
|
* b program
|
||||||
bank 00
|
bank 00
|
||||||
* d 4000
|
* d 5000
|
||||||
4000 00 ?
|
5000 47 00 30 00 SETD.0 3000
|
||||||
4001 00 ?
|
5004 72 10 SWI 10
|
||||||
4002 00 ?
|
5006 47 00 30 44 SETD.0 3044
|
||||||
4003 00 ?
|
500A 72 10 SWI 10
|
||||||
4004 00 ?
|
500C 47 00 30 7A SETD.0 307A
|
||||||
4005 00 ?
|
5010 27 1F INIB 1F
|
||||||
4006 00 ?
|
5012 72 11 SWI 11
|
||||||
4007 00 ?
|
5014 47 00 30 5D SETD.0 305D
|
||||||
* x 4000
|
* x 5000
|
||||||
4000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
5000 47 00 30 00 72 10 47 00 30 44 72 10 47 00 30 7A G.0.r.G.0Dr.G.0z
|
||||||
4010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
5010 27 1F 72 11 47 00 30 5D 72 10 47 00 30 7A 72 10 '.r.G.0]r.G.0zr.
|
||||||
4020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
5020 47 00 30 65 72 10 20 72 12 00 00 00 00 00 00 00 G.0er. r........
|
||||||
4030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
5030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||||
* b data
|
* b data
|
||||||
bank 01
|
bank 01
|
||||||
* x 2000
|
* x 3000
|
||||||
2000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
3000 61 20 70 72 6F 67 72 61 6D 2C 20 6C 6F 61 64 65 a program, loade
|
||||||
2010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
3010 64 20 6F 66 66 20 61 20 64 69 73 6B 2C 20 72 75 d off a disk, ru
|
||||||
2020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
3020 6E 6E 69 6E 67 20 6F 6E 20 74 68 65 20 73 79 73 nning on the sys
|
||||||
2030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
3030 74 65 6D 20 74 68 61 74 20 6C 6F 61 64 65 64 20 tem that loaded
|
||||||
* b 2
|
* b 2
|
||||||
bank 02
|
bank 02
|
||||||
* x 0
|
* x 0
|
||||||
|
|||||||
@@ -10,24 +10,10 @@ dir do drive delete
|
|||||||
I do not know: d
|
I do not know: d
|
||||||
> zzzx
|
> zzzx
|
||||||
I do not know: zzzx
|
I do not know: zzzx
|
||||||
> echo here
|
> echo he[13;3Hecho hello.sbx [13;18Hre
|
||||||
here
|
hello.sbx re
|
||||||
> help [15;3Hhelp [15;8H
|
> help [15;3Hhel[15;6H
|
||||||
dir list what is on the disk
|
I do not know: hel
|
||||||
load <file> read a program off the disk
|
|
||||||
run [words] start what was loaded, and tell it those words
|
|
||||||
<name> [words] look where you are and then in /Apps, and start that
|
|
||||||
cd [path] go to a directory, or to the root with nothing after it
|
|
||||||
mkdir <path> make a directory
|
|
||||||
rmdir <path> remove an empty one
|
|
||||||
do <file> run the lines in a file, which must start with #!
|
|
||||||
echo [words] say them
|
|
||||||
clear empty the screen
|
|
||||||
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
|
|
||||||
> exit
|
> exit
|
||||||
halted
|
halted
|
||||||
Execution halted.
|
Execution halted.
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CosmOS
|
||||||
|
> Cr[2;3HCrash [2;9Hzz
|
||||||
|
Crash opcode | service | bank | device | blind
|
||||||
|
finished
|
||||||
|
> Sa[5;3HSay[5;6Hzz
|
||||||
|
I do not know: Sayzz
|
||||||
|
> cd Ap[7;3Hcd Apps/[7;11H
|
||||||
|
/Apps> echo where am I
|
||||||
|
where am I
|
||||||
|
/Apps> cd /
|
||||||
|
> echo Apps/S[11;3Hecho Apps/Say.sbx [11;21H
|
||||||
|
Apps/Say.sbx
|
||||||
|
> echo /Apps/C[13;3Hecho /Apps/Copy.sbx [13;23H
|
||||||
|
/Apps/Copy.sbx
|
||||||
|
> exit
|
||||||
|
halted
|
||||||
|
Execution halted.
|
||||||
|
[exit 0]
|
||||||
@@ -3,10 +3,10 @@ b nonsense
|
|||||||
b 9
|
b 9
|
||||||
load greet.sbx
|
load greet.sbx
|
||||||
b program
|
b program
|
||||||
d 4000
|
d 5000
|
||||||
x 4000
|
x 5000
|
||||||
b data
|
b data
|
||||||
x 2000
|
x 3000
|
||||||
b 2
|
b 2
|
||||||
x 0
|
x 0
|
||||||
s 0 FF
|
s 0 FF
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Cr zz
|
||||||
|
Sa zz
|
||||||
|
cd Ap
|
||||||
|
echo where am I
|
||||||
|
cd /
|
||||||
|
echo Apps/S
|
||||||
|
echo /Apps/C
|
||||||
|
exit
|
||||||
@@ -389,6 +389,17 @@ cosmosHistory | CosmOS/Source/cosmos.asm | run | cosmosHis
|
|||||||
# The last line is the one that says it works on what is actually there rather than on what
|
# The last line is the one that says it works on what is actually there rather than on what
|
||||||
# was typed: two backspaces take "help" down to "he", and Tab finishes it again.
|
# was typed: two backspaces take "help" down to "he", and Tab finishes it again.
|
||||||
cosmosTab | CosmOS/Source/cosmos.asm | run | cosmosTab.in | - | disks/cosmos.img
|
cosmosTab | CosmOS/Source/cosmos.asm | run | cosmosTab.in | - | disks/cosmos.img
|
||||||
|
# And the half of it that reaches the disk. A program is offered under the name somebody
|
||||||
|
# would type - the extension taken off - because that is what a first word can usefully be;
|
||||||
|
# anywhere after the first word everything is offered as it really is. A directory answers
|
||||||
|
# with a separator rather than a space, which says what it is and lets the next part be
|
||||||
|
# typed straight away.
|
||||||
|
#
|
||||||
|
# A path in the word says where to look, and the shell looks in the three places it would
|
||||||
|
# look to RUN something: where you are, /Apps on the disk you are on, and /Apps on drive 0.
|
||||||
|
# Offering what the shell would not find would be finishing a word into something that then
|
||||||
|
# does not work.
|
||||||
|
cosmosTabPath | CosmOS/Source/cosmos.asm | run | cosmosTabPath.in | - | disks/cosmos.img
|
||||||
# The same editing offered to a PROGRAM, through osReadLine. Edit reads its lines that way,
|
# The same editing offered to a PROGRAM, through osReadLine. Edit reads its lines that way,
|
||||||
# so a word typed with two letters the wrong way round is put right without starting the line
|
# so a word typed with two letters the wrong way round is put right without starting the line
|
||||||
# again - which is the whole of what A4 buys.
|
# again - which is the whole of what A4 buys.
|
||||||
|
|||||||
Reference in New Issue
Block a user