feat(hmpl): render simple placeholder with memory leak of course

This commit is contained in:
2025-03-21 04:00:23 +00:00
parent 9438280750
commit c4d14e5aa2
8 changed files with 125 additions and 37 deletions

View File

@@ -3,7 +3,8 @@
#include <string.h>
#include <unistd.h>
//#include "libhmpl.h"
#include "libhectic.h"
#include "chectic.h"
#include "cjson/cJSON.h"
#define KB128 131072
@@ -47,7 +48,7 @@
// _offset := simple_start + start_pattern_length;
// RAISE LOG '% := % + %', _offset, simple_start, start_pattern_length;
// IF _offset = 0 THEN
// RAISE EXCEPTION 'Malformed template: offcet cannot be 0';
// RAISE EXCEPTION 'Malformed template: offset cannot be 0';
// END IF;
// CONTINUE;
// END IF;
@@ -59,8 +60,62 @@
//
// RETURN result;
// END $$;
char *eval(cJSON *context, const char *key) {
if (!context || !key) return NULL;
char *key_copy = strdup(key);
char *token, *rest = key_copy;
cJSON *res = context;
void render_template_placeholders(char *text, char *context, char prefix[1]) {
while ((token = strtok_r(rest, ".", &rest))) {
res = cJSON_GetObjectItemCaseSensitive(res, token);
if (!res) {
free(key_copy);
return NULL;
}
}
free(key_copy);
if (cJSON_IsString(res) && res->valuestring)
return strdup(res->valuestring);
else if (cJSON_IsNumber(res)) {
char buf[64];
snprintf(buf, sizeof(buf), "%g", res->valuedouble);
return strdup(buf);
}
return cJSON_PrintUnformatted(res);
}
void substring(const char *src, char *dest, size_t start, size_t len) {
raise_debug("substring %s from %d to %d", 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';
}
char* replace_substring(const char* src, int start, int end, const char* replacement) {
raise_debug("replace_substring");
int src_len = strlen(src);
int rep_len = strlen(replacement);
int new_len = src_len - (end - start + 1) + rep_len;
char* new_str = malloc(new_len + 1);
if (!new_str) return NULL;
memcpy(new_str, src, start); // copy before
memcpy(new_str + start, replacement, rep_len); // insert replacement
strcpy(new_str + start + rep_len, src + end + 1); // copy after
return new_str;
}
void render_template_placeholders(char *text, cJSON *context, char prefix[1]) {
raise_debug("render_template_placeholders");
// start
char start_pattern[4];
sprintf(&start_pattern[0], "{{%s", prefix);
@@ -71,35 +126,68 @@ void render_template_placeholders(char *text, char *context, char prefix[1]) {
while (1) {
// find tag start
char *placeholder_start = strstr(text + offset, start_pattern);
if (!placeholder_start) {
break;
if (!placeholder_start) { break; }
char *releative_start = (size_t)placeholder_start - (size_t)text + start_pattern_length;
raise_debug("start: %d", releative_start);
if (offset != 0) {
placeholder_start += offset - 1;
}
char* placeholder_end = strstr(placeholder_start, "}}");
// TODO: user error instead exaption
if (!placeholder_end) { raise_exception("Malformed template: missing closing braces for placeholder start"); };
raise_debug("end: %d", (size_t)placeholder_end - (size_t)text);
int len = (size_t)placeholder_end - (size_t)placeholder_start - start_pattern_length;
char* placeholder_key = malloc(len + 1);;
substring(text, placeholder_key, releative_start, len);
raise_debug("key: %s", placeholder_key);
char* replacement = eval(context, placeholder_key);
raise_debug("%s = eval(%s, %s)", replacement, context, placeholder_key);
if (!replacement) {
offset = placeholder_start + start_pattern_length;
raise_log("offset is %s = %s + %s", offset, placeholder_start, start_pattern_length);
if (offset = 0) {
raise_exception("offset cannot be 0 here");
};
continue;
}
text = replace_substring(text, releative_start - start_pattern_length, releative_start + len + 2 - 1, replacement);
raise_info(text);
};
}
void render_template(char *text, char *context) {
void render_template(char *text, cJSON *context) {
render_template_placeholders(text, context, "");
}
int main(int argc, char *argv[]) {
char *text = NULL;
char *context = strdup(argc > 1 ? argv[1] : "{}");
init_logger();
raise_info("start");
if (argc > 2) {
text = strdup(argv[2]);
} else if (!isatty(fileno(stdin))) {
size_t size = 0;
ssize_t len = getdelim(&text, &size, '\0', stdin);
if (len < 0) {
perror("read stdin");
free(context);
return 1;
}
}
char *text = NULL;
cJSON *context = cJSON_Parse(strdup(argc > 1 ? argv[1] : "{}"));
if (argc > 2) {
text = strdup(argv[2]);
} else if (!isatty(fileno(stdin))) {
size_t size = 0;
ssize_t len = getdelim(&text, &size, '\0', stdin);
if (len < 0) {
perror("read stdin");
free(context);
return 1;
}
}
if (text) {
render_template(text, context);
}
free(text);
free(context);
return 0;
printf("%s", text);
free(text);
free(context);
return 0;
}