feat: add keyboard layout support
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* config.h
|
||||
* Config file manager for MontaukOS programs
|
||||
* Loads, modifies, and saves TOML config files from 0:/config/
|
||||
* Loads, modifies, and saves TOML config files from 0:/config/ and
|
||||
* 0:/users/<name>/config/, and reads OS data tables from 0:/os/data/
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
@@ -187,29 +188,13 @@ namespace config {
|
||||
// ---- File operations ----
|
||||
|
||||
// Ensure the config directory exists
|
||||
inline void ensure_dir() {
|
||||
montauk::fmkdir(CONFIG_DIR);
|
||||
}
|
||||
|
||||
// Build full path: "0:/config/<name>.toml"
|
||||
inline void build_path(char* out, int outSz, const char* name) {
|
||||
int p = 0;
|
||||
const char* dir = CONFIG_DIR;
|
||||
while (*dir && p < outSz - 2) out[p++] = *dir++;
|
||||
out[p++] = '/';
|
||||
while (*name && p < outSz - 6) out[p++] = *name++;
|
||||
// Append ".toml"
|
||||
const char* ext = ".toml";
|
||||
while (*ext && p < outSz - 1) out[p++] = *ext++;
|
||||
out[p] = '\0';
|
||||
}
|
||||
|
||||
// Load a config file by name (without extension).
|
||||
// Returns an initialized Doc (empty if file doesn't exist).
|
||||
inline toml::Doc load(const char* name) {
|
||||
char path[128];
|
||||
build_path(path, sizeof(path), name);
|
||||
// ---- Shared file I/O (absolute path in, Doc out) ----
|
||||
// Only the path builders below know where each class of file lives. These
|
||||
// two do the actual work for system config, per-user config and OS data.
|
||||
|
||||
// Read and parse a TOML file at an absolute path.
|
||||
// Returns an initialized Doc (empty if the file is missing or empty).
|
||||
inline toml::Doc load_path(const char* path) {
|
||||
int handle = montauk::open(path);
|
||||
if (handle < 0) {
|
||||
toml::Doc doc;
|
||||
@@ -235,15 +220,9 @@ namespace config {
|
||||
return doc;
|
||||
}
|
||||
|
||||
// Save a Doc to disk as a TOML file.
|
||||
// Creates the file if it doesn't exist.
|
||||
// Returns 0 on success, negative on error.
|
||||
inline int save(const char* name, toml::Doc* doc) {
|
||||
ensure_dir();
|
||||
|
||||
char path[128];
|
||||
build_path(path, sizeof(path), name);
|
||||
|
||||
// Serialize a Doc and write it to an absolute path. The caller creates the
|
||||
// parent directory. Returns 0 on success, negative on error.
|
||||
inline int save_path(const char* path, toml::Doc* doc) {
|
||||
char* text = serialize(doc);
|
||||
int textLen = montauk::slen(text);
|
||||
|
||||
@@ -262,6 +241,42 @@ namespace config {
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
inline void ensure_dir() {
|
||||
montauk::fmkdir(CONFIG_DIR);
|
||||
}
|
||||
|
||||
// Build full path: "0:/config/<name>.toml"
|
||||
inline void build_path(char* out, int outSz, const char* name) {
|
||||
int p = 0;
|
||||
const char* dir = CONFIG_DIR;
|
||||
while (*dir && p < outSz - 2) out[p++] = *dir++;
|
||||
out[p++] = '/';
|
||||
while (*name && p < outSz - 6) out[p++] = *name++;
|
||||
// Append ".toml"
|
||||
const char* ext = ".toml";
|
||||
while (*ext && p < outSz - 1) out[p++] = *ext++;
|
||||
out[p] = '\0';
|
||||
}
|
||||
|
||||
// Load a config file by name (without extension).
|
||||
// Returns an initialized Doc (empty if file doesn't exist).
|
||||
inline toml::Doc load(const char* name) {
|
||||
char path[128];
|
||||
build_path(path, sizeof(path), name);
|
||||
return load_path(path);
|
||||
}
|
||||
|
||||
// Save a Doc to disk as a TOML file.
|
||||
// Creates the file if it doesn't exist.
|
||||
// Returns 0 on success, negative on error.
|
||||
inline int save(const char* name, toml::Doc* doc) {
|
||||
ensure_dir();
|
||||
|
||||
char path[128];
|
||||
build_path(path, sizeof(path), name);
|
||||
return save_path(path, doc);
|
||||
}
|
||||
|
||||
// ---- Per-user config ----
|
||||
|
||||
// Build path: "0:/users/<username>/config/<name>.toml"
|
||||
@@ -298,30 +313,7 @@ namespace config {
|
||||
inline toml::Doc load_user(const char* username, const char* name) {
|
||||
char path[192];
|
||||
build_user_path(path, sizeof(path), username, name);
|
||||
|
||||
int handle = montauk::open(path);
|
||||
if (handle < 0) {
|
||||
toml::Doc doc;
|
||||
doc.init();
|
||||
return doc;
|
||||
}
|
||||
|
||||
uint64_t size = montauk::getsize(handle);
|
||||
if (size == 0) {
|
||||
montauk::close(handle);
|
||||
toml::Doc doc;
|
||||
doc.init();
|
||||
return doc;
|
||||
}
|
||||
|
||||
char* text = (char*)montauk::malloc(size + 1);
|
||||
montauk::read(handle, (uint8_t*)text, 0, size);
|
||||
montauk::close(handle);
|
||||
text[size] = '\0';
|
||||
|
||||
toml::Doc doc = toml::parse(text);
|
||||
montauk::mfree(text);
|
||||
return doc;
|
||||
return load_path(path);
|
||||
}
|
||||
|
||||
// Save a per-user config file
|
||||
@@ -330,21 +322,7 @@ namespace config {
|
||||
|
||||
char path[192];
|
||||
build_user_path(path, sizeof(path), username, name);
|
||||
|
||||
char* text = serialize(doc);
|
||||
int textLen = montauk::slen(text);
|
||||
|
||||
montauk::fdelete(path);
|
||||
int handle = montauk::fcreate(path);
|
||||
if (handle < 0) {
|
||||
montauk::mfree(text);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = montauk::fwrite(handle, (const uint8_t*)text, 0, textLen);
|
||||
montauk::close(handle);
|
||||
montauk::mfree(text);
|
||||
return ret < 0 ? ret : 0;
|
||||
return save_path(path, doc);
|
||||
}
|
||||
|
||||
// Delete a config file. Returns 0 on success.
|
||||
@@ -426,4 +404,36 @@ namespace config {
|
||||
}
|
||||
|
||||
} // namespace config
|
||||
|
||||
// ---- Read-only OS data tables ----
|
||||
// Reference data that ships with the OS and is never written back: keyboard
|
||||
// layouts, time zone tables and the like. This lives under 0:/os because it is
|
||||
// OS payload, not configuration -- 0:/config is for state a user or admin
|
||||
// edits. There is deliberately no save() here, so the read-only nature of the
|
||||
// directory is enforced by the API rather than by convention.
|
||||
namespace data {
|
||||
|
||||
static constexpr const char* DATA_DIR = "0:/os/data";
|
||||
|
||||
// Build full path: "0:/os/data/<name>.toml"
|
||||
inline void build_path(char* out, int outSz, const char* name) {
|
||||
int p = 0;
|
||||
const char* dir = DATA_DIR;
|
||||
while (*dir && p < outSz - 2) out[p++] = *dir++;
|
||||
out[p++] = '/';
|
||||
while (*name && p < outSz - 6) out[p++] = *name++;
|
||||
const char* ext = ".toml";
|
||||
while (*ext && p < outSz - 1) out[p++] = *ext++;
|
||||
out[p] = '\0';
|
||||
}
|
||||
|
||||
// Load an OS data table by name (without extension).
|
||||
// Returns an initialized Doc (empty if the file is missing).
|
||||
inline toml::Doc load(const char* name) {
|
||||
char path[128];
|
||||
build_path(path, sizeof(path), name);
|
||||
return config::load_path(path);
|
||||
}
|
||||
|
||||
} // namespace data
|
||||
} // namespace montauk
|
||||
|
||||
Reference in New Issue
Block a user