From 0cc3a4e8b4c189f5a06238040cc6027ddfc940b2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 18:28:29 +0000 Subject: [PATCH 1/4] Initial plan From b2d45d7042f9a4033a493fd7a88d9344226c8a79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 18:34:21 +0000 Subject: [PATCH 2/4] Add .dmr files, documentation, and headers to release package Co-authored-by: JohnAmadis <17320783+JohnAmadis@users.noreply.github.com> --- .github/workflows/release.yml | 15 ++- dmini.dmr | 33 ++++++ docs/dmini.md | 200 ++++++++++++++++++++++++++++++++++ test_dmini.dmr | 12 ++ 4 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 dmini.dmr create mode 100644 docs/dmini.md create mode 100644 test_dmini.dmr diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef044ea..f3bcb5e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,8 +105,19 @@ jobs: if [ -f $DMF_DIR/test_dmini.dmd ]; then cp $DMF_DIR/test_dmini.dmd release_package/ fi - - # Copy documentation and license + + # Copy .dmr resource files + cp dmini.dmr release_package/ + cp test_dmini.dmr release_package/ + + # Copy header files + mkdir -p release_package/include + cp include/dmini.h release_package/include/ + cp $BUILD_DIR/dmini_defs.h release_package/include/ + + # Copy documentation + mkdir -p release_package/docs + cp -r docs/* release_package/docs/ cp README.md release_package/ cp LICENSE release_package/ diff --git a/dmini.dmr b/dmini.dmr new file mode 100644 index 0000000..89e4ac6 --- /dev/null +++ b/dmini.dmr @@ -0,0 +1,33 @@ +# DMOD Resource File for dmini +# This file specifies where resources should be installed + +# === Core Module === +# Main module file - always installed +dmf=./dmini.dmf => ${DMOD_DMF_DIR}/${module}.dmf + +# Compiled module (if exists) - always installed +dmfc=./dmini.dmfc => ${DMOD_DMF_DIR}/${module}.dmfc + +# Dependencies file (if exists) +dmd=./dmini.dmd => ${destination}/${module}.dmd + +# Version information +version=./dmini_version.txt => ${destination}/${module}_version.txt + +# === Documentation === +# Module documentation in markdown format for dmf-man tool +docs=./docs => ${destination}/${module}/docs + +# README file +readme=./README.md => ${destination}/${module}/README.md + +# === Header Files === +# Public API header +inc=./include/dmini.h => ${destination}/${module}/include/dmini.h + +# Generated module definitions header +inc_defs=./include/dmini_defs.h => ${destination}/${module}/include/dmini_defs.h + +# === License === +# License file +license=./LICENSE => ${destination}/${module}/LICENSE diff --git a/docs/dmini.md b/docs/dmini.md new file mode 100644 index 0000000..ad296c5 --- /dev/null +++ b/docs/dmini.md @@ -0,0 +1,200 @@ +# DMINI(3) + +## NAME + +dmini - DMOD INI File Parser Module + +## SYNOPSIS + +```c +#include "dmini.h" + +dmini_context_t dmini_create(void); +void dmini_destroy(dmini_context_t ctx); + +int dmini_parse_string(dmini_context_t ctx, const char* data); +int dmini_parse_file(dmini_context_t ctx, const char* filename); + +int dmini_generate_string(dmini_context_t ctx, char* buffer, size_t buffer_size); +int dmini_generate_file(dmini_context_t ctx, const char* filename); + +const char* dmini_get_string(dmini_context_t ctx, const char* section, + const char* key, const char* default_value); +int dmini_get_int(dmini_context_t ctx, const char* section, + const char* key, int default_value); + +int dmini_set_string(dmini_context_t ctx, const char* section, + const char* key, const char* value); +int dmini_set_int(dmini_context_t ctx, const char* section, + const char* key, int value); + +int dmini_has_section(dmini_context_t ctx, const char* section); +int dmini_has_key(dmini_context_t ctx, const char* section, const char* key); + +int dmini_remove_section(dmini_context_t ctx, const char* section); +int dmini_remove_key(dmini_context_t ctx, const char* section, const char* key); +``` + +## DESCRIPTION + +The **dmini** module provides a lightweight INI file parser and generator +optimized for embedded systems. It uses only DMOD SAL (System Abstraction +Layer) functions and implements memory-efficient line-by-line file I/O +operations. + +### INI File Format + +INI files consist of sections, key-value pairs, and comments: + +* Sections are defined by `[section_name]` +* Key-value pairs are defined by `key=value` +* Comments start with `;` or `#` +* Whitespace is automatically trimmed from keys and values +* Keys without section headers belong to the global section + +### Context Management + +**dmini_create()** creates a new INI context for storing sections and +key-value pairs. Returns a context pointer or NULL on error. + +**dmini_destroy()** frees all memory associated with an INI context. + +### Parsing + +**dmini_parse_string()** parses an INI file from a null-terminated string. +Returns DMINI_OK on success or an error code on failure. + +**dmini_parse_file()** parses an INI file from a file path using SAL file +functions. Uses line-by-line reading with 256-byte buffers. Returns DMINI_OK +on success or an error code on failure. + +### Generation + +**dmini_generate_string()** generates an INI file string from the context. +If buffer is NULL, returns the required buffer size. If buffer is not NULL, +fills it with the INI data. Returns required buffer size or a negative error +code. + +**dmini_generate_file()** generates an INI file from the context and writes +it directly to a file using line-by-line writing. Returns DMINI_OK on success +or an error code on failure. + +### Data Access + +**dmini_get_string()** retrieves a string value for the given section and key. +Pass NULL for section to access the global section. Returns the value string +or default_value if not found. + +**dmini_get_int()** retrieves an integer value for the given section and key. +Pass NULL for section to access the global section. Returns the integer value +or default_value if not found. + +**dmini_set_string()** sets a string value for the given section and key. +Creates the section if it doesn't exist. Pass NULL for section to access the +global section. Returns DMINI_OK on success or an error code on failure. + +**dmini_set_int()** sets an integer value for the given section and key. +Creates the section if it doesn't exist. Pass NULL for section to access the +global section. Returns DMINI_OK on success or an error code on failure. + +### Queries + +**dmini_has_section()** checks if a section exists in the context. Returns 1 +if the section exists, 0 otherwise. + +**dmini_has_key()** checks if a key exists in the specified section. Pass NULL +for section to check the global section. Returns 1 if the key exists, 0 +otherwise. + +### Removal + +**dmini_remove_section()** removes an entire section and all its keys from the +context. Returns DMINI_OK on success or an error code on failure. + +**dmini_remove_key()** removes a single key from the specified section. Pass +NULL for section to remove from the global section. Returns DMINI_OK on +success or an error code on failure. + +## RETURN VALUES + +Functions return the following error codes: + +* **DMINI_OK** (0) - Success +* **DMINI_ERR_GENERAL** (-1) - General error +* **DMINI_ERR_MEMORY** (-2) - Memory allocation error +* **DMINI_ERR_INVALID** (-3) - Invalid parameter +* **DMINI_ERR_NOT_FOUND** (-4) - Section or key not found +* **DMINI_ERR_FILE** (-5) - File I/O error + +## EXAMPLES + +### Basic Usage + +```c +#include "dmini.h" + +// Create context +dmini_context_t ctx = dmini_create(); + +// Parse INI file +dmini_parse_file(ctx, "config.ini"); + +// Read values +const char* host = dmini_get_string(ctx, "database", "host", "localhost"); +int port = dmini_get_int(ctx, "database", "port", 5432); + +// Modify values +dmini_set_string(ctx, "cache", "enabled", "true"); +dmini_set_int(ctx, "cache", "size", 1024); + +// Generate to file +dmini_generate_file(ctx, "output.ini"); + +// Cleanup +dmini_destroy(ctx); +``` + +### Querying Buffer Size + +```c +// Query required buffer size +int size = dmini_generate_string(ctx, NULL, 0); + +// Allocate buffer +char* buffer = Dmod_Malloc(size); + +// Generate INI to buffer +dmini_generate_string(ctx, buffer, size); + +// Use buffer... + +// Free buffer +Dmod_Free(buffer); +``` + +### Working with Global Section + +```c +// Set global key (no section) +dmini_set_string(ctx, NULL, "global_key", "global_value"); + +// Get global key +const char* val = dmini_get_string(ctx, NULL, "global_key", "default"); +``` + +## MEMORY FOOTPRINT + +* **dmini library**: 536B RAM, 5KB ROM +* **Line buffer**: 256 bytes (temporary, not persistent) + +## SEE ALSO + +dmod(3), dmod_loader(1) + +## AUTHOR + +Patryk Kubiak + +## LICENSE + +MIT License - Copyright (c) 2025 Choco-Technologies diff --git a/test_dmini.dmr b/test_dmini.dmr new file mode 100644 index 0000000..7afc0b4 --- /dev/null +++ b/test_dmini.dmr @@ -0,0 +1,12 @@ +# DMOD Resource File for test_dmini +# This file specifies where resources should be installed + +# === Core Module === +# Main module file - always installed +dmf=./test_dmini.dmf => ${DMOD_DMF_DIR}/${module}.dmf + +# Compiled module (if exists) - always installed +dmfc=./test_dmini.dmfc => ${DMOD_DMF_DIR}/${module}.dmfc + +# Version information +version=./test_dmini_version.txt => ${destination}/${module}_version.txt From b3197b344f83094808617afce13d1009e4fc4b35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 18:43:42 +0000 Subject: [PATCH 3/4] Fix dmini.dmr to use entire include directory for headers Co-authored-by: JohnAmadis <17320783+JohnAmadis@users.noreply.github.com> --- dmini.dmr | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dmini.dmr b/dmini.dmr index 89e4ac6..7f1249e 100644 --- a/dmini.dmr +++ b/dmini.dmr @@ -22,11 +22,8 @@ docs=./docs => ${destination}/${module}/docs readme=./README.md => ${destination}/${module}/README.md # === Header Files === -# Public API header -inc=./include/dmini.h => ${destination}/${module}/include/dmini.h - -# Generated module definitions header -inc_defs=./include/dmini_defs.h => ${destination}/${module}/include/dmini_defs.h +# Include directory with all headers (dmini.h and dmini_defs.h) +inc=./include => ${destination}/${module}/include # === License === # License file From dde368722bbd27d66ff36c81f12dbe1356ab227b Mon Sep 17 00:00:00 2001 From: Patryk Kubiak Date: Wed, 10 Dec 2025 19:52:47 +0100 Subject: [PATCH 4/4] Update dmr files: change 'Compiled module' to 'Compressed module' for clarity --- dmini.dmr | 2 +- test_dmini.dmr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dmini.dmr b/dmini.dmr index 7f1249e..fed4f13 100644 --- a/dmini.dmr +++ b/dmini.dmr @@ -5,7 +5,7 @@ # Main module file - always installed dmf=./dmini.dmf => ${DMOD_DMF_DIR}/${module}.dmf -# Compiled module (if exists) - always installed +# Compressed module dmfc=./dmini.dmfc => ${DMOD_DMF_DIR}/${module}.dmfc # Dependencies file (if exists) diff --git a/test_dmini.dmr b/test_dmini.dmr index 7afc0b4..4594cb1 100644 --- a/test_dmini.dmr +++ b/test_dmini.dmr @@ -5,7 +5,7 @@ # Main module file - always installed dmf=./test_dmini.dmf => ${DMOD_DMF_DIR}/${module}.dmf -# Compiled module (if exists) - always installed +# Compressed module dmfc=./test_dmini.dmfc => ${DMOD_DMF_DIR}/${module}.dmfc # Version information