Add HTML escaping to post.wl
This commit is contained in:
@@ -34,6 +34,7 @@ typedef struct {
|
||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define SIZEOF(X) (int) sizeof(X)
|
||||
#define ALIGNOF(X) (int) _Alignof(X)
|
||||
#define COUNT(X) (int) (sizeof(X)/sizeof((X)[0]))
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UNREACHABLE __builtin_trap()
|
||||
@@ -68,14 +69,12 @@ static bool is_hex_digit(char c)
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char to_lower(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return c - 'A' + 'a';
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int hex_digit_to_int(char c)
|
||||
{
|
||||
@@ -98,7 +97,6 @@ static bool streq(String a, String b)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool streqcase(String a, String b)
|
||||
{
|
||||
if (a.len != b.len)
|
||||
@@ -108,7 +106,7 @@ static bool streqcase(String a, String b)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define REPORT(err, fmt, ...) report((err), __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
||||
static void report(Error *err, char *file, int line, char *fmt, ...)
|
||||
@@ -161,7 +159,6 @@ static bool grow_alloc(WL_Arena *a, char *p, int new_len)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static String copystr(String s, WL_Arena *a)
|
||||
{
|
||||
char *p = alloc(a, s.len, 1);
|
||||
@@ -170,7 +167,6 @@ static String copystr(String s, WL_Arena *a)
|
||||
memcpy(p, s.ptr, s.len);
|
||||
return (String) { p, s.len };
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// WRITER
|
||||
@@ -193,14 +189,14 @@ static void write_raw_mem(Writer *w, void *ptr, int len)
|
||||
}
|
||||
|
||||
static void write_raw_u8 (Writer *w, uint8_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_u16(Writer *w, uint16_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_u16(Writer *w, uint16_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_u32(Writer *w, uint32_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_u64(Writer *w, uint64_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_s8 (Writer *w, int8_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_s16(Writer *w, int16_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_s32(Writer *w, int32_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_u64(Writer *w, uint64_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_s8 (Writer *w, int8_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_s16(Writer *w, int16_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_s32(Writer *w, int32_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_s64(Writer *w, int64_t x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
//static void write_raw_f32(Writer *w, float x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_f32(Writer *w, float x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
static void write_raw_f64(Writer *w, double x) { write_raw_mem(w, &x, SIZEOF(x)); }
|
||||
|
||||
static void write_text(Writer *w, String str)
|
||||
@@ -265,6 +261,7 @@ typedef enum {
|
||||
TOKEN_KWORD_FALSE,
|
||||
TOKEN_KWORD_INCLUDE,
|
||||
TOKEN_KWORD_LEN,
|
||||
TOKEN_KWORD_ESCAPE,
|
||||
TOKEN_VALUE_FLOAT,
|
||||
TOKEN_VALUE_INT,
|
||||
TOKEN_VALUE_STR,
|
||||
@@ -312,6 +309,7 @@ typedef enum {
|
||||
NODE_INCLUDE,
|
||||
NODE_SELECT,
|
||||
NODE_NESTED,
|
||||
NODE_OPER_ESCAPE,
|
||||
NODE_OPER_LEN,
|
||||
NODE_OPER_POS,
|
||||
NODE_OPER_NEG,
|
||||
@@ -415,7 +413,6 @@ static bool consume_str(Scanner *s, String x)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void write_token(Writer *w, Token token)
|
||||
{
|
||||
switch (token.type) {
|
||||
@@ -436,6 +433,7 @@ static void write_token(Writer *w, Token token)
|
||||
case TOKEN_KWORD_FALSE : write_text(w, S("false")); break;
|
||||
case TOKEN_KWORD_INCLUDE: write_text(w, S("include")); break;
|
||||
case TOKEN_KWORD_LEN : write_text(w, S("len")); break;
|
||||
case TOKEN_KWORD_ESCAPE: write_text(w, S("escape")); break;
|
||||
case TOKEN_VALUE_FLOAT : write_text_f64(w, token.fval); break;
|
||||
case TOKEN_VALUE_INT : write_text_s64(w, token.ival); break;
|
||||
case TOKEN_OPER_ASS : write_text(w, S("=")); break;
|
||||
@@ -469,7 +467,6 @@ static void write_token(Writer *w, Token token)
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parser_report(Parser *p, char *fmt, ...)
|
||||
{
|
||||
@@ -552,6 +549,7 @@ static Token next_token(Parser *p)
|
||||
if (streq(kword, S("false"))) return (Token) { .type=TOKEN_KWORD_FALSE };
|
||||
if (streq(kword, S("include"))) return (Token) { .type=TOKEN_KWORD_INCLUDE };
|
||||
if (streq(kword, S("len"))) return (Token) { .type=TOKEN_KWORD_LEN };
|
||||
if (streq(kword, S("escape"))) return (Token) { .type=TOKEN_KWORD_ESCAPE };
|
||||
|
||||
return (Token) { .type=TOKEN_IDENT, .sval=kword };
|
||||
}
|
||||
@@ -778,8 +776,7 @@ static Node *parse_html(Parser *p)
|
||||
}
|
||||
|
||||
if (s->cur == s->len) {
|
||||
parser_report(p, "Invaid end of source inside HTML tag");
|
||||
return NULL;
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
s->cur++;
|
||||
|
||||
@@ -790,8 +787,7 @@ static Node *parse_html(Parser *p)
|
||||
while (s->cur < s->len && is_space(s->src[s->cur]))
|
||||
s->cur++;
|
||||
if (s->cur == s->len || s->src[s->cur] != '>') {
|
||||
parser_report(p, "Invalid character inside HTML closing tag");
|
||||
return NULL;
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
s->cur++;
|
||||
no_body = true;
|
||||
@@ -835,8 +831,7 @@ static Node *parse_html(Parser *p)
|
||||
}
|
||||
|
||||
if (s->cur == s->len) {
|
||||
parser_report(p, "Missing closing HTML tag </%.*s>", tagname.len, tagname.ptr);
|
||||
return NULL;
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
s->cur++;
|
||||
|
||||
@@ -848,20 +843,17 @@ static Node *parse_html(Parser *p)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
parser_report(p, "Missing tag name after '</'");
|
||||
return NULL;
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
String closing_tagname = t.sval;
|
||||
|
||||
if (!streq(closing_tagname, tagname)) {
|
||||
parser_report(p, "HTML tag mismatch (%.*s != %.*s)", tagname.len, tagname.ptr, closing_tagname.len, closing_tagname.ptr);
|
||||
return NULL;
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_OPER_GRT) {
|
||||
parser_report(p, "Missing '>' in closing HTML tag");
|
||||
return NULL;
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1134,6 +1126,23 @@ static Node *parse_atom(Parser *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case TOKEN_KWORD_ESCAPE:
|
||||
{
|
||||
Node *child = parse_atom(p);
|
||||
if (child == NULL)
|
||||
return NULL;
|
||||
|
||||
Node *parent = alloc_node(p);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_OPER_ESCAPE;
|
||||
parent->left = child;
|
||||
|
||||
ret = parent;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOKEN_IDENT:
|
||||
{
|
||||
Node *node = alloc_node(p);
|
||||
@@ -1910,6 +1919,12 @@ static void write_node(Writer *w, Node *node)
|
||||
write_text(w, S(")"));
|
||||
break;
|
||||
|
||||
case NODE_OPER_ESCAPE:
|
||||
write_text(w, S("(escape "));
|
||||
write_node(w, node->left);
|
||||
write_text(w, S(")"));
|
||||
break;
|
||||
|
||||
case NODE_OPER_POS:
|
||||
write_text(w, S("(+"));
|
||||
write_node(w, node->left);
|
||||
@@ -2003,14 +2018,6 @@ static void write_node(Writer *w, Node *node)
|
||||
write_text(w, S(")"));
|
||||
break;
|
||||
|
||||
case NODE_OPER_SHOVEL:
|
||||
write_text(w, S("("));
|
||||
write_node(w, node->left);
|
||||
write_text(w, S("<<"));
|
||||
write_node(w, node->right);
|
||||
write_text(w, S(")"));
|
||||
break;
|
||||
|
||||
case NODE_VALUE_INT:
|
||||
write_text_s64(w, node->ival);
|
||||
break;
|
||||
@@ -2206,6 +2213,7 @@ enum {
|
||||
OPCODE_CALL,
|
||||
OPCODE_RET,
|
||||
OPCODE_GROUP,
|
||||
OPCODE_ESCAPE,
|
||||
OPCODE_PACK,
|
||||
OPCODE_GPOP,
|
||||
OPCODE_FOR,
|
||||
@@ -2516,8 +2524,6 @@ static void cg_pop_scope(Codegen *cg)
|
||||
ASSERT(cg->num_scopes > 0);
|
||||
Scope *scope = &cg->scopes[cg->num_scopes-1];
|
||||
|
||||
ASSERT(scope->type == SCOPE_PROC || scope->type == SCOPE_GLOBAL || scope->max_vars == 0);
|
||||
|
||||
Scope *parent_scope = NULL;
|
||||
if (cg->num_scopes > 1)
|
||||
parent_scope = &cg->scopes[cg->num_scopes-2];
|
||||
@@ -2552,6 +2558,9 @@ static void cg_pop_scope(Codegen *cg)
|
||||
|
||||
call->next = cg->free_list_calls;
|
||||
cg->free_list_calls = call;
|
||||
|
||||
// TODO: remove
|
||||
ASSERT(cg->scopes[cg->num_scopes-1].calls == NULL || (cg->scopes[cg->num_scopes-1].calls - cg->calls >= 0 && cg->scopes[cg->num_scopes-1].calls - cg->calls < MAX_UNPATCHED_CALLS));
|
||||
}
|
||||
|
||||
cg->num_syms = scope->idx_syms;
|
||||
@@ -2620,10 +2629,13 @@ static void cg_write_pushs(Codegen *cg, String str, bool dont_group)
|
||||
}
|
||||
}
|
||||
|
||||
static void walk_node(Codegen *cg, Node *node);
|
||||
static void walk_node(Codegen *cg, Node *node, bool inside_html);
|
||||
|
||||
static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
{
|
||||
// TODO: remove
|
||||
ASSERT(cg->scopes[cg->num_scopes-1].calls == NULL || (cg->scopes[cg->num_scopes-1].calls - cg->calls >= 0 && cg->scopes[cg->num_scopes-1].calls - cg->calls < MAX_UNPATCHED_CALLS));
|
||||
|
||||
switch (node->type) {
|
||||
|
||||
case NODE_NESTED:
|
||||
@@ -2635,6 +2647,12 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
cg_write_opcode(cg, OPCODE_LEN);
|
||||
break;
|
||||
|
||||
case NODE_OPER_ESCAPE:
|
||||
cg_write_opcode(cg, OPCODE_GROUP);
|
||||
walk_expr_node(cg, node->left, false);
|
||||
cg_write_opcode(cg, OPCODE_ESCAPE);
|
||||
break;
|
||||
|
||||
case NODE_OPER_POS:
|
||||
walk_expr_node(cg, node->left, one);
|
||||
break;
|
||||
@@ -2699,6 +2717,9 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
|
||||
case NODE_OPER_SHOVEL:
|
||||
{
|
||||
Node *dst = node->left;
|
||||
Node *src = node->right;
|
||||
|
||||
walk_expr_node(cg, node->left, true);
|
||||
|
||||
cg_push_scope(cg, SCOPE_ASSIGNMENT);
|
||||
@@ -2824,7 +2845,7 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
|
||||
Node *child = node->html_attr;
|
||||
while (child) {
|
||||
walk_node(cg, child);
|
||||
walk_node(cg, child, true);
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
@@ -2834,7 +2855,7 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
cg_write_pushs(cg, S(">"), false);
|
||||
Node *child = node->html_child;
|
||||
while (child) {
|
||||
walk_node(cg, child);
|
||||
walk_node(cg, child, true);
|
||||
child = child->next;
|
||||
}
|
||||
cg_write_pushs(cg, S("</"), false);
|
||||
@@ -2925,14 +2946,17 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one)
|
||||
}
|
||||
}
|
||||
|
||||
static void walk_node(Codegen *cg, Node *node)
|
||||
static void walk_node(Codegen *cg, Node *node, bool inside_html)
|
||||
{
|
||||
// TODO: remove
|
||||
ASSERT(cg->scopes[cg->num_scopes-1].calls == NULL || (cg->scopes[cg->num_scopes-1].calls - cg->calls >= 0 && cg->scopes[cg->num_scopes-1].calls - cg->calls < MAX_UNPATCHED_CALLS));
|
||||
|
||||
switch (node->type) {
|
||||
|
||||
case NODE_GLOBAL:
|
||||
for (Node *child = node->left;
|
||||
child; child = child->next) {
|
||||
walk_node(cg, child);
|
||||
walk_node(cg, child, false);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2940,7 +2964,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
cg_push_scope(cg, SCOPE_COMPOUND);
|
||||
for (Node *child = node->left;
|
||||
child; child = child->next)
|
||||
walk_node(cg, child);
|
||||
walk_node(cg, child, inside_html);
|
||||
cg_pop_scope(cg);
|
||||
break;
|
||||
|
||||
@@ -2972,10 +2996,10 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
int off1 = cg_write_opcode(cg, OPCODE_VARS);
|
||||
int off2 = cg_write_u8(cg, 0);
|
||||
|
||||
walk_node(cg, node->proc_body);
|
||||
walk_node(cg, node->proc_body, false);
|
||||
cg_write_opcode(cg, OPCODE_RET);
|
||||
|
||||
cg_patch_u8 (cg, off2, cg->scopes[cg->num_scopes-1].max_vars);
|
||||
cg_patch_u8 (cg, off2, count_function_vars(cg));
|
||||
cg_patch_u32(cg, off0, cg_current_offset(cg));
|
||||
|
||||
cg_pop_scope(cg);
|
||||
@@ -3028,7 +3052,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
int p1 = cg_write_u32(cg, 0);
|
||||
|
||||
cg_push_scope(cg, SCOPE_IF);
|
||||
walk_node(cg, node->if_branch1);
|
||||
walk_node(cg, node->if_branch1, inside_html);
|
||||
cg_pop_scope(cg);
|
||||
|
||||
cg_write_opcode(cg, OPCODE_JUMP);
|
||||
@@ -3038,7 +3062,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
cg_patch_u32(cg, p1, cg_current_offset(cg));
|
||||
|
||||
cg_push_scope(cg, SCOPE_ELSE);
|
||||
walk_node(cg, node->if_branch2);
|
||||
walk_node(cg, node->if_branch2, inside_html);
|
||||
cg_pop_scope(cg);
|
||||
|
||||
cg_flush_pushs(cg);
|
||||
@@ -3052,7 +3076,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
int p1 = cg_write_u32(cg, 0);
|
||||
|
||||
cg_push_scope(cg, SCOPE_IF);
|
||||
walk_node(cg, node->if_branch1);
|
||||
walk_node(cg, node->if_branch1, inside_html);
|
||||
cg_pop_scope(cg);
|
||||
|
||||
cg_flush_pushs(cg);
|
||||
@@ -3086,7 +3110,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
cg_write_u8(cg, var_2);
|
||||
int p = cg_write_u32(cg, 0);
|
||||
|
||||
walk_node(cg, node->left);
|
||||
walk_node(cg, node->left, inside_html);
|
||||
|
||||
cg_write_opcode(cg, OPCODE_JUMP);
|
||||
cg_write_u32(cg, start);
|
||||
@@ -3115,7 +3139,7 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
int p = cg_write_u32(cg, 0);
|
||||
|
||||
cg_push_scope(cg, SCOPE_WHILE);
|
||||
walk_node(cg, node->left);
|
||||
walk_node(cg, node->left, inside_html);
|
||||
cg_pop_scope(cg);
|
||||
|
||||
cg_write_opcode(cg, OPCODE_JUMP);
|
||||
@@ -3126,12 +3150,12 @@ static void walk_node(Codegen *cg, Node *node)
|
||||
break;
|
||||
|
||||
case NODE_INCLUDE:
|
||||
walk_node(cg, node->include_root);
|
||||
walk_node(cg, node->include_root, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
walk_expr_node(cg, node, false);
|
||||
if (cg_global_scope(cg) && !inside_assignment(cg))
|
||||
if (cg_global_scope(cg) && !inside_assignment(cg) && !inside_html)
|
||||
cg_write_opcode(cg, OPCODE_OUTPUT);
|
||||
break;
|
||||
}
|
||||
@@ -3168,7 +3192,7 @@ static int codegen(Node *node, char *dst, int cap, char *errmsg, int errcap)
|
||||
cg_push_scope(&cg, SCOPE_GLOBAL);
|
||||
cg_write_opcode(&cg, OPCODE_VARS);
|
||||
int off = cg_write_u8(&cg, 0);
|
||||
walk_node(&cg, node);
|
||||
walk_node(&cg, node, false);
|
||||
cg_write_opcode(&cg, OPCODE_EXIT);
|
||||
cg_patch_u8(&cg, off, cg.scopes[0].max_vars);
|
||||
cg_pop_scope(&cg);
|
||||
@@ -3271,6 +3295,10 @@ static int write_instr(Writer *w, char *src, int len, String data)
|
||||
write_text(w, S("GROUP\n"));
|
||||
return 1;
|
||||
|
||||
case OPCODE_ESCAPE:
|
||||
write_text(w, S("ESCAPE\n"));
|
||||
return 1;
|
||||
|
||||
case OPCODE_PACK:
|
||||
write_text(w, S("PACK\n"));
|
||||
return 1;
|
||||
@@ -3452,7 +3480,7 @@ static int write_instr(Writer *w, char *src, int len, String data)
|
||||
|
||||
static int write_program(WL_Program program, char *dst, int cap)
|
||||
{
|
||||
if ((uint32_t) program.len < 3 * sizeof(uint32_t))
|
||||
if (program.len < 3 * sizeof(uint32_t))
|
||||
return -1;
|
||||
|
||||
uint32_t magic;
|
||||
@@ -3466,7 +3494,7 @@ static int write_program(WL_Program program, char *dst, int cap)
|
||||
if (magic != WL_MAGIC)
|
||||
return -1;
|
||||
|
||||
if (code_len + data_len + 3 * sizeof(uint32_t) != (uint32_t) program.len)
|
||||
if (code_len + data_len + 3 * sizeof(uint32_t) != program.len)
|
||||
return -1;
|
||||
|
||||
String code = { program.ptr + 3 * sizeof(uint32_t) , code_len };
|
||||
@@ -3583,9 +3611,7 @@ WL_AddResult wl_compiler_add(WL_Compiler *compiler, WL_String content)
|
||||
if (include->include_root == NULL) {
|
||||
|
||||
if (compiler->num_files == FILE_LIMIT) {
|
||||
snprintf(compiler->err, sizeof(compiler->err), "File limit reached");
|
||||
compiler->err = true;
|
||||
return (WL_AddResult) { .type=WL_ADD_ERROR };
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
|
||||
// TODO: Make the path relative to the compiled file
|
||||
@@ -4449,29 +4475,7 @@ static void value_convert_to_str_inner(Writer *w, Value v)
|
||||
break;
|
||||
|
||||
case TYPE_MAP:
|
||||
{
|
||||
write_text(w, S("{"));
|
||||
AggregateValue *agg = (void*) (v & ~(Value) 7);
|
||||
for (int i = 0; i < agg->count; i += 2) {
|
||||
value_convert_to_str_inner(w, agg->vals[i+0]);
|
||||
write_text(w, S(": "));
|
||||
value_convert_to_str_inner(w, agg->vals[i+1]);
|
||||
if (i+2 < agg->count || agg->ext)
|
||||
write_text(w, S(", "));
|
||||
}
|
||||
Extension *ext = agg->ext;
|
||||
while (ext) {
|
||||
for (int i = 0; i < ext->count; i += 2) {
|
||||
value_convert_to_str_inner(w, ext->vals[i+0]);
|
||||
write_text(w, S(": "));
|
||||
value_convert_to_str_inner(w, ext->vals[i+1]);
|
||||
if (i+2 < ext->count || ext->next)
|
||||
write_text(w, S(", "));
|
||||
}
|
||||
ext = ext->next;
|
||||
}
|
||||
write_text(w, S("}"));
|
||||
}
|
||||
write_text(w, S("<map>"));
|
||||
break;
|
||||
|
||||
case TYPE_ERROR:
|
||||
@@ -4486,6 +4490,140 @@ static int value_convert_to_str(Value v, char *dst, int cap)
|
||||
return w.len;
|
||||
}
|
||||
|
||||
static Value value_escape_packed(Value v, WL_Arena *arena, Error *err);
|
||||
|
||||
static int array_escape(Value v, Value *out, int max, WL_Arena *arena, Error *err)
|
||||
{
|
||||
Value v2 = value_empty_array(value_length(v), arena, err);
|
||||
if (v2 == VALUE_ERROR) return -1;
|
||||
|
||||
AggregateValue *src = (void*) (v & ~(Value) 7);
|
||||
|
||||
for (int i = 0; i < src->count; i++) {
|
||||
|
||||
Value child = src->vals[i];
|
||||
|
||||
Value escaped_child = value_escape_packed(child, arena, err);
|
||||
if (escaped_child == VALUE_ERROR)
|
||||
return -1;
|
||||
|
||||
if (!value_append(v2, escaped_child, arena, err))
|
||||
return -1;
|
||||
}
|
||||
Extension *ext = src->ext;
|
||||
while (ext) {
|
||||
for (int i = 0; i < ext->count; i++) {
|
||||
|
||||
Value child = src->vals[i];
|
||||
|
||||
Value escaped_child = value_escape_packed(child, arena, err);
|
||||
if (escaped_child == VALUE_ERROR)
|
||||
return -1;
|
||||
|
||||
if (!value_append(v2, escaped_child, arena, err))
|
||||
return -1;
|
||||
}
|
||||
ext = ext->next;
|
||||
}
|
||||
|
||||
if (max == 0)
|
||||
return -1;
|
||||
out[0] = v2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int string_escape(Value v, Value *out, int max, WL_Arena *arena, Error *err)
|
||||
{
|
||||
String s = value_to_str(v);
|
||||
|
||||
int i = 0;
|
||||
int num = 0;
|
||||
for (;;) {
|
||||
|
||||
int off = i;
|
||||
while (i < s.len
|
||||
&& s.ptr[i] != '<'
|
||||
&& s.ptr[i] != '>'
|
||||
&& s.ptr[i] != '&'
|
||||
&& s.ptr[i] != '"'
|
||||
&& s.ptr[i] != '\'')
|
||||
i++;
|
||||
String substr = { s.ptr + off, i - off };
|
||||
|
||||
Value escaped_v = value_from_str(substr, arena, err); // TODO: don't copy the string
|
||||
if (escaped_v == VALUE_ERROR) return -1;
|
||||
|
||||
if (num == max) {
|
||||
REPORT(err, "Escape buffer limit reached");
|
||||
return -1;
|
||||
}
|
||||
out[num++] = escaped_v;
|
||||
|
||||
if (i == s.len) break;
|
||||
|
||||
switch (s.ptr[i++]) {
|
||||
case '<' : escaped_v = value_from_str(S("<"), arena, err); break; // TODO: don't come these strings
|
||||
case '>' : escaped_v = value_from_str(S(">"), arena, err); break;
|
||||
case '&' : escaped_v = value_from_str(S("&"), arena, err); break;
|
||||
case '"' : escaped_v = value_from_str(S("""), arena, err); break;
|
||||
case '\'': escaped_v = value_from_str(S("'"), arena, err); break;
|
||||
}
|
||||
if (escaped_v == VALUE_ERROR) return -1;
|
||||
|
||||
if (num == max) {
|
||||
REPORT(err, "Escape buffer limit reached");
|
||||
return -1;
|
||||
}
|
||||
out[num++] = escaped_v;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int value_escape(Value v, Value *out, int max, WL_Arena *arena, Error *err)
|
||||
{
|
||||
Type t = value_type(v);
|
||||
|
||||
if (t == TYPE_ARRAY)
|
||||
return array_escape(v, out, max, arena, err);
|
||||
|
||||
if (t == TYPE_STRING)
|
||||
return string_escape(v, out, max, arena, err);
|
||||
|
||||
if (max < 1)
|
||||
return -1;
|
||||
out[0] = v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Value value_escape_packed(Value v, WL_Arena *arena, Error *err)
|
||||
{
|
||||
Value tmp[32];
|
||||
int num = value_escape(v, tmp, COUNT(tmp), arena, err);
|
||||
if (num < 0) return VALUE_ERROR;
|
||||
|
||||
Value escaped_v;
|
||||
|
||||
if (num > 1) {
|
||||
|
||||
Value packed = value_empty_array(num, arena, err);
|
||||
if (packed == VALUE_ERROR)
|
||||
return VALUE_ERROR;
|
||||
|
||||
for (int j = 0; j < num; j++)
|
||||
if (!value_append(packed, tmp[j], arena, err))
|
||||
return VALUE_ERROR;
|
||||
escaped_v = packed;
|
||||
|
||||
} else {
|
||||
|
||||
ASSERT(num == 1);
|
||||
escaped_v = tmp[0];
|
||||
}
|
||||
|
||||
return escaped_v;
|
||||
}
|
||||
|
||||
#undef TYPE_PAIR
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@@ -4543,7 +4681,7 @@ struct WL_Runtime {
|
||||
|
||||
WL_Runtime *wl_runtime_init(WL_Arena *arena, WL_Program program)
|
||||
{
|
||||
if ((uint32_t) program.len < 3 * sizeof(uint32_t))
|
||||
if (program.len < 3 * sizeof(uint32_t))
|
||||
return NULL;
|
||||
|
||||
uint32_t magic;
|
||||
@@ -4645,7 +4783,7 @@ static String rt_read_str(WL_Runtime *rt)
|
||||
ASSERT(rt->state == RUNTIME_LOOP);
|
||||
uint32_t off = rt_read_u32(rt);
|
||||
uint32_t len = rt_read_u32(rt);
|
||||
ASSERT(off + len <= (uint32_t) rt->data.len);
|
||||
ASSERT(off + len <= rt->data.len);
|
||||
return (String) { rt->data.ptr + off, len };
|
||||
}
|
||||
|
||||
@@ -4857,6 +4995,37 @@ static void step(WL_Runtime *rt)
|
||||
rt_push_group(rt);
|
||||
break;
|
||||
|
||||
case OPCODE_ESCAPE:
|
||||
{
|
||||
ASSERT(rt->num_groups > 0);
|
||||
int start = rt->groups[--rt->num_groups];
|
||||
int end = rt->stack;
|
||||
|
||||
Value escaped[256];
|
||||
int num_escaped = 0;
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
Value v = rt->values[i];
|
||||
int num = value_escape(v, escaped + num_escaped, COUNT(escaped) - num_escaped, rt->arena, &rt->err);
|
||||
if (num < 0) break;
|
||||
num_escaped += num;
|
||||
}
|
||||
|
||||
if (num_escaped > COUNT(escaped)) {
|
||||
REPORT(&rt->err, "Escape buffer limit reached");
|
||||
rt->state = RUNTIME_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
rt->stack = start;
|
||||
if (!rt_check_stack(rt, num_escaped)) break;
|
||||
|
||||
for (int i = 0; i < num_escaped; i++)
|
||||
rt->values[rt->stack + i] = escaped[i];
|
||||
rt->stack += num_escaped;
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PACK:
|
||||
rt_pack_group(rt);
|
||||
break;
|
||||
@@ -5156,7 +5325,6 @@ WL_EvalResult wl_runtime_eval(WL_Runtime *rt)
|
||||
|
||||
switch (rt->state) {
|
||||
|
||||
case RUNTIME_BEGIN:
|
||||
case RUNTIME_LOOP:
|
||||
UNREACHABLE;
|
||||
|
||||
|
||||
+6
-6
@@ -179,13 +179,13 @@ let main =
|
||||
<main>
|
||||
<div class="thread-header">
|
||||
<div class="thread-title">
|
||||
<span>\post.title</span>
|
||||
<span>\escape(post.title)</span>
|
||||
</div>
|
||||
<div class="thread-meta">
|
||||
submitted 3 hours ago by <a href="">\post.username</a> | <a href="">\len comments</a>
|
||||
submitted 3 hours ago by <a href="">\escape(post.username)</a> | <a href="">\len(comments)</a>
|
||||
</div>
|
||||
<div class="thread-text">
|
||||
<pre>\post.content</pre>
|
||||
<pre>\escape(post.content)</pre>
|
||||
</div>
|
||||
<details>
|
||||
<summary>
|
||||
@@ -209,10 +209,10 @@ let main =
|
||||
</div>
|
||||
<div class="comment-content">
|
||||
<div class="comment-meta">
|
||||
<a href="">\comment.username</a> 2 hours ago
|
||||
<a href="">\escape(comment.username)</a> 2 hours ago
|
||||
</div>
|
||||
<div class="comment-text">
|
||||
<pre>\comment.content</pre>
|
||||
<pre>\escape(comment.content)</pre>
|
||||
</div>
|
||||
\if $login_user_id != none:
|
||||
<details>
|
||||
@@ -235,7 +235,7 @@ let main =
|
||||
</div>
|
||||
</div>
|
||||
|
||||
\if len root_comments == 0:
|
||||
\if len(root_comments) == 0:
|
||||
<div id="no-comments">
|
||||
No comments
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user