*/
-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
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) {
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;
}
* @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;
}
}
/* 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);
* 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
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)
{
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);
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 {
else if (*p == 'e' || *p == 'E') {
if (got_exp) {
/* Double exp, not a number */
+ rspamd_cl_chunk_restore_state (chunk, &s);
return FALSE;
}
else {
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 {
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;
}
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;
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 ++;
}