(rontolisp) docs
← The uiop Package

uiop/os

uiop/os is what a portable library asks about the host: which operating system this is, which implementation, what the environment says, where the working directory is. All 22 exports are implemented, and every host answer is derived from one source — upstream's own uiop:featurep over *features* — so the same rule decides them on all four backends.

Every name is reachable through either spelling: uiop:getenv and uiop/os:getenv are the same function (The uiop Package).

Three answers here are rontolisp's own, and each is a decision rather than a gap:

  • uiop:os-unix-p is t outright. Every backend presents the POSIX-shaped file and namestring model, so the answer is right — but *features* deliberately carries no :unix, because that would flip the #+unix reader branch of every library the frontend reads, which is a far wider claim than one OS predicate.
  • The environment is read from the host and written to an override map. No backend can rewrite its own process environment (the JVM cannot at all, WASI's is read-only), so (setf (uiop:getenv name) value) records the value in a per-program map that uiop:getenv consults first.
  • There is no chdir anywhere, and no working directory on the WASM backends. See The working directory.

Host identity

FunctionWhat it answers
uiop:implementation-type / uiop:*implementation-type*:rontolisp
uiop:lisp-version-stringthis build's version, the same string (rontolisp:version) carries
uiop:operating-system:unix
uiop:detect-os:os-unix — upstream's own body minus the loop: only one predicate can win here, so it pushes that feature onto *features* and returns it
uiop:architecturethe ABI the artifact targets: :jvm on the interpreter and the JVM (a class file is CPU-independent), :wasm32 on both WASM outputs
uiop:implementation-identifierall four joined and downcased, the way upstream builds a fasl-cache directory name: "rontolisp-<version>-unix-jvm"
uiop:hostnamenil — no backend has a host-identity primitive, and this is exactly what upstream answers on an implementation its own #+ clauses do not name
uiop:os-unix-pt (see above)
uiop:os-macosx-p / uiop:os-windows-p / uiop:os-genera-pnil — upstream's own derivations over *features*, which carries no host-OS feature
uiop:os-conda cond over the predicates above, choosing the first clause whose test is true
(:RONTOLISP :UNIX :OS-UNIX)
(T NIL NIL)
:UNIX

Feature expressions

uiop:featurep evaluates a feature expression against *features* at run time, exactly as #+ does at read time: an atom is a membership test, and (:not e), (:or e...) and (:and e...) combine them.

(T T T T NIL)

The feature set differs per backend by design — :rontolisp-interpreter, :rontolisp-jvm and :rontolisp-wasm are what tell them apart — so uiop:featurep (and uiop:architecture with it) answers for the backend that is running. A second, optional argument tests a feature set of your own: (uiop:featurep :x '(:x)) is T. Rebinding *features* around the call, which upstream's parameter list invites, works on every backend — it is an ordinary special variable.

Environment variables

FunctionWhat it does
uiop:getenvthe value of a variable as a string, or nil when unset
(setf uiop:getenv)record an override the reads above consult first; a nil value is an unset
uiop:getenvpthe value, but nil for the empty string as well — "is this variable really set?"
("hello" "hello")
("" NIL)
NIL

The override is per program run, not a change to the process environment: a subprocess would not see it, and neither would anything outside this image. That is the honest shape of (setf (uiop:getenv ...)) on hosts that do not allow the write, and it is what makes the option-setting idiom libraries use — bind some variables, run a body, put them back — behave the same on all four backends.

The working directory

FunctionWhat it does
uiop:getcwdthe host working directory in directory form, or a signalled uiop:not-implemented-error where the host has none
uiop:chdirsignals uiop:not-implemented-error on every backend

uiop:getcwd answers on the interpreter and the JVM, where the host process has a working directory. Both WASM backends signal: a WASI program is given preopened directories and no current one, so there is nothing to answer.

uiop:chdir signals everywhere, including the JVM. Java reads user.dir once at startup and cannot move the process working directory, and WASI has no chdir at all — an answer that only changed what merges look like, while open kept resolving elsewhere, would be worse than the error.

Windows shortcuts

Upstream carries a small .lnk reader, and its two octet primitives are generally useful:

FunctionWhat it does
uiop:read-little-endianread an unsigned little-endian integer of n octets (4 by default) from a binary stream
uiop:read-null-terminated-stringread octets up to a 0 and answer them as a string
uiop:parse-windows-shortcut / uiop:parse-file-location-infosignal uiop:not-implemented-error

The two readers are real stream work and run everywhere read-byte does. The two .lnk parsers navigate the file with file-position, which no rontolisp file stream supports, so they name that primitive instead of misparsing silently.