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:
Anachronaut
2026-09-06 15:27:57 -04:00
co-authored by Claude Opus 5
parent d9ebc76cf5
commit 2defbb49e2
20 changed files with 583 additions and 23 deletions
+3 -2
View File
@@ -18,6 +18,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -31,7 +32,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -50,7 +51,7 @@ args.script 64
pass.script 20
holds.script 87
crossed.txt 560
37 files, 1 directory
38 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -8,6 +8,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -21,7 +22,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -39,7 +40,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> drive 1
> dir
other.txt 28
+3 -2
View File
@@ -25,6 +25,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -38,7 +39,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -56,7 +57,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -15,6 +15,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -28,7 +29,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -46,7 +47,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -15,6 +15,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -28,7 +29,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -46,7 +47,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -101,6 +101,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -114,7 +115,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -132,7 +133,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -20,6 +20,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -33,7 +34,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -51,7 +52,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+3 -2
View File
@@ -8,6 +8,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -21,7 +22,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -39,7 +40,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> load
load what?
> load nosuch.sbx
+3 -2
View File
@@ -6,6 +6,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -19,7 +20,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -37,7 +38,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> load Say.sbx
loaded, starting at 5000
> run the disk took its time
+3 -2
View File
@@ -15,6 +15,7 @@ Life.sbx 1396
Snake.sbx 2164
Keys.sbx 664
Say.sbx 156
Where.sbx 827
Break.sbx 149
Grid.sbx 571
Press.sbx 872
@@ -28,7 +29,7 @@ Crash.sbx 632
vars.script 50
blocks.script 343
loops.script 272
splash.tune 189
splash.tune 210
tune.sbx 318
Play.sbx 2526
notes.txt 21
@@ -46,7 +47,7 @@ aloud.script 59
args.script 64
pass.script 20
holds.script 87
36 files, 1 directory
37 files, 1 directory
> exit
halted
Execution halted.
+29
View File
@@ -0,0 +1,29 @@
CosmOS
> Where
loaded from /Where.sbx
finished
> Where splash.tune
loaded from /Where.sbx
beside it: /splash.tune
finished
> mkdir /work
made
> cd /work
/work> Where
loaded from /Apps/Where.sbx
finished
/work> Where tiles.atlas
loaded from /Apps/Where.sbx
beside it: /Apps/tiles.atlas
finished
/work> cd /
> load /Apps/Where.sbx
loaded, starting at 5000
> run notes.txt
loaded from /Apps/Where.sbx
beside it: /Apps/notes.txt
finished
> exit
halted
Execution halted.
[exit 0]
+10
View File
@@ -0,0 +1,10 @@
Where
Where splash.tune
mkdir /work
cd /work
Where
Where tiles.atlas
cd /
load /Apps/Where.sbx
run notes.txt
exit
+10
View File
@@ -105,6 +105,15 @@ for i in 1 2 3 4 5 6 7 8; do "$TOOL" put "$DISKS/sbfs.img" "filler$i.txt" >/dev/
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
"$ROOT/Programs/CosmOS/Apps/Say.asm" -o "$WORK/Say.sbx" >/dev/null
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Say.sbx" >/dev/null
# Where.sbx says where it was loaded from, and where a name would be beside it. TWO COPIES
# on purpose, which is the whole test: the one at the root is found where you are standing
# and is named by the bare word that was typed, so the system has to work out what that word
# meant; the one in /Apps is found by a path that already says where it is. Both have to come
# out saying the same kind of thing, and the /Apps one has to go on saying it from a
# directory that has no copy of its own.
"$ROOT/Assembler" -I "$ROOT/Programs/Libraries" -I "$ROOT/Programs/CosmOS/Source" \
"$ROOT/Programs/CosmOS/Apps/Where.asm" -o "$WORK/Where.sbx" >/dev/null
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Where.sbx" >/dev/null
# Break.sbx stops itself twice and shows what the registers were each time. It needs no disk
# of its own: it only prints.
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
@@ -227,6 +236,7 @@ python3 -c "open('twoblocks.txt','w').write('the second disk, at length. ' * 20)
"$ROOT/Programs/CosmOS/Apps/Copy.asm" -o "$WORK/Copy.sbx" >/dev/null
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Copy.sbx" /Apps/Copy.sbx >/dev/null
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Say.sbx" /Apps/Say.sbx >/dev/null
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Where.sbx" /Apps/Where.sbx >/dev/null
# A SCRIPT in the system's place, which is the one thing on this disk that is fetched from
# drive 0 a block at a time WHILE it runs. Its own name carries the drive in front of it,
# and resolving a name like that moves the machine to that drive - so a script started from
+17
View File
@@ -1000,6 +1000,23 @@ cosmosScriptNest | CosmOS/Source/cosmos.asm | run | cosmosScr
# which would let a command run with an argument missing. At the prompt they are ordinary
# unset names, because there is no script to have been given anything.
cosmosScriptArgs | CosmOS/Source/cosmos.asm | run | cosmosScriptArgs.in | 200000000 | disks/cosmos.img
# ---- Where a program came from ----
#
# osWhereAmI and Libraries/path.asm, which are what an application with assets stands on.
#
# THE ANSWER FOLLOWS THE PROGRAM AND NOT THE PERSON, which is the claim 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. Standing in /work, the copy in /Apps says /Apps
# and puts its asset there, while the argument still means what the person typed.
#
# Two copies of it on this disk reach the system by different routes. The one at the root is
# found where you are standing and named by the bare word typed, so the path has to be worked
# out from where the person was; the one in /Apps arrives already absolute. Running it from
# the root is also the check on the root's own path, which came out as "//" until the first
# caller that asks there rather than only when somebody has moved.
#
# And load then run, because that is the other way into the same place.
cosmosWhere | CosmOS/Source/cosmos.asm | run | cosmosWhere.in | 200000000 | disks/cosmos.img
# ---- Starting itself ----
#
# /System/Boot/startup.sh runs before anybody can type. This one is also the check on #quiet