UniData BASIC segfaults at 26 items; UniVerse has no such limit Measured on UniData 8.3 with synthetic programs (count, not byte length) and with disjoint sets of the same size. Section 3, with the mv_package#125 failure as the evidence, plus the two things that hide it: a crashed install leaves objects behind, and each crash burns a licence slot.
OSREAD returns different things per port: raw bytes vs @AM-separated Measured on MVX, UniData 8.3, UniVerse 14.2.1 and jBASE 6.2.1.1 with the same two-line file. Section 3 (compiles everywhere, behaves differently), with the mv_package#118 failure as the evidence, and cross-referenced from the existing OSREAD/GETENV entry in section 1.
SETTING is reserved on UniData, as a label too
a Q-pointer names an account that must be registered; an F pointer by path does not Reaching a file in another account, a Q-pointer's second attribute is resolved through UD.ACCOUNT, so an account made by hand is unreachable. A file pointer carrying absolute paths needs no registry. jBASE needs neither and opens a path directly, which the U2 pair refuse. Measured on all three.
UniVerse: X<-1> = "" does not append, and parallel arrays go off by one The append form adds an element on UniData and jBASE; on UniVerse an empty value is a no-op, so two arrays kept in parallel desynchronise the moment one takes an empty and every later read is off by one. Nothing fails. Measured on all three.
jBASE: keep JBCOBJECTLIST in jBASE's own config, and put $HOME/lib last jBASE reads nothing from an account directory, so a profile there needs a human to source it; the environment array in jbase_config.json is read by every session and is where jBASE documents this variable itself. Order matters -- $HOME/lib holds bootstrap copies of names real packages provide, so first would shadow the real package permanently while appearing to work. PUTENV sets JBCDEV_LIB for an EXECUTEd CATALOG.
jBASE: LN is reserved, objects are $<PROG>, and a path replaces the file pointer Three found porting mvpkg's package installs to jBASE: LN is the natural-log function and its error names the following line too; objects sit beside their source as $<PROG>, the jBASE spelling of UniData's _<PROG>, which a loop over BP/* has to skip (and $* in a shell case pattern is the positional parameters); and BASIC and CATALOG take a path with a wildcard, where an MD DIR pointer does not open at all and SELECT over such a directory returns nothing.
UniVerse: a file pointer used for compiling comes in a pair Compiling through a pointer you wrote makes UniVerse create a second VOC record for the object side, <name>.O, which survives and is never updated when you re-point the original -- so several trees compiled through one temporary pointer all land in the first one.
a system-wide catalog makes a failed install look like a working one The check that missed it asked whether a catalog object exists, which cannot fail on a machine that has ever installed the package. Ask whether this run produced it, and read the compile output rather than the exit status.
UniVerse: creating a file from BASIC, the F pointer, per-account cataloging Four differences found porting mvpkg to UniVerse 14.2.1: - CREATE.FILE asks its seven questions whatever arguments it is given, so from BASIC the answers go on the input stack with DATA. Types 18 and 19, never 30. - a VOC file pointer says F on UniVerse and DIR on UniData, and UniVerse does not accept the UniData spelling. - the .O object directory has to exist before compiling from a file that points outside the account. - cataloging is per account: the pointer is VOC type V, not C, and DEFFUN ... CALLING "*NAME" asks for the global catalog and does not find it.
jBASE: the catalog search path IS configurable, with JBCOBJECTLIST This page said the output location of a catalog is configurable and the search path is not, which is half the story: JBCDEV_LIB alone moves the output and leaves the loader looking in the old place. Set JBCOBJECTLIST too and it resolves -- measured for a cataloged subroutine, which is the case the original finding failed on. That makes per-package catalog directories possible, which matters because the shared $HOME/lib/lib0.so is what lets one package's unresolvable DEFC symbol break every other cataloged program.
jBASE: one package's DEFC symbols can break every cataloged program Cataloging is per USER and shares one lib0.so, so an unresolvable DEFC symbol makes the whole library unloadable -- every other cataloged program then fails with a message naming neither the symbol's package nor the real cause. Found while installing mvpkg, where the install was correct and MVPKG still would not run.
CONVERT: the statement form is not portable either, and FIELD usually replaces it Adds what mv_package#54 taught: MVX rejects CONVERT...TO...IN, so there is no portable spelling at all; FIELD is a guard-free replacement for the common shell-capture case; and the trap recurred in six places despite already being on this page, because the symptom never looks like CONVERT.
porting: COMMON size checking, and how to quote an SH -c command Both found verifying the five dependency packages on UniVerse. The COMMON one is a difference in strictness rather than syntax: jBASE accepts a caller whose block is a variable short, UniVerse refuses to load the subroutine. Worth knowing because the mismatch can live in working jBASE code indefinitely. The SH -c quoting is the more dangerous: curl-cmd's UniVerse arm had an unbalanced quote, compiled, ran, and fetched nothing -- returning an empty body with no error, which reads exactly like an empty response.
porting: RETURN(value) on UniVerse, @USER.TYPE, and flat guards RETURN(x) is the portable spelling -- UniVerse rejects the bare form in a FUNCTION, and its error mentions neither functions nor parentheses, so it reads as a problem with whatever is being returned. The nested-guard note is promoted from a PLATFORM.H caveat to a general rule, because it was not a PLATFORM.H problem: mvpkg had two $IFDEFs inside $ELSE blocks that worked on three systems and broke on UniVerse.
porting: UniVerse — the $IFDEF row, provisioning, and its two missing built-ins UniVerse was 'not tested' in the $IFDEF table because its accounts would not provision. They do: running uv in a fresh directory asks TWO questions, and piping only Y leaves no VOC and looks like a silent failure. Recipe recorded, with the assertion that should follow it. With that unblocked, uv turns out to be the worst of the four on $IFDEF: it is silently false when the first symbol is undefined and a COMPILE ERROR when it is defined, so the same line's fate depends on which symbols are set. And the two missing built-ins are recorded with their actual errors, because neither names the thing that is missing: OSREAD parses as a variable, GETENV as an undimensioned array.
porting: how to reach a shell from jBASE, and the two traps inside the fix jBASE EXECUTE is argv-style with no shell, so the `!` form and `sh -c "..."` both fail -- the second is worth naming because it is what everyone reaches for next, and it fails for the same reason the first does. Writing the command to a file and running sh on the file works because the file is the quoting boundary. The two sub-traps are recorded because I hit both: putting the redirect on the EXECUTE line reintroduces the original bug, and TRIM does not strip the newline echo leaves, so the exit status silently reads as unknown.
porting: record that MVX deliberately will not gain $IFDEF OR MVX is ours, so \`||\` could be added there. Writing down why it will not be is worth more than the code would have been: source using it compiles correctly on MVX, is silently wrong on jBASE, and does not compile on UniData. One symbol per $IFDEF is the portable subset, so MVX targets that subset too -- otherwise the compiler most used for development is the one least able to catch the bug.
porting: $IFDEF has no OR, and jBASE leaks $DEFINE through a false guard Both found while porting mvpkg, and both share a shape: the broken form compiles. A table of what each system does with $IFDEF A || B is worth more than the rule, because two of the three tested accept it and silently read only the first symbol -- so it works or not depending on which symbol you wrote first, which is the kind of bug that survives review. The $DEFINE leak is the same trap one level deeper and cost most of a session: GETENV works fine on jBASE, and a guarded rename to MVX's ENV() fired anyway, turning every call into a function that does not exist there. UniVerse is recorded as not tested rather than assumed; its account would not provision.
porting: MVMASTER, rather than guarding every master-dictionary open The VOC/MD entry said to $IFDEF each OPEN. That is the wrong advice at any scale above one: mvpkg opens the master dictionary fourteen times, and the name is a single fact about the platform. PLATFORM.H is already generated per platform, so it is where the fact belongs. Both caveats are ones this port actually hit -- UniData has no valued $DEFINE, and a nested $IFDEF inside the generated header is the construct that compiles on udt and fails on uv.
porting: five jBASE findings from running mvpkg, not compiling it All five came out of a bring-up on jBASE 6.2.1.1: the client compiles 29/29 and catalogs 29/29, and then fails at run time in ways the compile could not show. GETENV is the one worth reading twice. It is already on the not-everywhere list, but the jBASE error quotes your variable name back as a conversion code, so the output blames OCONV for a missing function. VOC/MD and the CREATE.FILE DIR misparse are the same shape: no error at the point of the mistake. The catalog note is the one that cost the most time. Pointing JBCDEV_LIB at an account-local lib/ compiles clean, catalogs clean, reports success, and then fails every CALL -- because on jBASE the output location of a catalog is configurable and the search path is not.
porting: LN, NEG, DEFFUN CALLING, and jBASE's real MAT dimensions All four came out of porting mvpkg and its five dependencies. LN and NEG are jBASE functions, so they join the reserved-word table. DEFFUN ... CALLING is U2 syntax with no jBASE equivalent -- and the note records the way out, which is that jBASE resolves a DEFFUN against the catalog by name, so an already-cataloged dependency makes the alias unnecessary rather than merely unavailable. The MAT row gained jBASE's position, which is a third one: not rejected as on UniData, not nominal as on UniVerse, but real and range-checked at compile time.
jBASE EXECUTE cannot see stderr, and two silent traps writing DEFC primitives Both C traps kill the process with exit 201 and no message, which is a long way to travel for an undeclared strdup.
Correct: jBASE EXECUTE runs OS commands directly The earlier entry said jBASE had no shell access. It has no SH wrapper, which is not the same thing -- EXECUTE runs the command itself, CREATE-ACCOUNT included. Testing only the wrapper the other platforms use is how that got written down backwards. Adds the two real consequences: no shell syntax (so no 2>&1, and CAPTURING takes stdout alone), and a spawned MV binary makes its own session, which a counted licence charges for.
CONVERT's argument order, the missing shell escape, and KEYIN through jsh Three more measured on 6.2.1.1. CONVERT is the dangerous one: both orders compile everywhere and the wrong one returns something plausible rather than failing.
$IFDEF on a symbol you never included is silently false The most expensive shape here, because the compiler easiest to develop against hides it: mvx-basic predefines MVX and ENGINE, so the guarded branch is taken on MVX regardless of the source, and on udt/uv $ELSE is right anyway. Fifteen mv_git handlers were wrong for a year before jBASE surfaced it.
jBASE ships its own sort and jbase_env.sh puts it first The only coreutil shadowed on 6.2.1.1, which is what makes it easy to miss: everything else in the pipeline behaves, and the failure reads as a quoting or directory problem rather than the wrong binary.
jBASE reserves DATA as well Completes the list measured against mv_git: eight words accounted for all thirteen programs that would not catalog.
jBASE also reserves COUNT; name the files for KEY and DIR COUNT is the sharp one: it is a function on every MV system, so COUNT(X) reads as ordinary BASIC everywhere and only the assignment form collides.
jBASE reserves SUB, SENTENCE, STATUS, KEY and DIR as well as OUT Verified on 6.2.1.1. All six compile fine on MVX, UniData and UniVerse, so they accumulate until jBASE first sees the code -- in mv_git they had reached 16 programs, and the catalog step discarded its output, so the suite reported a clean run while a third of the verb's subroutines were missing from the library.