A program can ask where it came from
SWI osWhereAmI hands back the path the program was loaded from, on the same terms as osArgument, and Libraries/path.asm joins a name to the place another thing is in. Between them an application can find its own assets: ask where you are, then pathBeside that and the file's name. The answer FOLLOWS THE PROGRAM AND NOT THE PERSON, which is the whole point and the reason the working directory could not serve. A program's assets are relative to the program and its arguments are relative to whoever ran it, and cwd can only be one of them - setting it to the program's own would mean "Play mytune.tune", typed by somebody in their own directory, looked in Play's. It is made absolute before the program starts, because the path the search settled on may be a bare name: a program found where somebody was standing is named by the word that was typed, and a bare name means the working directory - which a program is entitled to move out of. Worked out once, at the start, since where a program came from is a fact about its start and cannot change afterwards. Joining is a LIBRARY and not a service. A service that opened a file relative to the program would need a twin for every file operation there is - read, save, info, block, start, write, done, delete, rename - while one service handing back a path composes with all of them. ---- And the root's own path was "//" ---- Found by the first caller that asks. shellPath prepends a separator in front of whatever string it is given, so being handed the separator itself wrote two of them. Nothing saw it while the only caller was the prompt, which asks where it is only when that is not the root. It is handed an empty string now, and cosmosWhere runs a program from the root. Where.sbx exists to be run rather than read, and is on the test disk twice: at the root, where it is found by the bare word typed, and in /Apps, where it is found by a path that already says where it is. 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
d9ebc76cf5
commit
2defbb49e2
@@ -4763,11 +4763,16 @@ shellPathStep:
|
||||
shellPathDone:
|
||||
; A machine at the root has written nothing at all, and the path to the root is the
|
||||
; separator on its own.
|
||||
;
|
||||
; AN EMPTY STRING, because prepending puts a separator in FRONT of whatever it is given -
|
||||
; so being handed the separator itself wrote two of them and the root came out as "//".
|
||||
; Nothing saw it for as long as the only caller was the prompt, which asks where it is
|
||||
; only when that is not the root; the first caller that always asks found it at once.
|
||||
SETD.0 CwdAt
|
||||
LDD.1.0
|
||||
LDA.1
|
||||
BNA shellPathReady
|
||||
SETD.0 Separator
|
||||
SETD.0 NoText
|
||||
CALL shellPathPrepend
|
||||
shellPathReady:
|
||||
RET
|
||||
@@ -5649,6 +5654,9 @@ runLoaded:
|
||||
INIB 0d64
|
||||
CALL copyText
|
||||
|
||||
; And where the program itself came from, so it can be asked later.
|
||||
CALL runWhere
|
||||
|
||||
CALL installVectors
|
||||
|
||||
; The entry address is a number until BRD makes it a place. DP3 is the one to build it
|
||||
@@ -5657,6 +5665,98 @@ runLoaded:
|
||||
LDD.3.1
|
||||
BRD.3
|
||||
|
||||
; ---- Where the program itself came from ----
|
||||
;
|
||||
; ProgramName holds the path the search settled on, and that path may be a bare name: a
|
||||
; program found where somebody was standing is named by the word that was typed. A BARE NAME
|
||||
; MEANS THE WORKING DIRECTORY, and a program is entitled to move out of it - so a program
|
||||
; asked later where it lives would be told "beside wherever you are now", which is the one
|
||||
; answer that is certainly wrong.
|
||||
;
|
||||
; So it is made absolute HERE, once. Where a program came from is a fact about its start and
|
||||
; cannot change afterwards; where the person is can change on the program's own next line.
|
||||
runWhere:
|
||||
; A path that begins with a separator has already said where it is.
|
||||
SETD.0 ProgramName
|
||||
LDA.0
|
||||
INIB 0x2F
|
||||
CCF
|
||||
SUB
|
||||
BRQ runWhereAsFound
|
||||
|
||||
; Or a drive in front of it, which says so twice over. A digit and then a colon, both, the
|
||||
; same test the path walker makes - a name may begin with a digit, and the colon is the
|
||||
; whole of what tells the two apart.
|
||||
LDA.0
|
||||
INIB 0x30
|
||||
CCF
|
||||
SUB
|
||||
BRC runWhereRelative ; Below a digit.
|
||||
LDA.0
|
||||
INIB 0x3A
|
||||
CCF
|
||||
SUB
|
||||
BNC runWhereRelative ; Above one.
|
||||
INCD.0
|
||||
LDA.0
|
||||
INIB 0x3A ; splitlint[redundant-assignment]: 0x3A above is one past '9' and here it is ':'
|
||||
CCF
|
||||
SUB
|
||||
BRQ runWhereAsFound
|
||||
|
||||
runWhereRelative:
|
||||
; Where the machine is, written out. shellPath builds it backwards from the end of its
|
||||
; buffer and hands back a pointer into the middle, which is a string like any other.
|
||||
CALL shellPath
|
||||
SETD.0 CwdAt
|
||||
LDD.0.0
|
||||
SETD.1 RunPath
|
||||
INIB 0d127
|
||||
CALL copyText
|
||||
|
||||
; The end of it, and the last character on the way past. At the root there is no last
|
||||
; character at all, which is an answer rather than a special case: nought is not a
|
||||
; separator, so a separator gets written and the path begins with one.
|
||||
SETD.0 RunPath
|
||||
RSTA
|
||||
SETD.1 RunPathLast
|
||||
STA.1
|
||||
runWhereEnd:
|
||||
LDA.0
|
||||
BRA runWhereJoin
|
||||
SETD.1 RunPathLast
|
||||
STA.1
|
||||
INCD.0
|
||||
BRI runWhereEnd
|
||||
|
||||
runWhereJoin:
|
||||
SETD.1 RunPathLast
|
||||
LDA.1
|
||||
INIB 0x2F
|
||||
CCF
|
||||
SUB
|
||||
BRQ runWhereName ; It ends in a separator already, so a second would be a lie.
|
||||
INIA 0x2F
|
||||
STA.0
|
||||
INCD.0
|
||||
|
||||
runWhereName:
|
||||
; And the program's own name under it. DP0 is where it goes, which is at most 127 bytes
|
||||
; along a buffer of 192 - so the 64 a name can be always fits.
|
||||
PSHD.0
|
||||
POPD.1
|
||||
SETD.0 ProgramName
|
||||
INIB 0d64
|
||||
CALL copyText
|
||||
RET
|
||||
|
||||
runWhereAsFound:
|
||||
SETD.0 ProgramName
|
||||
SETD.1 RunPath
|
||||
INIB 0d192
|
||||
CALL copyText
|
||||
RET
|
||||
|
||||
runNothing:
|
||||
SETD.0 NothingLoaded
|
||||
CALL printString
|
||||
@@ -5836,6 +5936,16 @@ handleArgument:
|
||||
CALL copyText
|
||||
RETI
|
||||
|
||||
; The same bargain for the other thing a program is entitled to know about its own start:
|
||||
; where it came from. Worked out in runWhere before the program was given the machine, so
|
||||
; this only has to hand it over.
|
||||
handleWhereAmI:
|
||||
PSHD.0
|
||||
POPD.1
|
||||
SETD.0 RunPath
|
||||
CALL copyText
|
||||
RETI
|
||||
|
||||
; ---- The disk, on a program's behalf ----
|
||||
;
|
||||
; A loaded program that wanted a file used to include the whole filesystem, so it carried a
|
||||
@@ -8110,6 +8220,17 @@ SearchDrive:
|
||||
0x00
|
||||
RunDrive:
|
||||
0x00
|
||||
|
||||
; ---- Where the program came from, made absolute ----
|
||||
;
|
||||
; A hundred and ninety two, which is a working directory of up to 127, a separator, and a
|
||||
; name of up to 64. None of those three can be made longer without the others being counted
|
||||
; again.
|
||||
RunPath:
|
||||
#Reserve 0d192
|
||||
RunPathLast:
|
||||
0x00
|
||||
|
||||
ScreenSaved:
|
||||
0x00
|
||||
ScreenWasDrive:
|
||||
@@ -8530,6 +8651,7 @@ CommandLine:
|
||||
osBreak handleBreak
|
||||
osLastStatus handleLastStatus
|
||||
osTakeScreen handleTakeScreen
|
||||
osWhereAmI handleWhereAmI
|
||||
osBootState handleBootState
|
||||
osBootSettle handleBootSettle
|
||||
Device 0x20 diskDone
|
||||
|
||||
Reference in New Issue
Block a user