= TB shell scripting for MOP2
Kamil Kowalczyk
2025-11-08
:jbake-type: post
:jbake-tags: MOP2 osdev
:jbake-status: published

This post is about TB (ToolBox) - the shell interpreter for MOP2 operating system.

= Invoking applications

Applications are invoked by providing an absolute path to the binary executable and the list of
arguments. In MOP2 paths must be formatted as `MOUNTPOINT:/path/to/my/file`. All paths are absolute
and MOP2 doesn't support relative paths (there's no concept of a CWD or current working directory).

.Example of listing currently running processes
[source]
----
base:/bin/pctl ls
----

Typing out the entire path might get tiresome. Imagine typing `MOUNTPOINT:/path/to/app arg more args`
every time you want to call an app. This is what TB aliases/macros are for. They make the user type
less ;).

.Example of calling an application via an alias
[source]
----
$pctl ls
----

Now that's way better!

=== Creating new aliases

To create an alias we can type

[source]
----
mkalias pctl base:/bin/pctl
----

And then we can use our `$pctl`!

But there's another issue - we have to write aliases for every application, which isn't better than
us typing out the entire path. Luckliy, there's a solution for this. TB has two useful functions
that can help us solve this - `eachfile` and `mkaliasbn`.

`eachfile` takes a directory, an ignore list and a command, which is run for every entry in the said
directory. We can also access the current directory entry via special symbol called `&EF-ELEM`.
In `base/scripts/rc.tb` we can see the full example in action.

[source]
----
eachfile !.gitkeep base:/bin \
  mkaliasbn &EF-ELEM
----

This script means: for each file in base:/bin (excluding .gitkeep), call mkaliasbn for the current
entry. `mkaliasbn` then takes the base name of a path, which is expanded by `&EF-ELEM` and creates
an alias. `mkaliasbn` just simply does `mkalias <app> MP:/path/<app>`.

== Logging

In the UNIX shell there's one very useful statement - `set -x`. `set -x` tells the shell to print out
executed commands. It's useful for script debugging or in general to know what the script does (or 
if it's doing anything / not stuck). This is one thing that I hate about Windows - it shows up a
stupid dotted spinner and doesn't tell you what it's doing and you start wondering. Is it stuck?
Is it waiting for a drive/network/other I/O? Is it bugged? Can I turn of my PC? Will it break if I
do? The user SHOULD NOT have these kinds of questions. That's why I believe that `set -x` is very
important.

I wanted to have something similar in TB, so I've added a `setlogcmds` function. It takes `yes` or
`no` as an argument to enable/disable logging. It can be invoked like so:

[source]
----
setlogcmds yes
----

Now the user will see printed statements, for eg. during the system start up:

[source]
----
this is an init script!
+$tb -m runfile -f base:/scripts/mount.tb
Mounting filesystems...
+$fs mount -mp uhome -fs LittleFS -dev atasd-ch0-M-part2 -fmt no
OK uhome
----

== String stack and subshells

In UNIX shell, it's common to get the output of an application, store it into a variable and then
pass that variable around to other apps. For eg:

[source]
----
# Use of a subshell
MYVAR=$(cat file.txt)
echo $MYVAR | myapp # or something...
----

In TB, I've decided to go with a stack, since I find it easier to implement than a variable hashmap.
A stack can be implemented using any dynamic list BTW.

The stack in TB is manipulated via `stackpush` and `stackpop` functions. We can `stackpush` a string
using `stackpush <my string>` and then `stackpop` it to remove it. We can also access the top of
the stack via `$stack`. It's a special magic alias, which expands to the string that is at the top.
An example of stack usage would be:

[source]
----
stackpush 'hello world string!'
print $stack
stackpop
----

=== The `do` function

The `do` function does what a subshell does in UNIX shell. We can `do` a command an then have it's
output placed at the top of the stack. An example of this would be:

[source]
----
do print 'hello world from subshell'
print $stack
stackpop
----

It's a simpler, more primitive mechanism than the UNIX subshells, but it gets the job done ;).
