Files
2026-08-22 07:44:34 +02:00

237 lines
7.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="MontaukOS userspace configuration and TOML API">
<title>Configuration and TOML - MontaukOS</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Open Sans', Arial, sans-serif;
max-width: 960px;
margin: 0 auto;
padding: 1em;
line-height: 1.5;
display: flex;
gap: 2em;
}
p { margin: 0 0 0.75em; }
h2 { margin: 1.25em 0 0.5em; }
h3 { margin: 1em 0 0.35em; }
.sidebar { width: 160px; flex-shrink: 0; }
.sidebar ul { list-style: none; padding: 0; }
.sidebar li { margin: 0.5em 0; }
.sidebar a { color: #0066CC; text-decoration: none; font-weight: 600; }
.sidebar a:hover { color: #004499; text-decoration: underline; }
.sidebar .current { color: #004499; }
.sidebar hr { border: none; border-top: 1px solid #999; margin: 0.75em 0; }
.main { flex: 1; min-width: 0; }
a { color: #0000EE; }
a:visited { color: #0066CC; }
hr { border-style: solid; border-width: 1px 0 0 0; border-color: #999; }
.center { text-align: center; }
pre {
background: #f4f4f4;
border: 1px solid #ccc;
padding: 0.75em;
overflow-x: auto;
}
code { font-family: monospace; }
@media (max-width: 700px) {
body { flex-direction: column; gap: 1em; padding: 1em 0.75em; }
.sidebar { width: auto; }
.sidebar ul { display: flex; flex-wrap: wrap; gap: 0 1em; }
.sidebar hr { width: 100%; }
}
</style>
</head>
<body>
<div class="sidebar">
<ul>
<li><a href="../../index.html">Home</a></li>
<li><a href="../../downloads.html">Downloads</a></li>
<li><a href="../index.html">Documentation</a></li>
<li><a href="https://git.montaukos.org/daniel/MontaukOS/issues">Issue tracker</a></li>
<li><a href="https://git.montaukos.org/daniel/MontaukOS">Git</a></li>
</ul>
<hr>
<ul>
<li><a href="index.html">Application Programming Manual</a></li>
<li><a href="config.html" class="current">Configuration and TOML</a></li>
</ul>
</div>
<div class="main">
<div class="center">
<h1>Configuration and TOML</h1>
</div>
<hr>
<p>MontaukOS provides a small header-only C++ API for reading and writing
TOML configuration files from userspace. Include
<code>&lt;montauk/config.h&gt;</code> for file-backed configuration and
<code>&lt;montauk/toml.h&gt;</code> for the in-memory TOML document model.</p>
<h2>Configuration locations</h2>
<p>System configuration is stored in <code>0:/config</code>. The API accepts a
name without the <code>.toml</code> extension:</p>
<pre><code>0:/config/desktop.toml
0:/config/network.toml</code></pre>
<p>Per-user configuration is stored below the user directory:</p>
<pre><code>0:/users/&lt;username&gt;/config/&lt;name&gt;.toml</code></pre>
<h2>Loading and saving</h2>
<pre><code>#include &lt;montauk/config.h&gt;
auto doc = montauk::config::load("desktop");
const char* theme = doc.get_string("appearance.theme", "light");
montauk::config::set_string(&amp;doc, "appearance.theme", "dark");
int result = montauk::config::save("desktop", &amp;doc);
doc.destroy();</code></pre>
<p><code>load()</code> returns an initialized empty document if the file does
not exist. <code>save()</code> creates the configuration directory and returns
<code>0</code> on success or a negative value on error. Saving rewrites the
whole file.</p>
<h3>System configuration API</h3>
<pre><code>toml::Doc config::load(const char* name);
int config::save(const char* name, toml::Doc* doc);
int config::remove(const char* name);</code></pre>
<h3>Per-user configuration API</h3>
<pre><code>toml::Doc config::load_user(const char* username, const char* name);
int config::save_user(const char* username,
const char* name,
toml::Doc* doc);</code></pre>
<p>For example:</p>
<pre><code>auto doc = montauk::config::load_user("alice", "desktop");
bool clock24 = doc.get_bool("display.clock_24h", false);
montauk::config::set_bool(&amp;doc, "display.clock_24h", true);
montauk::config::save_user("alice", "desktop", &amp;doc);
doc.destroy();</code></pre>
<h2>Reading values</h2>
<p>Keys may use dotted paths corresponding to TOML tables:</p>
<pre><code>[server]
host = "pool.ntp.org"
port = 123
enabled = true</code></pre>
<pre><code>const char* host = doc.get_string("server.host", "localhost");
int64_t port = doc.get_int("server.port", 80);
bool enabled = doc.get_bool("server.enabled", false);</code></pre>
<p>Typed getters return their default when the key is absent or has another
type. The available value types are:</p>
<pre><code>toml::Type::String
toml::Type::Int
toml::Type::Bool
toml::Type::Array
toml::Type::Table</code></pre>
<p>Arrays and tables are returned as <code>toml::Value*</code>. Their children
are available through <code>value-&gt;array.items</code> and
<code>value-&gt;array.count</code>:</p>
<pre><code>auto* names = doc.get_array("server.names");
if (names) {
for (int i = 0; i &lt; names-&gt;array.count; ++i) {
auto* item = names-&gt;array.items[i];
if (item-&gt;type == montauk::toml::Type::String)
montauk::print(item-&gt;str);
}
}</code></pre>
<h2>Modifying documents</h2>
<pre><code>void config::set_string(toml::Doc* doc,
const char* key, const char* value);
void config::set_int(toml::Doc* doc,
const char* key, int64_t value);
void config::set_bool(toml::Doc* doc,
const char* key, bool value);
bool config::unset(toml::Doc* doc, const char* key);</code></pre>
<p>The setters overwrite an existing value or append a new one. The
<code>unset()</code> return value is <code>true</code> when a matching key was
removed.</p>
<h2>Parsing and serialization</h2>
<p>Use <code>toml::parse()</code> when TOML is already available in memory:</p>
<pre><code>const char* text =
"[server]\n"
"port = 8080\n"
"enabled = true\n";
auto doc = montauk::toml::parse(text);
int64_t port = doc.get_int("server.port");
doc.destroy();</code></pre>
<p>A document can be serialized to newly allocated TOML text:</p>
<pre><code>char* text = montauk::config::serialize(&amp;doc);
// Use text...
montauk::mfree(text);</code></pre>
<p>Serialization produces normalized TOML and does not preserve comments or
the original formatting.</p>
<h2>Memory ownership</h2>
<p><code>toml::Doc</code> owns its parsed values and strings. Every document
returned by <code>load()</code>, <code>load_user()</code>, or
<code>toml::parse()</code> must eventually be released with
<code>doc.destroy()</code>.</p>
<p>When constructing a document manually, initialize it before using the
mutation helpers:</p>
<pre><code>montauk::toml::Doc doc;
doc.init();
montauk::config::set_bool(&amp;doc, "enabled", true);
montauk::config::save("example", &amp;doc);
doc.destroy();</code></pre>
<h2>Supported TOML features</h2>
<p>The userspace parser supports strings, literal and multiline strings,
integers (including hexadecimal, octal, and binary forms), booleans, arrays,
tables, inline tables, dotted keys, and comments.</p>
<p>There are no typed float or datetime accessors. Callers should also treat
configuration names and usernames as safe path components, since they are
used to construct filesystem paths.</p>
<hr>
<div class="center">
<a href="index.html">Back to Application Programming Manual</a>
</div>
</div>
</body>
</html>