From d39ed7f9fed1d8755258c7cfaf99f4eaf224a4c6 Mon Sep 17 00:00:00 2001 From: yukkop Date: Mon, 24 Mar 2025 13:36:31 +0000 Subject: [PATCH] refactor(hmpl,hectic): warnings --- flake.nix | 4 + package/c/hectic/default.nix | 21 ++-- package/c/hectic/hectic.c | 44 +++----- package/c/hectic/hectic.h | 36 +++++- package/c/hectic/make.sh | 101 +++++++++++++++++ package/c/hectic/test/01-arena.c | 2 +- package/c/hmpl/README.md | 82 ++++++++++++++ package/c/hmpl/default.nix | 29 +---- package/c/hmpl/hmpl.c | 181 ++++++++++++++++++++++++------- package/c/hmpl/hmpl.h | 5 +- package/c/hmpl/main.c | 2 +- package/c/hmpl/make.sh | 105 ++++++++++++++++++ package/c/hmpl/test/test.c | 42 ++++++- 13 files changed, 537 insertions(+), 117 deletions(-) create mode 100644 package/c/hectic/make.sh create mode 100644 package/c/hmpl/README.md create mode 100644 package/c/hmpl/make.sh diff --git a/flake.nix b/flake.nix index ff13d0d..e7bd2bb 100644 --- a/flake.nix +++ b/flake.nix @@ -94,6 +94,10 @@ devShells.${system} = let shells = self.devShells.${system}; in { + c = pkgs.mkShell { + buildInputs = (with pkgs; [ gdb gcc ]) ++ (with self.packages.${system}; [ hectic nvim-pager]); + PAGER = "${self.packages.${system}.nvim-pager}/bin/pager"; + }; default = pkgs.mkShell { buildInputs = (with self.packages.${system}; [ diff --git a/package/c/hectic/default.nix b/package/c/hectic/default.nix index 5841e7a..f73ddfb 100644 --- a/package/c/hectic/default.nix +++ b/package/c/hectic/default.nix @@ -1,4 +1,4 @@ -{ stdenv, gcc, lib }: +{ stdenv, gcc, lib, bash }: stdenv.mkDerivation { pname = "hectic"; @@ -6,22 +6,15 @@ stdenv.mkDerivation { src = ./.; doCheck = true; + nativeBuildInputs = [ gcc ]; + buildPhase = '' - mkdir -p target - ${gcc}/bin/cc -Wall -Wextra -g \ - -std=c99 \ - -pedantic -fsanitize=address \ - -c hectic.c -o target/hectic.o - ${gcc}/bin/ar rcs target/libhectic.a target/hectic.o + ls + ${bash}/bin/sh ./make.sh build ''; checkPhase = '' - mkdir -p target/test - for test_file in test/*.c; do - exe="target/test/$(basename ''${test_file%.c})" - ${gcc}/bin/cc -Wall -Wextra -g -pedantic -fsanitize=address -I. "$test_file" -Ltarget -lhectic -o "$exe" - "$exe" - done + ${bash}/bin/sh ./make.sh check ''; installPhase = '' @@ -31,7 +24,7 @@ stdenv.mkDerivation { ''; meta = { - description = "libhectic"; + description = "hectic"; license = lib.licenses.mit; }; } diff --git a/package/c/hectic/hectic.c b/package/c/hectic/hectic.c index 808d17d..e5e9442 100644 --- a/package/c/hectic/hectic.c +++ b/package/c/hectic/hectic.c @@ -10,6 +10,7 @@ void set_output_color_mode(ColorMode mode) { const char* log_level_to_string(LogLevel level) { switch (level) { + case LOG_LEVEL_TRACE: return "TRACE"; case LOG_LEVEL_DEBUG: return "DEBUG"; case LOG_LEVEL_LOG: return "LOG"; case LOG_LEVEL_INFO: return "INFO"; @@ -22,7 +23,9 @@ const char* log_level_to_string(LogLevel level) { LogLevel log_level_from_string(const char *level_str) { if (!level_str) return LOG_LEVEL_INFO; - if (strcmp(level_str, "DEBUG") == 0) + if (strcmp(level_str, "TRACE") == 0) + return LOG_LEVEL_TRACE; + else if (strcmp(level_str, "DEBUG") == 0) return LOG_LEVEL_DEBUG; else if (strcmp(level_str, "LOG") == 0) return LOG_LEVEL_LOG; @@ -75,22 +78,11 @@ char* log_message(LogLevel level, char *file, int line, const char *format, ...) return timeStr; } -// ----------- -// -- utils -- -// ----------- +// ---------- +// -- misc -- +// ---------- -void substr(const char *src, char *dest, size_t start, size_t len) { - raise_debug("substring %s from %zu to %zu", src, start, len); - size_t srclen = strlen(src); - if (start >= srclen) { - dest[0] = '\0'; - return; - } - if (start + len > srclen) - len = srclen - start; - strncpy(dest, src + start, len); - dest[len] = '\0'; -} +//void fomatBytes(size_t bytes, char ) // ---------- // -- Json -- @@ -223,7 +215,7 @@ static Json *json_parse_value__(const char **s, Arena *arena) { if (!item) return NULL; memset(item, 0, sizeof(Json)); item->type = JSON_STRING; - item->string = json_parse_string__(s, arena); + item->JsonValue.string = json_parse_string__(s, arena); return item; } else if (strncmp(*s, "null", 4) == 0) { Json *item = arena_alloc(arena, sizeof(Json)); @@ -237,7 +229,7 @@ static Json *json_parse_value__(const char **s, Arena *arena) { if (!item) return NULL; memset(item, 0, sizeof(Json)); item->type = JSON_BOOL; - item->boolean = 1; + item->JsonValue.boolean = 1; *s += 4; return item; } else if (strncmp(*s, "false", 5) == 0) { @@ -245,7 +237,7 @@ static Json *json_parse_value__(const char **s, Arena *arena) { if (!item) return NULL; memset(item, 0, sizeof(Json)); item->type = JSON_BOOL; - item->boolean = 0; + item->JsonValue.boolean = 0; *s += 5; return item; } else if ((**s == '-') || isdigit((unsigned char)**s)) { @@ -253,7 +245,7 @@ static Json *json_parse_value__(const char **s, Arena *arena) { if (!item) return NULL; memset(item, 0, sizeof(Json)); item->type = JSON_NUMBER; - item->number = json_parse_number__(s); + item->JsonValue.number = json_parse_number__(s); return item; } else if (**s == '[') { return json_parse_array__(s, arena); @@ -267,14 +259,14 @@ Json *json_parse(Arena *arena, const char **s) { return json_parse_value__(s, arena); } -char *json_to_string(Arena *arena, Json *item) { +char *json_to_string(Arena *arena, const Json * const item) { return json_to_string_with_opts(arena, item, JSON_NORAW); } /* Minimal JSON printer with raw output option. When raw is non-zero and the item is a JSON_STRING, it is printed without quotes. */ -char *json_to_string_with_opts(Arena *arena, Json *item, JsonRawOpt raw) { +char *json_to_string_with_opts(Arena *arena, const Json * const item, JsonRawOpt raw) { char *out = arena_alloc(arena, 1024); if (!out) return NULL; @@ -304,13 +296,13 @@ char *json_to_string_with_opts(Arena *arena, Json *item, JsonRawOpt raw) { sprintf(ptr, "]"); } else if (item->type == JSON_STRING) { if ((int)raw) - sprintf(ptr, "%s", item->string); + sprintf(ptr, "%s", item->JsonValue.string); else - sprintf(ptr, "\"%s\"", item->string); + sprintf(ptr, "\"%s\"", item->JsonValue.string); } else if (item->type == JSON_NUMBER) { - sprintf(ptr, "%g", item->number); + sprintf(ptr, "%g", item->JsonValue.number); } else if (item->type == JSON_BOOL) { - sprintf(ptr, item->boolean ? "true" : "false"); + sprintf(ptr, item->JsonValue.boolean ? "true" : "false"); } else if (item->type == JSON_NULL) { sprintf(ptr, "null"); } diff --git a/package/c/hectic/hectic.h b/package/c/hectic/hectic.h index 11db898..ec64370 100644 --- a/package/c/hectic/hectic.h +++ b/package/c/hectic/hectic.h @@ -1,6 +1,9 @@ #ifndef EPRINTF_HECTIC #define EPRINTF_HECTIC +// NOTE(yukkop): definitions and features from the POSIX.1-2008 standard +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -30,7 +33,7 @@ typedef enum { } ColorMode; // Static color mode variable -static ColorMode color_mode = COLOR_MODE_AUTO; +static ColorMode color_mode __attribute__((unused)) = COLOR_MODE_AUTO; // Function to set color mode void set_output_color_mode(ColorMode mode); @@ -62,6 +65,7 @@ void set_output_color_mode(ColorMode mode); // ------------ typedef enum { + LOG_LEVEL_TRACE, LOG_LEVEL_DEBUG, LOG_LEVEL_LOG, LOG_LEVEL_INFO, @@ -78,6 +82,15 @@ LogLevel log_level_from_string(const char *level_str); char* log_message(LogLevel level, char *file, int line, const char *format, ...); +#define raise_trace_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_TRACE, file, line, fmt, ##__VA_ARGS__) +#define raise_debug_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_DEBUG, file, line, fmt, ##__VA_ARGS__) +#define raise_log_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_LOG, file, line, fmt, ##__VA_ARGS__) +#define raise_info_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_INFO, file, line, fmt, ##__VA_ARGS__) +#define raise_notice_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_NOTICE, file, line, fmt, ##__VA_ARGS__) +#define raise_warn_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_WARN, file, line, fmt, ##__VA_ARGS__) +#define raise_exception_with_opt(file, line, fmt, ...) log_message(LOG_LEVEL_EXCEPTION, file, line, fmt, ##__VA_ARGS__) + +#define raise_trace(fmt, ...) log_message(LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define raise_debug(fmt, ...) log_message(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define raise_log(fmt, ...) log_message(LOG_LEVEL_LOG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define raise_info(fmt, ...) log_message(LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) @@ -89,7 +102,7 @@ char* log_message(LogLevel level, char *file, int line, const char *format, ...) // -- arena -- // ----------- -#define ARENA_DEFAULT_SIZE 1024 +#define ARENA_DEFAULT_SIZE MEM_MiB typedef struct { void *begin; @@ -100,6 +113,7 @@ typedef struct { // NOTE(yukkop): This macro is used to define procedures so that `__LINE__` and `__FILE__` // in `raise_debug` reflect the location where the macro is called, not where it's defined. #define arena_alloc_or_null(arena, size) __extension__ ({ \ + raise_trace("arena_alloc_or_null(%p, %zu)", (arena), (size)); \ void *mem__ = NULL; \ if ((arena)->begin == 0) { \ *(arena) = arena_init(ARENA_DEFAULT_SIZE); \ @@ -196,7 +210,17 @@ typedef struct { // -- misc -- // ---------- -void substr(const char *src, char *dest, size_t start, size_t len); +#define MEM_b 1 +#define MEM_KiB 1024 +#define MEM_MiB (MEM_KiB * 1024) +#define MEM_GiB (MEM_MiB * 1024) +#define MEM_TiB (MEM_TiB * 1024) +#define MEM_PiB (MEM_TiB * 1024) +#define MEM_EiB (MEM_PiB * 1024) +#define MEM_ZiB (MEM_EiB * 1024) +#define MEM_YiB (MEM_ZiB * 1024) +#define MEM_RiB (MEM_YiB * 1024) +#define MEM_QiB (MEM_RiB * 1024) // ---------- // -- Json -- @@ -226,14 +250,14 @@ typedef struct Json { double number; char *string; int boolean; - }; + } JsonValue; } Json; Json *json_parse(Arena *arena, const char **s); -char *json_to_string(Arena *arena, Json *item); +char *json_to_string(Arena *arena, const Json * const item); -char *json_to_string_with_opts(Arena *arena, Json *item, JsonRawOpt raw); +char *json_to_string_with_opts(Arena *arena, const Json * const item, JsonRawOpt raw); /* Retrieve an object item by key (case-sensitive) */ Json *json_get_object_item(Json *object, const char *key); diff --git a/package/c/hectic/make.sh b/package/c/hectic/make.sh new file mode 100644 index 0000000..fa83dea --- /dev/null +++ b/package/c/hectic/make.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# Usage: make.sh [build|check] [--norun] [--debug] [--color] +# Options: +# build Build the library and app (default if no mode is provided). +# check Build tests; runs them unless --norun is specified. +# --norun (check only) Build tests but do not run them. +# --debug Build with -O0 (debug mode). +# --color Pass -fdiagnostics-color=always to compiler. +# help, --help Show this help message. + +check_dependencies() { + for dep in cc ar; do + if ! command -v "$dep" >/dev/null 2>&1; then + echo "Error: Required dependency '$dep' not found." >&2 + exit 1 + fi + done +} +check_dependencies + +print_help() { + cat <template_name}} +``` + +result +```hmpl +``` + +## Order +used plain render +interpolation->section->include + +so you cannot render interpolation in interpolation or section + +Not allowed: +```hmpl +{{name_{{subname}}}} +{{#array_{{subname}}}} +``` + +But: +```hmpl +{{>{{template_name}}}} +``` +allowed; + +№ эксепшн на нераскрытые diff --git a/package/c/hmpl/default.nix b/package/c/hmpl/default.nix index 4ed9ee9..6d310cf 100644 --- a/package/c/hmpl/default.nix +++ b/package/c/hmpl/default.nix @@ -1,4 +1,4 @@ -{ stdenv, gcc, lib, hectic }: +{ stdenv, gcc, lib, hectic, bash }: stdenv.mkDerivation { pname = "hmpl"; @@ -7,35 +7,14 @@ stdenv.mkDerivation { doCheck = true; buildInputs = [ hectic ]; + nativeBuildInputs = [ gcc ]; buildPhase = '' - mkdir -p target - - echo "# Build library" - ${gcc}/bin/cc -Wall -Wextra -g \ - -std=c99 \ - -pedantic -fsanitize=address -c hmpl.c \ - -lhectic \ - -o target/hmpl.o - ${gcc}/bin/ar rcs target/libhmpl.a target/hmpl.o - - echo "# Build app" - ${gcc}/bin/cc -Wall -Wextra -g \ - -pedantic -fsanitize=address main.c \ - -Ltarget -lhmpl \ - -lhectic -o target/hmpl + ${bash}/bin/sh ./build.sh ''; checkPhase = '' - mkdir -p target/test - export LOG_LEVEL=DEBUG - for test_file in test/*.c; do - exe="target/test/$(basename ''${test_file%.c})" - ${gcc}/bin/cc -Wall -Wextra -g -pedantic \ - -fsanitize=address -I. "$test_file" \ - -Ltarget -lhmpl -lhectic -o "$exe" - "$exe" - done + ${bash}/bin/sh ./check.sh ''; installPhase = '' diff --git a/package/c/hmpl/hmpl.c b/package/c/hmpl/hmpl.c index f8d70e8..84a7953 100644 --- a/package/c/hmpl/hmpl.c +++ b/package/c/hmpl/hmpl.c @@ -1,9 +1,9 @@ #include "hmpl.h" -char *eval(Arena *arena, const Json * const context, const char * const query) { +Json *eval_object(Arena *arena, const Json * const context, const char * const query) { if (!context || !query) return NULL; - Json *res = context; + const Json *res = context; char *dot, *key = arena_strdup(arena, query); while ((dot = strchr(key, '.')) != NULL) { @@ -16,10 +16,13 @@ char *eval(Arena *arena, const Json * const context, const char * const query) { } raise_debug("res: %s, key: %s, query: %s", json_to_string(arena, res), key, query); - res = json_get_object_item(res, key); + return json_get_object_item(res, key); +} + +char *eval_string(Arena *arena, const Json * const context, const char * const query) { + Json *res = eval_object(arena, context, query); if (!res) return NULL; - return json_to_string_with_opts(arena, res, JSON_RAW); } @@ -27,7 +30,7 @@ char *eval(Arena *arena, const Json * const context, const char * const query) { // {{[prefix]key}} void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context, const char * const prefix) { raise_debug("hmpl_render_interpolation_tags"); - char start_pattern[8]; + char start_pattern[256]; snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix); int start_pattern_length = strlen(start_pattern); int offset = 0; @@ -46,9 +49,9 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context raise_exception("Malformed template: missing closing braces for interpolation tag"); int key_length = (end - current_text) - key_start; char *key = arena_alloc(arena, key_length + 1); - substr(current_text, key, key_start, key_length); + substr_clone(current_text, key, key_start, key_length); - char *replacement = eval(arena, context, key); + char *replacement = eval_string(arena, context, key); if (!replacement) { offset = (end - current_text) + 2; continue; @@ -87,7 +90,7 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context // END IF; // // -- Extract the key used for the loop. -// loop_key := substring(result from loop_start + 3 for key_end - loop_start - 3); +// loop_key := substr_cloneing(result from loop_start + 3 for key_end - loop_start - 3); // // RAISE DEBUG 'loop key %', loop_key; // @@ -98,7 +101,7 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context // END IF; // // -- Extract the inner block of the loop. -// block := substring(result from key_end + 2 for loop_end - key_end - 2); +// block := substr_cloneing(result from key_end + 2 for loop_end - key_end - 2); // // -- Retrieve the JSON array from the context for the loop key. // arr := eval_value(context, loop_key); @@ -121,43 +124,141 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context // END IF; // // -- Replace the entire loop block in the result with the rendered content. -// result := substring(result from 1 for loop_start - 1) +// result := substr_cloneing(result from 1 for loop_start - 1) // || rendered_block -// || substring(result from loop_end + char_length('{{/#' || loop_key || '}}')); +// || substr_cloneing(result from loop_end + char_length('{{/#' || loop_key || '}}')); // END LOOP; // // RETURN result; // END $$; +void substr_clone(const char *src, char *dest, size_t start, size_t len) { + raise_debug("substr_cloneing %s (%p) from %p to %zu", src, src, start, len); + size_t srclen = strlen(src); + if (start >= srclen) { + dest[0] = '\0'; + return; + } + if (start + len > srclen) + len = srclen - start; + strncpy(dest, src + start, len); + dest[len] = '\0'; + raise_trace("%s", dest); +} + // {{#array_key}} -// void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, const char * const prefix){ -// raise_debug("hmpl_render_section_tags"); -// char start_pattern[8]; -// snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix); -// int start_pattern_length = strlen(start_pattern); -// int offset = 0; -// -// while (1) { -// char *current_text = *text_ptr; -// char *opening_tag_start = strstr(current_text + offset, start_pattern); -// if (!opening_tag_start) -// break; -// -// int start_index = start - current_text; -// int key_start = start_index + start_pattern_length; -// -// char *end = strstr(start, "}}"); -// if (!end) -// raise_exception("Malformed template: missing closing braces for section tag"); -// int key_length = (end - current_text) - key_start; -// -// -// char *key = arena_alloc(arena, key_length + 1); -// substr(current_text, key, key_start, key_length); -// -// char *arr = eval(arena, context, key); -// } -// } +void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, const char * const prefix_start, const char * const prefix_end, const char * const separator_pattern){ + raise_debug("hmpl_render_section_tags"); + printf('key'); + char start_pattern[32]; + snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix_start); + int start_pattern_length = strlen(start_pattern); + + // TODO: rename close_tag_start_pattern + char end_pattern[32]; + snprintf(end_pattern, sizeof(end_pattern), "{{%s", prefix_end); + int end_pattern_length = strlen(end_pattern); + + int separator_pattern_length = strlen(separator_pattern); + if (!separator_pattern || separator_pattern_length == 0) { + raise_exception("Unexpected usage: separator pattern cannot be empty"); + } + + int offset = 0; + + while (1) { + printf('key'); + char *current_text = *text_ptr; + char *opening_tag_start = strstr(current_text + offset, start_pattern); + if (!opening_tag_start) + break; + int start_index = opening_tag_start - current_text; + int relative_key_start = start_index + start_pattern_length; + + char *opening_tag_separator = strstr(opening_tag_start, separator_pattern); + if (!opening_tag_start) { + raise_exception("Malformed template: missing separator for section tag or not specifiet name for element"); + exit(1); + } + int separator_index = opening_tag_separator - current_text; + int element_name_start = separator_index + separator_pattern_length; + + char *opening_tag_end = strstr(opening_tag_separator, "}}"); + if (!opening_tag_end) { + raise_exception("Malformed template: missing closing braces for section tag"); + exit(1); + } + printf('key'); + + printf('key'); + assert((size_t)opening_tag_end > (size_t)opening_tag_separator); + assert((size_t)opening_tag_separator > (size_t)opening_tag_start); + printf('key'); + + int key_length = (opening_tag_separator - current_text) - relative_key_start; + assert(key_length > 0); + printf('key'); + char *key = arena_alloc(arena, key_length + 1); + printf('key'); + //substr_clone(current_text, key, relative_key_start, key_length); + key[2] = 'c'; + char c=key[2]; + printf('key'); + printf('key: %d\n', c); + printf('key: %p\n', key[2]); + printf('key: %p\n', key); + + int element_name_length = (opening_tag_end - current_text) - element_name_start; + assert(element_name_length > 0); + + char *element_name = arena_alloc(arena, element_name_length + 1); + substr_clone(current_text, element_name, element_name_start, element_name_length); + + int close_tag_patern_length = start_pattern_length + key_length + end_pattern_length; + char *close_tag_patern = arena_alloc(arena, close_tag_patern_length + 1); + snprintf(close_tag_patern, sizeof(close_tag_patern), "%s%s%s", start_pattern, key, end_pattern); + + char *close_tag = strstr(opening_tag_end + offset + 1, close_tag_patern); + if (!close_tag) { + raise_exception('Malformed template: missing loop end for key %s', key); + exit(1); + } + + Json *arr = eval_object(arena, context, key); + + if (arr && arr->type == JSON_ARRAY) { + size_t elem_count = 0; + for (Json *e = arr->child; e; e = e->next) elem_count++; + + char *replacement = arena_alloc(arena, MEM_KiB * elem_count); + size_t offset = 0; + + for (Json *elem = arr->child; elem; elem = elem->next) { + char *block = arena_alloc(arena, MEM_KiB); + substr_clone(current_text, block, opening_tag_end + 2, close_tag - opening_tag_end - 2); + + char *prefix = arena_alloc(arena, element_name_length + 2); + snprintf(prefix, element_name_length + 2, "%s.", element_name); + + hmpl_render_interpolation_tags(arena, block, context, prefix); + + size_t block_len = strlen(block); + memcpy(replacement + offset, block, block_len); + offset += block_len; + } + + replacement[offset] = '\0'; + + char *new_text = arena_repstr(arena, current_text, + opening_tag_start - 1, + close_tag + close_tag_patern_length - opening_tag_start + 1, + replacement); + + *text_ptr = new_text; + } + offset = start_index; + } +} void hmpl_render_with_arena(Arena *arena, char **text, const Json * const context) { if (context->type != JSON_OBJECT) { @@ -169,7 +270,7 @@ void hmpl_render_with_arena(Arena *arena, char **text, const Json * const contex } void hmpl_render(char **text, const Json * const context) { - Arena arena = arena_init(1024 * 1024); + Arena arena = arena_init(MEM_MiB); hmpl_render_with_arena(&arena, text, context); diff --git a/package/c/hmpl/hmpl.h b/package/c/hmpl/hmpl.h index 27233d0..ccfd11c 100644 --- a/package/c/hmpl/hmpl.h +++ b/package/c/hmpl/hmpl.h @@ -5,15 +5,18 @@ #include #include #include +#include #include "hectic.h" void init_cjson_with_arenas(Arena *arena); -char *eval(Arena *arena, const Json * const context, const char * const key); +char *eval_string(Arena *arena, const Json * const context, const char * const key); /* Modified: text is passed by reference so we can update it and free old allocations */ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, Json *context, const char * const prefix); +void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, const char * const prefix_start, const char * const prefix_end, const char * const separator_pattern); + void render_template_with_arena(Arena *arena, char **text, const Json * const ccontext); void render_template(char **text, const Json * const context); diff --git a/package/c/hmpl/main.c b/package/c/hmpl/main.c index 252792a..d986674 100644 --- a/package/c/hmpl/main.c +++ b/package/c/hmpl/main.c @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) { init_logger(); raise_info("start"); - Arena arena = arena_init(1024 * 1024); + Arena arena = arena_init(MEM_MiB); raise_info("read the arguments"); char *text = NULL; diff --git a/package/c/hmpl/make.sh b/package/c/hmpl/make.sh new file mode 100644 index 0000000..aeb2484 --- /dev/null +++ b/package/c/hmpl/make.sh @@ -0,0 +1,105 @@ +#!/bin/sh +# Usage: make.sh [build|check] [--norun] [--debug] [--color] +# Options: +# build Build the library and app (default if no mode is provided). +# check Build tests; runs them unless --norun is specified. +# --norun (check only) Build tests but do not run them. +# --debug Build with -O0 (debug mode). +# --color Pass -fdiagnostics-color=always to compiler. +# help, --help Show this help message. + +check_dependencies() { + for dep in cc ar; do + if ! command -v "$dep" >/dev/null 2>&1; then + echo "Error: Required dependency '$dep' not found." >&2 + exit 1 + fi + done +} +check_dependencies + +print_help() { + cat <