What changed when print became a builtin
The four verbs, their names (both cases), the flush contract and the output order are exactly what the print plugin gave; the formatter is the plugin’s, ported — a checked wrapper over the system printf. The format string is parsed by the runtime, directive by directive; each directive is rebuilt from a whitelist and handed to snprintf with exactly one argument, so libc never sees the script’s string as a whole.
The directive grammar: %[flags][width][.precision]conv — flags - + space 0 #; width and precision are digits only, at most 1 048 576; conversions d i u o x X (integer), f F e E g G (double; an integer argument is accepted), s (string), c (one byte 0..255), %%. Everything else — %n %p %a, a * width or precision, a length modifier written in the script, a width above the ceiling, an unterminated directive — is an error that names the directive and the reason: print.printf: directive #1 ('%n') is not supported (supported: d i u o x X f F e E g G s c %).
Checked at compile time when the format is a string literal, at the directive’s position: directive #2 has no argument (1 given)., 1 directive, 2 arguments given., directive #1 expects an integer, argument 1 is a string. A variable or interpolated format is checked at run time by the same grammar, with the same texts.
Style rule (owner, 2026-10-04): where no formatting is needed, write print.Line("text") (with a newline) or print.Print("text"), not printf("text\n") — printf is for formatting (%d, %s, …). A Line text is not a format: a % in it is a character, never a directive. The examples in the tree and on this site follow the rule.
The old plugin line: plugin "../plugins/print/PrintPlugin"; names a plugin that no longer exists (print is built in since rev31zzti), so it fails like any missing plugin file; there is no alias and no special message — the canonical line is plugin "builtin:print";. %f prints a C-locale decimal point on every platform.
Introduction
The print plugin is the most basic text-output operation in DominScript: following the traditional C-style printf pattern, it builds a string from a format string and any number of values, and writes the result to standard output (stdout). The plugin flushes automatically at the end of every call, so the written text appears at once. It has a formatting verb under two names (PrintF and printf — both call exactly the same function), and two unformatted companions, each also under two names: Line/line (text plus a newline) and Print/print (text as-is). The unformatted verbs interpret no % characters at all.
The two names
print.printf follows the familiar lower-case C convention and most sample scripts use this name. print.PrintF follows the PascalCase convention of DominScript plugins. Same behavior, same implementation — the choice is stylistic. The examples in this reference use the lower-case printf form, since it is the most common.
Loading the plugin
plugin "builtin:print";
A typical flow — formatted output
i32 $n; double $pi; $n = 42; $pi = 3.14159; printf("n=%d, pi=%.2f\n", $n, $pi);
Supported format specifiers
The format string is a simple C-like pattern. A “%” character must be followed by an optional width, an optional “.precision”, and a specifier character. Five specifiers are supported: %d (integer), %x (hexadecimal integer, lower-case), %f (floating-point), %s (string), and %% (a literal % character). The width applies to every specifier as left-padding with spaces to the given width; the precision specifies, for %f, the number of decimal digits (default 6).
What to know about every function (the basics)
The first argument MUST be a string (the format string); the following arguments must have types matching the specifiers.
Type strictness: %d accepts only int, %f only float, %s only string. A different type raises a runtime error.
Argument count strictness: if there are fewer arguments than specifiers, a runtime error.
The specifiers may have width and precision (e.g. %5d, %.2f, %10s). The width left-pads with spaces; %0-prefixed padding is NOT supported.
The output goes to standard output (stdout), and is flushed automatically at the end of every call (line buffering does not prevent the output from appearing).
The return value is ALWAYS 0 (the function does not return the number of characters, only a success indicator).
An unknown specifier (e.g. %z) or an invalid character after a numeric width raises a runtime error.
How to read the signatures
format is the format string, and the following ... is the variable number of evaluated arguments (integer, floating-point, or string). The type after the -> arrow is the return type. print.printf(format, ...) -> int expects a format string and zero or more values, and always returns 0.
Formatted output
Writes formatted text to standard output (stdout). Both names of the function (PrintF and printf) perform the same operation.
print.printf
print.printf(format, ...) -> int
Builds a string from a format string and any number of values, and writes it to standard output.
| Parameter | Type | Description |
|---|---|---|
| format | string | The format string (required). It knows the %d, %x, %f, %s, and %% specifiers; each supports a width (e.g. %5d), and — for %f — a .precision (e.g. %.2f). |
| ... | variadic | The values matching the specifiers in the format string (integer, floating-point, or string), in the corresponding order and type. |
Always 0 (success indicator). A bad format, wrong type, or missing argument raises a runtime error.
printf("dec=[%d] width5=[%5d]\n", 42, 42); printf("hex=[%x] width4=[%4x]\n", 255, 255); printf("float=[%f] p2=[%.2f] p0=[%.0f]\n", 3.14159, 3.14159, 3.14159); printf("str=[%s] width10=[%10s]\n", "hi", "hi"); print.Line($"escape: 100%");
dec=[42] width5=[ 42] hex=[ff] width4=[ ff] float=[3.141590] p2=[3.14] p0=[3] str=[hi] width10=[ hi] escape: 100%
The most common text-output operation: in every script you use this to write out computed values, states, and check messages. You can combine several values in one call; the type strictness helps catch mistakes early.
print.FastPrintF / print.fastprintf
print.FastPrintF(format, ...) -> intThe exact twin of PrintF — same formatting engine, byte-for-byte the same output — except that it does NOT flush on every call. Meant for writing large volumes of output to a pipe or file, where a per-call flush forces one write() syscall per line.
| Parameter | Type | Description |
|---|---|---|
| format | string | A printf-style format string. |
| ... | any | The values substituted into the format. |
Returns the number of characters written.
Bulk output where throughput matters. If you need each line to appear immediately (progress on a terminal, interleaving with another writer), use PrintF instead — or the output may sit in the buffer until it fills or the program exits.
print.PrintF
print.PrintF(format, ...) -> intExactly the same as printf — a PascalCase alias for the same function.
| Parameter | Type | Description |
|---|---|---|
| format | string | See printf. |
| ... | variadic | See printf. |
Always 0. printf and PrintF are semantically identical.
print.PrintF("int=%d, string=%s\n", 7, "apple");
int=7, string=apple
Use the PrintF name if you want to consistently follow the DominScript plugin-API PascalCase convention in your source code. There is no behavioral difference from the lower-case printf.
Practical notes
What builtin:print is good for
Diagnostic messages and intermediate values during development and debugging.
Log-like output in command-line scripts (simpler than the full log plugin).
User feedback: status, errors, results — all formatted nicely.
Mixing numeric values and strings into one piece of text in a single call (no need for separate string concatenation).
The specifiers exactly
%d for the decimal integer (signed, if negative). %x for the hexadecimal integer (lower-case “a”..“f”), without sign. %f for the floating-point, by default with 6 decimal digits; with .precision (e.g. %.2f) you can set the desired number of decimals. %s for the string (unchanged). %% places a single literal % character in the output. The width left-pads with spaces in every case.
What it does not support
The plugin provides a focused, minimal printf implementation. It does NOT know: %0-prefix padding (zero-padding), left-alignment (% - flag), %u (unsigned), %o (octal), %c (character), %p (pointer), %e/%g (scientific float), %lld/long modifiers, or any length modifiers. The supported %d/%x/%f/%s/%% with width/.precision covers typical script needs; if you need more complex formatting, preprocess with the str.* functions.
Return value
printf ALWAYS returns 0 (success), not the count of characters written. If you need the character count, build the string first (with the str plugin), query its length, and then write it with printf. The 0-return lets you embed printf into a complex expression without disturbing the order of the output.
Error handling
A wrong argument count (fewer arguments than specifiers), a type mismatch (for example passing a double to %d), or an unknown specifier are reported by the runtime as a runtime error, and the script stops. Non-printf errors (for example memory exhaustion) are rare, but also raise a runtime error. On a successful call, the output appears on stdout at once (flushing is automatic).
Unformatted output
Writes the text with no format-string interpretation — % characters pass through verbatim. Each operation is available in PascalCase and lowercase (Line/line, Print/print), following the printf/PrintF dual-naming convention. These are the recommended companions of the interpolated string literals ($"..."): the substituted value can never cause a formatting error.
print.Line / print.line
print.Line(text) -> intWrites the text unchanged, appends a newline, and flushes. The text is NOT a format string. Always returns 0.
string $Offer[32] = "50% off"; print.Line($"deal: $Offer"); print.Line("raw: %d %s %%");
deal: 50% off raw: %d %s %%
The counter-example matters: the same call through printf is a data-dependent runtime error — in printf($"deal: $Offer") the interpolated text lands in the format-string position, and once $Offer contains a %, the call stops with a runtime error. When mixing with real formatting, keep the interpolated part behind %s.
print.Print / print.print
print.Print(text) -> intThe same as Line without the trailing newline — for prompts, partial lines, and continued output. Always returns 0.
print.Print("prompt> "); print.print("continued"); print.Line(" <end");
prompt> continued <end
print.Error / print.error
print.Error(text) -> intThe script’s own error channel (since rev31zztt): the text plus a newline to stderr, flushed. In a pipeline (domin x.dom | sort) the script’s diagnostics stay out of the data. Not a format: a % in the text is a character.
print.ErrorF / print.errorf
print.ErrorF(format, ...) -> intprintf’s shape and checks (the same directive grammar, the same compile-time check of a literal format), written to stderr and flushed on every call. It first drains anything FastErrorF left in its buffer, so the family’s own order holds.
print.FastErrorF / print.fasterrorf
print.FastErrorF(format, ...) -> intErrorF without the per-call flush — the FastPrintF contract mirrored for stderr. The C library leaves stderr unbuffered (so the runtime’s own error lines leave at once), therefore this verb keeps its own 64 KiB buffer: Error/ErrorF drain it first, a full buffer drains itself, and exit() drains the rest — nothing is lost on a normal termination or a runtime error, but a runtime-error line may precede text still in the buffer, exactly as with FastPrintF.