clean up of files and fixed docs
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
tt
|
||||||
|
tt.exe
|
||||||
@@ -50,4 +50,4 @@ cat page.tt | ./tt params.json > page.html
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Internals
|
## Internals
|
||||||
TinyTemplate works by compiling a template string into a bytecode program, and then evaluating the program to generate the output.
|
TinyTemplate works by compiling a template string into a bytecode program, and then evaluating the program to generate the output. (TODO)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Francesco",
|
||||||
|
"fruits": ["Orange", "Peach", "Mango"],
|
||||||
|
"chocolate": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>TinyTemplate example</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a>Hello, my name is {{name}} and my favourite fruits are:</a>
|
||||||
|
<ul>
|
||||||
|
{% for fruit in fruits %}
|
||||||
|
<li>{{fruit}}</li>
|
||||||
|
{% end %}
|
||||||
|
</ul>
|
||||||
|
{% if chocolate %}
|
||||||
|
<a>but I also like chocolate!</a>
|
||||||
|
{% else %}
|
||||||
|
<a>and I do NOT like chocolate!</a>
|
||||||
|
{% end %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
all: tt
|
all: tt
|
||||||
|
|
||||||
tt: cli.c tinytemplate.c xjson.c
|
tt: src/cli.c src/tinytemplate.c 3p/xjson.c
|
||||||
gcc $^ -o $@ -Wall -Wextra -g
|
gcc $^ -o $@ -Wall -Wextra -g -I3p
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm tt tt.exe
|
rm tt tt.exe
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>{{username}}s blog!</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>Hei, welcome to my blog! I'm {{name}} {{surname}} and I'm {{age}} years old!</p>
|
|
||||||
<ul>
|
|
||||||
{% for post in posts %}
|
|
||||||
<li>{{post.title}} - {{post.date}}</li>
|
|
||||||
{% end %}
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>coziss blog!</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>Hei, welcome to my blog! I'm Francesco Cozzuto and I'm 24 years old!</p>
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>Scriviamo un server TCP - 10/9/2023</li>
|
|
||||||
|
|
||||||
<li>Gli assert - 4/5/2022</li>
|
|
||||||
|
|
||||||
<li>Big e little endian: Ordinamento dei byte - 14/5/2022</li>
|
|
||||||
|
|
||||||
<li>Complessità computazionale - ???</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"username": "cozis",
|
|
||||||
"name": "Francesco",
|
|
||||||
"surname": "Cozzuto",
|
|
||||||
"age": 24,
|
|
||||||
"posts": [
|
|
||||||
{"title": "Scriviamo un server TCP", "date": "10/9/2023"},
|
|
||||||
{"title": "Gli assert", "date": "4/5/2022"},
|
|
||||||
{"title": "Big e little endian: Ordinamento dei byte", "date": "14/5/2022"},
|
|
||||||
{"title": "Complessità computazionale", "date": "???"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+39
-32
@@ -6,28 +6,30 @@
|
|||||||
#include "tinytemplate.h"
|
#include "tinytemplate.h"
|
||||||
|
|
||||||
typedef struct wrap_t wrap_t;
|
typedef struct wrap_t wrap_t;
|
||||||
|
typedef struct eval_context_t eval_context_t;
|
||||||
|
|
||||||
struct wrap_t {
|
struct wrap_t {
|
||||||
eval_context_t *context;
|
eval_context_t *context;
|
||||||
union {
|
union {
|
||||||
xj_value *value;
|
xj_value *value;
|
||||||
wrap_t *next;
|
wrap_t *next;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
struct eval_context_t {
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
xj_value *params;
|
wrap_t params;
|
||||||
wrap_t *free;
|
wrap_t *free;
|
||||||
wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH];
|
wrap_t pool[TINYTEMPLATE_MAX_ITER_DEPTH];
|
||||||
} eval_context_t;
|
};
|
||||||
|
|
||||||
static bool query_json_array(void *data,
|
static bool query_json_array(void *data,
|
||||||
tinytemplate_type_t *type,
|
tinytemplate_type_t *type,
|
||||||
tinytemplate_value_t *value);
|
tinytemplate_value_t *value);
|
||||||
|
|
||||||
static bool query_json_object(void *data, const char *key, size_t len,
|
static bool query_json_object(void *data, const char *key, size_t len,
|
||||||
tinytemplate_type_t *type,
|
tinytemplate_type_t *type,
|
||||||
tinytemplate_value_t *value);
|
tinytemplate_value_t *value);
|
||||||
|
|
||||||
static void convert_json_object(eval_context_t *context,
|
static void convert_json_object(eval_context_t *context,
|
||||||
xj_value *child,
|
xj_value *child,
|
||||||
@@ -58,13 +60,14 @@ static void convert_json_object(eval_context_t *context,
|
|||||||
|
|
||||||
case XJ_ARRAY:
|
case XJ_ARRAY:
|
||||||
{
|
{
|
||||||
iter_t *iter = context->free;
|
wrap_t *wrap = context->free;
|
||||||
*type = TINYTEMPLATE_TYPE_ARRAY;
|
*type = TINYTEMPLATE_TYPE_ARRAY;
|
||||||
value->as_array.data = iter;
|
value->as_array.data = wrap;
|
||||||
value->as_array.next = query_json_array;
|
value->as_array.next = query_json_array;
|
||||||
if (iter) {
|
if (wrap) {
|
||||||
context->free = iter->next;
|
context->free = wrap->next;
|
||||||
iter->curs = child->as_array;
|
wrap->value = child->as_array;
|
||||||
|
wrap->context = context;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -87,14 +90,12 @@ static bool query_json_array(void *data,
|
|||||||
tinytemplate_type_t *type,
|
tinytemplate_type_t *type,
|
||||||
tinytemplate_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
iter_t *iter = data;
|
wrap_t *wrap = data;
|
||||||
|
|
||||||
if (iter->curs) {
|
if (wrap->value) {
|
||||||
iter->curs = iter->curs->next;
|
convert_json_object(wrap->context, wrap->value, type, value);
|
||||||
if (iter->curs) {
|
wrap->value = wrap->value->next;
|
||||||
convert_json_object(iter->curs, type, value);
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -103,10 +104,11 @@ static bool query_json_object(void *data, const char *key, size_t len,
|
|||||||
tinytemplate_type_t *type,
|
tinytemplate_type_t *type,
|
||||||
tinytemplate_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
xj_value *json_value = data;
|
wrap_t *wrap = data;
|
||||||
assert(json_value->type == XJ_OBJECT);
|
|
||||||
|
|
||||||
xj_value *child = json_value->as_object;
|
assert(wrap->value->type == XJ_OBJECT);
|
||||||
|
|
||||||
|
xj_value *child = wrap->value->as_object;
|
||||||
while (child) {
|
while (child) {
|
||||||
size_t keylen = strlen(child->key);
|
size_t keylen = strlen(child->key);
|
||||||
if (keylen == len && !strncmp(key, child->key, len))
|
if (keylen == len && !strncmp(key, child->key, len))
|
||||||
@@ -116,12 +118,16 @@ static bool query_json_object(void *data, const char *key, size_t len,
|
|||||||
if (!child)
|
if (!child)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
convert_json_object(child, type, value);
|
convert_json_object(wrap->context, child, type, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void callback(void *userp, const char *str, size_t len)
|
static void callback(void *userp, const char *lbl, size_t lbllen,
|
||||||
|
const char *str, size_t len)
|
||||||
{
|
{
|
||||||
|
(void) lbl;
|
||||||
|
(void) lbllen;
|
||||||
|
|
||||||
eval_context_t *context = userp;
|
eval_context_t *context = userp;
|
||||||
fwrite(str, 1, len, context->stream);
|
fwrite(str, 1, len, context->stream);
|
||||||
}
|
}
|
||||||
@@ -131,8 +137,8 @@ static bool query_root_json_object(void *data, const char *key, size_t len,
|
|||||||
tinytemplate_value_t *value)
|
tinytemplate_value_t *value)
|
||||||
{
|
{
|
||||||
eval_context_t *context = data;
|
eval_context_t *context = data;
|
||||||
if (context->params)
|
if (context->params.value)
|
||||||
return query_json_object(context->params, key, len, type, value);
|
return query_json_object(&context->params, key, len, type, value);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -140,9 +146,10 @@ static bool query_root_json_object(void *data, const char *key, size_t len,
|
|||||||
static void init_context(eval_context_t *context,
|
static void init_context(eval_context_t *context,
|
||||||
FILE *stream, xj_value *root)
|
FILE *stream, xj_value *root)
|
||||||
{
|
{
|
||||||
context->stream=stdout;
|
context->stream = stream;
|
||||||
context->params=root;
|
context->params.context = context;
|
||||||
context->free = context->pool;
|
context->params.value = root;
|
||||||
|
context->free = context->pool;
|
||||||
|
|
||||||
for (int i = 0; i < TINYTEMPLATE_MAX_ITER_DEPTH-1; i++)
|
for (int i = 0; i < TINYTEMPLATE_MAX_ITER_DEPTH-1; i++)
|
||||||
context->pool[i].next = &context->pool[i+1];
|
context->pool[i].next = &context->pool[i+1];
|
||||||
@@ -217,7 +224,7 @@ int main(int argc, char **argv)
|
|||||||
} while (status == TINYTEMPLATE_STATUS_EMEMORY);
|
} while (status == TINYTEMPLATE_STATUS_EMEMORY);
|
||||||
|
|
||||||
eval_context_t context;
|
eval_context_t context;
|
||||||
init_context(&context);
|
init_context(&context, stdout, root);
|
||||||
|
|
||||||
if (tinytemplate_eval(buffer, program, &context, query_root_json_object, callback, message, sizeof(message)) != TINYTEMPLATE_STATUS_DONE) {
|
if (tinytemplate_eval(buffer, program, &context, query_root_json_object, callback, message, sizeof(message)) != TINYTEMPLATE_STATUS_DONE) {
|
||||||
fprintf(stderr, "Failed to evaluate template (%s)\n", message);
|
fprintf(stderr, "Failed to evaluate template (%s)\n", message);
|
||||||
@@ -73,6 +73,7 @@ typedef enum {
|
|||||||
OPCODE_NEXT,
|
OPCODE_NEXT,
|
||||||
OPCODE_CHLD,
|
OPCODE_CHLD,
|
||||||
OPCODE_IDX,
|
OPCODE_IDX,
|
||||||
|
OPCODE_BLOCK,
|
||||||
} opcode_t;
|
} opcode_t;
|
||||||
|
|
||||||
// Represents a substring of the template
|
// Represents a substring of the template
|
||||||
@@ -85,15 +86,20 @@ typedef enum {
|
|||||||
SCOPE_IF,
|
SCOPE_IF,
|
||||||
SCOPE_IF_ELSE,
|
SCOPE_IF_ELSE,
|
||||||
SCOPE_FOR,
|
SCOPE_FOR,
|
||||||
|
SCOPE_BLOCK,
|
||||||
} scope_type_t;
|
} scope_type_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
scope_type_t type;
|
scope_type_t type;
|
||||||
|
|
||||||
size_t if_jcnd;
|
size_t if_jcnd;
|
||||||
size_t if_jump;
|
size_t if_jump;
|
||||||
size_t for_next;
|
|
||||||
|
size_t for_next;
|
||||||
slice_t for_child_label;
|
slice_t for_child_label;
|
||||||
slice_t for_index_label;
|
slice_t for_index_label;
|
||||||
|
|
||||||
|
slice_t block_name;
|
||||||
} scope_t;
|
} scope_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -134,6 +140,7 @@ typedef enum {
|
|||||||
TOKEN_KWORD_FOR,
|
TOKEN_KWORD_FOR,
|
||||||
TOKEN_KWORD_ELSE,
|
TOKEN_KWORD_ELSE,
|
||||||
TOKEN_KWORD_END,
|
TOKEN_KWORD_END,
|
||||||
|
TOKEN_KWORD_BLOCK,
|
||||||
TOKEN_OPER_MOD,
|
TOKEN_OPER_MOD,
|
||||||
} token_t;
|
} token_t;
|
||||||
|
|
||||||
@@ -191,6 +198,7 @@ append_instr(compile_state_t *state,
|
|||||||
case OPCODE_GETS:
|
case OPCODE_GETS:
|
||||||
case OPCODE_PUSHV:
|
case OPCODE_PUSHV:
|
||||||
case OPCODE_PUSHS:
|
case OPCODE_PUSHS:
|
||||||
|
case OPCODE_BLOCK:
|
||||||
instr->operands[0].as_size = va_arg(operands, size_t);
|
instr->operands[0].as_size = va_arg(operands, size_t);
|
||||||
instr->operands[1].as_size = va_arg(operands, size_t);
|
instr->operands[1].as_size = va_arg(operands, size_t);
|
||||||
break;
|
break;
|
||||||
@@ -372,6 +380,11 @@ next_token_kword_or_ident(scanner_t *scanner, slice_t *slice,
|
|||||||
if (!strncmp(scanner->src + offset, "else", length))
|
if (!strncmp(scanner->src + offset, "else", length))
|
||||||
return TOKEN_KWORD_ELSE;
|
return TOKEN_KWORD_ELSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 5: // block
|
||||||
|
if (!strncmp(scanner->src + offset, "block", length))
|
||||||
|
return TOKEN_KWORD_BLOCK;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TOKEN_IDENT;
|
return TOKEN_IDENT;
|
||||||
@@ -756,7 +769,6 @@ selection_construct_start(scanner_t *scanner,
|
|||||||
return DONE;
|
return DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
iteration_construct_start(scanner_t *scanner,
|
iteration_construct_start(scanner_t *scanner,
|
||||||
compile_state_t *state,
|
compile_state_t *state,
|
||||||
@@ -812,13 +824,48 @@ iteration_construct_start(scanner_t *scanner,
|
|||||||
return DONE;
|
return DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
block_construct_start(scanner_t *scanner,
|
||||||
|
compile_state_t *state,
|
||||||
|
error_t *error)
|
||||||
|
{
|
||||||
|
// This function is called after "{% block" is parsed
|
||||||
|
assert(scanner->src[scanner->cur-5] == 'b'
|
||||||
|
&& scanner->src[scanner->cur-4] == 'l'
|
||||||
|
&& scanner->src[scanner->cur-3] == 'o'
|
||||||
|
&& scanner->src[scanner->cur-2] == 'c'
|
||||||
|
&& scanner->src[scanner->cur-1] == 'k');
|
||||||
|
|
||||||
|
if (state->scope_depth == TINYTEMPLATE_MAX_SCOPE_DEPTH) {
|
||||||
|
report(error, "Scope depth limit reached");
|
||||||
|
return ESCOPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
slice_t label;
|
||||||
|
if (next_token(scanner, &label, NULL) != TOKEN_IDENT) {
|
||||||
|
report(error, "Missing block label");
|
||||||
|
return ESYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_instr(state, OPCODE_BLOCK, label.offset, label.length);
|
||||||
|
|
||||||
|
tinytemplate_status_t status;
|
||||||
|
if ((status = close_construct(scanner, error, "block")) != DONE)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
state->scope_stack[state->scope_depth].type = SCOPE_BLOCK;
|
||||||
|
state->scope_stack[state->scope_depth].block_name = label;
|
||||||
|
state->scope_depth++;
|
||||||
|
return DONE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
resolve_scope(compile_state_t *state)
|
resolve_scope(compile_state_t *state)
|
||||||
{
|
{
|
||||||
assert(state->scope_depth > 0);
|
assert(state->scope_depth > 0);
|
||||||
|
|
||||||
scope_t *scope = state->scope_stack
|
scope_t *scope = state->scope_stack
|
||||||
+ state->scope_depth - 1;
|
+ state->scope_depth-1;
|
||||||
|
|
||||||
switch (scope->type) {
|
switch (scope->type) {
|
||||||
|
|
||||||
@@ -841,6 +888,17 @@ resolve_scope(compile_state_t *state)
|
|||||||
instr = state->program + scope->if_jump;
|
instr = state->program + scope->if_jump;
|
||||||
instr->operands[0].as_size = state->num_instr;
|
instr->operands[0].as_size = state->num_instr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SCOPE_BLOCK:
|
||||||
|
{
|
||||||
|
// Get parent block name
|
||||||
|
slice_t parent_label = {0, 0};
|
||||||
|
for (int i = state->scope_depth-2; i >= 0; i--)
|
||||||
|
if (state->scope_stack[i].type == SCOPE_BLOCK)
|
||||||
|
parent_label = state->scope_stack[i].block_name;
|
||||||
|
append_instr(state, OPCODE_BLOCK, parent_label.offset, parent_label.length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->scope_depth--;
|
state->scope_depth--;
|
||||||
@@ -900,6 +958,10 @@ construct_else(scanner_t *scanner,
|
|||||||
case SCOPE_FOR:
|
case SCOPE_FOR:
|
||||||
report(error, "Bad {%% else %%} coupled with {%% for .. %%}");
|
report(error, "Bad {%% else %%} coupled with {%% for .. %%}");
|
||||||
return ESEMANT;
|
return ESEMANT;
|
||||||
|
|
||||||
|
case SCOPE_BLOCK:
|
||||||
|
report(error, "Bad {%% else %%} coupled with {%% block .. %%}");
|
||||||
|
return ESEMANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DONE;
|
return DONE;
|
||||||
@@ -918,7 +980,7 @@ control_flow_block(scanner_t *scanner,
|
|||||||
case TOKEN_KWORD_FOR: return iteration_construct_start(scanner, state, error);
|
case TOKEN_KWORD_FOR: return iteration_construct_start(scanner, state, error);
|
||||||
case TOKEN_KWORD_END: return construct_end(scanner, state, error);
|
case TOKEN_KWORD_END: return construct_end(scanner, state, error);
|
||||||
case TOKEN_KWORD_ELSE: return construct_else(scanner, state, error);
|
case TOKEN_KWORD_ELSE: return construct_else(scanner, state, error);
|
||||||
|
case TOKEN_KWORD_BLOCK: return block_construct_start(scanner, state, error);
|
||||||
default:
|
default:
|
||||||
report(error, "Bad token [%.*s] after [{%%]",
|
report(error, "Bad token [%.*s] after [{%%]",
|
||||||
(int) slice.length, scanner->src + slice.offset);
|
(int) slice.length, scanner->src + slice.offset);
|
||||||
@@ -1050,13 +1112,28 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
tinytemplate_value_t stack[TINYTEMPLATE_MAX_EXPR_DEPTH];
|
tinytemplate_value_t stack[TINYTEMPLATE_MAX_EXPR_DEPTH];
|
||||||
size_t stack_depth = 0;
|
size_t stack_depth = 0;
|
||||||
|
|
||||||
|
slice_t label = {0, 0};
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
const tinytemplate_instr_t *instr = &program[index++];
|
const tinytemplate_instr_t *instr = &program[index++];
|
||||||
switch (instr->opcode) {
|
switch (instr->opcode) {
|
||||||
case OPCODE_NOPE: /* Do nothing */ break;
|
|
||||||
case OPCODE_DONE: done = true; break;
|
case OPCODE_NOPE:
|
||||||
|
/* Do nothing */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_DONE:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_BLOCK:
|
||||||
|
label = (slice_t) {
|
||||||
|
.offset = instr->operands[0].as_size,
|
||||||
|
.length = instr->operands[1].as_size,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
case OPCODE_ITER:
|
case OPCODE_ITER:
|
||||||
assert(stack_depth > 0); // ITER excepts a value on the stack
|
assert(stack_depth > 0); // ITER excepts a value on the stack
|
||||||
@@ -1233,7 +1310,8 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
{
|
{
|
||||||
size_t offset = instr->operands[0].as_size;
|
size_t offset = instr->operands[0].as_size;
|
||||||
size_t length = instr->operands[1].as_size;
|
size_t length = instr->operands[1].as_size;
|
||||||
callback(userp, src + offset, length);
|
callback(userp, src + label.offset, label.length,
|
||||||
|
src + offset, length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1248,7 +1326,8 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
char text[128];
|
char text[128];
|
||||||
int num = snprintf(text, sizeof(text), "%lld", stack[stack_depth-1].as_int);
|
int num = snprintf(text, sizeof(text), "%lld", stack[stack_depth-1].as_int);
|
||||||
assert(num > 0);
|
assert(num > 0);
|
||||||
callback(userp, text, (size_t) num);
|
callback(userp, src + label.offset, label.length,
|
||||||
|
text, (size_t) num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1257,13 +1336,15 @@ tinytemplate_eval(const char *src, const instr_t *program, void *userp,
|
|||||||
char text[128];
|
char text[128];
|
||||||
int num = snprintf(text, sizeof(text), "%lf", stack[stack_depth-1].as_float);
|
int num = snprintf(text, sizeof(text), "%lf", stack[stack_depth-1].as_float);
|
||||||
assert(num > 0);
|
assert(num > 0);
|
||||||
callback(userp, text, (size_t) num);
|
callback(userp, src + label.offset, label.length,
|
||||||
|
text, (size_t) num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TINYTEMPLATE_TYPE_STRING:
|
case TINYTEMPLATE_TYPE_STRING:
|
||||||
callback(userp, stack[stack_depth-1].as_string.str,
|
callback(userp, src + label.offset, label.length,
|
||||||
stack[stack_depth-1].as_string.len);
|
stack[stack_depth-1].as_string.str,
|
||||||
|
stack[stack_depth-1].as_string.len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -29,7 +29,7 @@ typedef union tinytemplate_value_t tinytemplate_value_t;
|
|||||||
|
|
||||||
typedef bool (*tinytemplate_nextcallback_t)(void*, tinytemplate_type_t*, tinytemplate_value_t*);
|
typedef bool (*tinytemplate_nextcallback_t)(void*, tinytemplate_type_t*, tinytemplate_value_t*);
|
||||||
typedef bool (*tinytemplate_getter_t)(void*, const char*, size_t, tinytemplate_type_t*, tinytemplate_value_t*);
|
typedef bool (*tinytemplate_getter_t)(void*, const char*, size_t, tinytemplate_type_t*, tinytemplate_value_t*);
|
||||||
typedef void (*tinytemplate_callback_t)(void *userp, const char *str, size_t len);
|
typedef void (*tinytemplate_callback_t)(void *userp, const char *lbl, size_t lblen, const char *str, size_t len);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *data;
|
void *data;
|
||||||
Reference in New Issue
Block a user