From 41e269801406c374a041da0fd0c6b4eff6ba4f3d Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 17 Oct 2013 14:56:02 +0100 Subject: [PATCH] Fix rcl issues (ported from libucl). --- src/rcl/rcl_emitter.c | 130 ++++++++++++++++++++++-------------------- src/rcl/rcl_parser.c | 56 ++++++++++++++---- 2 files changed, 113 insertions(+), 73 deletions(-) diff --git a/src/rcl/rcl_emitter.c b/src/rcl/rcl_emitter.c index 9702ffefd..bf394ee1d 100644 --- a/src/rcl/rcl_emitter.c +++ b/src/rcl/rcl_emitter.c @@ -31,9 +31,12 @@ */ -static void rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact); -static void rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact); -static void rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top); +static void rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, + gboolean start_tabs, gboolean compact); +static void rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, + gboolean start_tabs, gboolean compact); +static void rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, + gboolean start_tabs, gboolean is_top, gboolean expand_array); /** * Add tabulation to the output buffer @@ -306,25 +309,22 @@ rspamd_cl_elt_obj_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, g_string_append_len (buf, "{\n", 2); } - while (obj) { - HASH_ITER (hh, obj, cur, tmp) { - rspamd_cl_add_tabs (buf, tabs + 1, is_top); - g_string_append (buf, cur->key); - if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { - g_string_append_len (buf, " = ", 3); - } - else { - g_string_append_c (buf, ' '); - } - rspamd_cl_elt_write_rcl (cur, buf, is_top ? tabs : tabs + 1, FALSE, FALSE); - if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { - g_string_append_len (buf, ";\n", 2); - } - else { - g_string_append_c (buf, '\n'); - } + HASH_ITER (hh, obj, cur, tmp) { + rspamd_cl_add_tabs (buf, tabs + 1, is_top); + g_string_append (buf, cur->key); + if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { + g_string_append_len (buf, " = ", 3); + } + else { + g_string_append_c (buf, ' '); + } + rspamd_cl_elt_write_rcl (cur, buf, is_top ? tabs : tabs + 1, FALSE, FALSE, TRUE); + if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { + g_string_append_len (buf, ";\n", 2); + } + else { + g_string_append_c (buf, '\n'); } - obj = obj->next; } rspamd_cl_add_tabs (buf, tabs, is_top); if (!is_top) { @@ -348,7 +348,7 @@ rspamd_cl_elt_array_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs g_string_append_len (buf, "[\n", 2); while (cur) { - rspamd_cl_elt_write_rcl (cur, buf, tabs + 1, TRUE, FALSE); + rspamd_cl_elt_write_rcl (cur, buf, tabs + 1, TRUE, FALSE, FALSE); g_string_append_len (buf, ",\n", 2); cur = cur->next; } @@ -362,47 +362,53 @@ rspamd_cl_elt_array_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs * @param buf buffer */ static void -rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top) +rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, + gboolean start_tabs, gboolean is_top, gboolean expand_array) { - switch (obj->type) { - case RSPAMD_CL_INT: - if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs, FALSE); - } - g_string_append_printf (buf, "%ld", (long int)rspamd_cl_obj_toint (obj)); - break; - case RSPAMD_CL_FLOAT: - if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs, FALSE); - } - g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); - break; - case RSPAMD_CL_TIME: - if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs, FALSE); - } - g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); - break; - case RSPAMD_CL_BOOLEAN: - if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs, FALSE); - } - g_string_append_printf (buf, "%s", rspamd_cl_obj_toboolean (obj) ? "true" : "false"); - break; - case RSPAMD_CL_STRING: - if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs, FALSE); + if (expand_array && obj->next) { + rspamd_cl_elt_array_write_rcl (obj, buf, tabs, start_tabs, is_top); + } + else { + switch (obj->type) { + case RSPAMD_CL_INT: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%ld", (long int)rspamd_cl_obj_toint (obj)); + break; + case RSPAMD_CL_FLOAT: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); + break; + case RSPAMD_CL_TIME: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); + break; + case RSPAMD_CL_BOOLEAN: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%s", rspamd_cl_obj_toboolean (obj) ? "true" : "false"); + break; + case RSPAMD_CL_STRING: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + rspamd_cl_elt_string_write_json (rspamd_cl_obj_tostring (obj), buf); + break; + case RSPAMD_CL_OBJECT: + rspamd_cl_elt_obj_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); + break; + case RSPAMD_CL_ARRAY: + rspamd_cl_elt_array_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); + break; + case RSPAMD_CL_USERDATA: + break; } - rspamd_cl_elt_string_write_json (rspamd_cl_obj_tostring (obj), buf); - break; - case RSPAMD_CL_OBJECT: - rspamd_cl_elt_obj_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); - break; - case RSPAMD_CL_ARRAY: - rspamd_cl_elt_array_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); - break; - case RSPAMD_CL_USERDATA: - break; } } @@ -420,7 +426,7 @@ rspamd_cl_object_emit_rcl (rspamd_cl_object_t *obj) /* Allocate large enough buffer */ buf = g_string_sized_new (BUFSIZ); - rspamd_cl_elt_write_rcl (obj, buf, 0, FALSE, TRUE); + rspamd_cl_elt_write_rcl (obj, buf, 0, FALSE, TRUE, TRUE); res = buf->str; g_string_free (buf, FALSE); diff --git a/src/rcl/rcl_parser.c b/src/rcl/rcl_parser.c index 7989ece15..b601df310 100644 --- a/src/rcl/rcl_parser.c +++ b/src/rcl/rcl_parser.c @@ -32,6 +32,13 @@ * The implementation of rcl parser */ +struct rspamd_cl_parser_saved_state { + guint line; + guint column; + gsize remain; + const guchar *pos; +}; + /** * Move up to len characters * @param parser @@ -54,6 +61,34 @@ rspamd_cl_chunk_skipc (struct rspamd_cl_chunk *chunk, guchar c) chunk->remain --; } +/** + * Save parser state + * @param chunk + * @param s + */ +static inline void +rspamd_cl_chunk_save_state (struct rspamd_cl_chunk *chunk, struct rspamd_cl_parser_saved_state *s) +{ + s->column = chunk->column; + s->pos = chunk->pos; + s->line = chunk->line; + s->remain = chunk->remain; +} + +/** + * Restore parser state + * @param chunk + * @param s + */ +static inline void +rspamd_cl_chunk_restore_state (struct rspamd_cl_chunk *chunk, struct rspamd_cl_parser_saved_state *s) +{ + chunk->column = s->column; + chunk->pos = s->pos; + chunk->line = s->line; + chunk->remain = s->remain; +} + static inline gboolean rcl_test_character (guchar c, gint type_flags) { @@ -227,6 +262,9 @@ rspamd_cl_lex_number (struct rspamd_cl_parser *parser, gboolean got_dot = FALSE, got_exp = FALSE, need_double = FALSE, is_date = FALSE; gdouble dv; gint64 lv; + struct rspamd_cl_parser_saved_state s; + + rspamd_cl_chunk_save_state (chunk, &s); if (*p == '-') { rspamd_cl_chunk_skipc (chunk, *p); @@ -240,11 +278,13 @@ rspamd_cl_lex_number (struct rspamd_cl_parser *parser, else { if (p == c) { /* Empty digits sequence, not a number */ + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } else if (*p == '.') { if (got_dot) { /* Double dots, not a number */ + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } else { @@ -257,6 +297,7 @@ rspamd_cl_lex_number (struct rspamd_cl_parser *parser, else if (*p == 'e' || *p == 'E') { if (got_exp) { /* Double exp, not a number */ + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } else { @@ -265,10 +306,12 @@ rspamd_cl_lex_number (struct rspamd_cl_parser *parser, rspamd_cl_chunk_skipc (chunk, *p); p ++; if (p >= chunk->end) { + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } if (!g_ascii_isdigit (*p) && *p != '+' && *p != '-') { /* Wrong exponent sign */ + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } else { @@ -295,6 +338,7 @@ rspamd_cl_lex_number (struct rspamd_cl_parser *parser, rspamd_cl_set_err (chunk, RSPAMD_CL_ESYNTAX, "numeric value is out of range", err); parser->prev_state = parser->state; parser->state = RSPAMD_RCL_STATE_ERROR; + rspamd_cl_chunk_restore_state (chunk, &s); return FALSE; } @@ -950,7 +994,7 @@ static gboolean rspamd_cl_parse_after_value (struct rspamd_cl_parser *parser, struct rspamd_cl_chunk *chunk, GError **err) { const guchar *p; - gboolean got_sep = FALSE, got_comma = FALSE, got_semicolon = FALSE; + gboolean got_sep = FALSE; struct rspamd_cl_stack *st; p = chunk->pos; @@ -973,22 +1017,12 @@ rspamd_cl_parse_after_value (struct rspamd_cl_parser *parser, struct rspamd_cl_c else if (*p == ',') { /* Got a separator */ got_sep = TRUE; - if (got_comma || got_semicolon) { - rspamd_cl_set_err (chunk, RSPAMD_CL_ESYNTAX, "unexpected comma detected", err); - return FALSE; - } - got_comma = TRUE; rspamd_cl_chunk_skipc (chunk, *p); p ++; } else if (*p == ';') { /* Got a separator */ got_sep = TRUE; - if (got_comma || got_semicolon) { - rspamd_cl_set_err (chunk, RSPAMD_CL_ESYNTAX, "unexpected semicolon detected", err); - return FALSE; - } - got_semicolon = TRUE; rspamd_cl_chunk_skipc (chunk, *p); p ++; } -- 2.39.5