feat(hmpl): render simple placeholder with memory leak of course
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "libhectic.h"
|
||||
#include "chectic.h"
|
||||
|
||||
void set_output_color_mode(ColorMode mode) {
|
||||
color_mode = mode;
|
||||
@@ -1,7 +1,7 @@
|
||||
{ stdenv, gcc, lib }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "libhectic";
|
||||
pname = "chectic";
|
||||
version = "1.0";
|
||||
src = ./.;
|
||||
doCheck = true;
|
||||
@@ -11,23 +11,23 @@ stdenv.mkDerivation {
|
||||
${gcc}/bin/cc -Wall -Wextra -g \
|
||||
-std=c99 \
|
||||
-pedantic -fsanitize=address \
|
||||
-c libhectic.c -o target/libhectic.o
|
||||
${gcc}/bin/ar rcs target/libhectic.a target/libhectic.o
|
||||
-c chectic.c -o target/chectic.o
|
||||
${gcc}/bin/ar rcs target/libchectic.a target/chectic.o
|
||||
'';
|
||||
|
||||
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 -l:libhectic.a -o "$exe"
|
||||
${gcc}/bin/cc -Wall -Wextra -g -pedantic -fsanitize=address -I. "$test_file" -Ltarget -lchectic -o "$exe"
|
||||
"$exe"
|
||||
done
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib $out/include
|
||||
cp target/libhectic.a $out/lib/
|
||||
cp libhectic.h $out/include/
|
||||
cp target/libchectic.a $out/lib/
|
||||
cp chectic.h $out/include/
|
||||
'';
|
||||
|
||||
meta = {
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "libhectic.h"
|
||||
#include "chectic.h"
|
||||
|
||||
void test_arena_init() {
|
||||
Arena arena = arena_init(128);
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "libhectic.h"
|
||||
#include "chectic.h"
|
||||
|
||||
#define TEST_RAISE_GENERIC(LOG_MACRO, LEVEL, LEVEL_STR) do { \
|
||||
FILE *orig_stderr = stderr; \
|
||||
@@ -1,4 +1,4 @@
|
||||
{ stdenv, gcc, lib, libhectic, cjson }:
|
||||
{ stdenv, gcc, lib, chectic, cjson }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "hmpl";
|
||||
@@ -6,13 +6,13 @@ stdenv.mkDerivation {
|
||||
src = ./.;
|
||||
doCheck = true;
|
||||
|
||||
buildInputs = [ libhectic cjson ];
|
||||
buildInputs = [ chectic cjson ];
|
||||
|
||||
buildPhase = ''
|
||||
mkdir -p target
|
||||
${gcc}/bin/cc -Wall -Wextra -g \
|
||||
-pedantic -fsanitize=address hmpl.c \
|
||||
-l:libhectic.a -l:cjson -o target/hmpl
|
||||
-lchectic -lcjson -o target/hmpl
|
||||
'';
|
||||
|
||||
checkPhase = '' '';
|
||||
@@ -23,7 +23,7 @@ stdenv.mkDerivation {
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "libhectic";
|
||||
description = "chectic";
|
||||
license = lib.licenses.mit;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user