From fa3310deb9c5fa5bb441277e2568d47633d017ba Mon Sep 17 00:00:00 2001 From: lixianjing Date: Fri, 1 Dec 2023 08:19:27 +0800 Subject: [PATCH] conf json support comments --- docs/changes.md | 3 ++ src/conf_io/conf_json.c | 81 +++++++++++++++++++++++++++++++++-------- tests/conf_json_test.cc | 55 ++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 15 deletions(-) diff --git a/docs/changes.md b/docs/changes.md index 44ece98ece..b4a0396d5b 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,8 @@ # 最新动态 +2023/12/01 + * conf_json 支持块注释/**/和行注释// + 2023/11/28 * 将 value change event 移到 tkc 中。 * remote\_ui 支持 hook log。 diff --git a/src/conf_io/conf_json.c b/src/conf_io/conf_json.c index 79c00cef79..861203ed48 100644 --- a/src/conf_io/conf_json.c +++ b/src/conf_io/conf_json.c @@ -27,18 +27,6 @@ #include "tkc/data_reader_factory.h" #include "tkc/data_writer_factory.h" -typedef enum _parser_state_t { - STATE_NONE = 0, - STATE_IN_NAME, - STATE_IN_VALUE_NUMBER, - STATE_IN_VALUE_STR, - STATE_GROUP, - STATE_BEFORE_KEY, - STATE_KEY, - STATE_BEFORE_VALUE, - STATE_AFTER_VALUE -} parser_state_t; - typedef struct _json_parser_t { const char* data; uint32_t size; @@ -51,6 +39,7 @@ typedef struct _json_parser_t { } json_parser_t; static ret_t conf_json_parse_value(json_parser_t* parser); +static ret_t conf_json_skip_all_comments(json_parser_t* parser); static ret_t conf_json_skip_to_char(json_parser_t* parser, char c); static ret_t conf_json_parse_name(json_parser_t* parser) { @@ -134,7 +123,7 @@ static ret_t conf_json_parse_object(json_parser_t* parser) { return_value_if_fail(conf_json_parse_value(parser) == RET_OK, RET_FAIL); parser->current = parser->current->parent; - return_value_if_fail(conf_json_skip_spaces(parser) == RET_OK, RET_BAD_PARAMS); + conf_json_skip_all_comments(parser); c = parser->data[parser->cursor]; if (c == '}') { parser->cursor++; @@ -170,7 +159,7 @@ static ret_t conf_json_parse_array(json_parser_t* parser) { return_value_if_fail(conf_json_parse_value(parser) == RET_OK, RET_FAIL); parser->current = node->parent; - conf_json_skip_spaces(parser); + conf_json_skip_all_comments(parser); c = parser->data[parser->cursor]; if (c == ']') { parser->cursor++; @@ -244,6 +233,65 @@ static ret_t conf_json_parse_string(json_parser_t* parser) { return conf_node_set_value(parser->current, &v); } +static ret_t conf_json_skip_comment(json_parser_t* parser) { + char c = 0; + char next_c = 0; + bool_t is_block_comment = FALSE; + bool_t is_line_comment = FALSE; + const char* p = parser->data; + + conf_json_skip_spaces(parser); + if ((parser->cursor + 1) < parser->size) { + c = p[parser->cursor]; + next_c = p[parser->cursor + 1]; + if (c == '/' && next_c == '*') { + is_block_comment = TRUE; + } else if (c == '/' && next_c == '/') { + is_line_comment = TRUE; + } else { + return RET_FAIL; + } + + parser->cursor += 2; + for (; (parser->cursor + 1) < parser->size; parser->cursor++) { + c = p[parser->cursor]; + next_c = p[parser->cursor + 1]; + + if (is_block_comment) { + if (c == '*' && next_c == '/') { + parser->cursor += 2; + break; + } + } else if (is_line_comment) { + if (c == '\r') { + parser->cursor++; + if (next_c == '\n') { + parser->cursor++; + } + break; + } else if (c == '\n') { + parser->cursor++; + break; + } + } + } + + return RET_OK; + } else { + return RET_FAIL; + } +} + +static ret_t conf_json_skip_all_comments(json_parser_t* parser) { + while (conf_json_skip_comment(parser) == RET_OK) { + if (parser->cursor == parser->size) { + break; + } + } + + return RET_OK; +} + static ret_t conf_json_parse_value(json_parser_t* parser) { char c = 0; conf_node_t* node = NULL; @@ -251,9 +299,12 @@ static ret_t conf_json_parse_value(json_parser_t* parser) { conf_doc_t* doc = parser->doc; for (; parser->cursor < parser->size; parser->cursor++) { + conf_json_skip_all_comments(parser); c = p[parser->cursor]; - if (c == '{' || c == '[') { + if (c == '\0' || parser->cursor == parser->size) { + break; + } else if (c == '{' || c == '[') { if (doc->root == NULL) { node = conf_doc_create_node(doc, CONF_NODE_ROOT_NAME); return_value_if_fail(node != NULL, RET_OOM); diff --git a/tests/conf_json_test.cc b/tests/conf_json_test.cc index e1fbe46d47..f32916405d 100644 --- a/tests/conf_json_test.cc +++ b/tests/conf_json_test.cc @@ -31,6 +31,35 @@ TEST(ConfJson, arr) { conf_doc_destroy(doc); } +TEST(ConfJson, arr_comment) { + value_t v; + str_t str; + const char* data = " /*comment*/[/*comment*/[/*comment*/1/*comment*/,2/*comment*/,/*comment*/3]/*comment*/, /*comment*/\"abc\"/*comment*/] "; + conf_doc_t* doc = conf_doc_load_json(data, -1); + + str_init(&str, 100); + conf_doc_save_json(doc, &str); + str_reset(&str); + + ASSERT_EQ(conf_doc_get(doc, "[1]", &v), RET_OK); + ASSERT_STREQ(value_str(&v), "abc"); + + ASSERT_EQ(conf_doc_get(doc, "[0].[0]", &v), RET_OK); + ASSERT_EQ(value_int(&v), 1); + + ASSERT_EQ(conf_doc_get(doc, "[0].[1]", &v), RET_OK); + ASSERT_EQ(value_int(&v), 2); + + ASSERT_EQ(conf_doc_get(doc, "[0].[2]", &v), RET_OK); + ASSERT_EQ(value_int(&v), 3); + + str_init(&str, 100); + conf_doc_save_json(doc, &str); + str_reset(&str); + + conf_doc_destroy(doc); +} + TEST(ConfJson, arr1) { value_t v; str_t str; @@ -95,6 +124,32 @@ TEST(ConfJson, basic1) { conf_doc_destroy(doc); } +TEST(ConfJson, basic1_comment) { + value_t v; + str_t str; + conf_node_t* node = NULL; + const char* data = " /*comment*/{//comment\r\"tom\"//comment\n : { //comment\r\n \"name\"//comment\r\n : //comment\r\n\"tom\"//comment\r\n, \"age\"//comment\r : 100 //comment\n } /*comment*/ /*comment*/} "; + + conf_doc_t* doc = conf_doc_load_json(data, -1); + + node = conf_node_find_child(doc->root, "tom"); + ASSERT_EQ(node != NULL, true); + ASSERT_STREQ(conf_node_get_name(node), "tom"); + + ASSERT_EQ(conf_doc_get(doc, "tom.name", &v), RET_OK); + ASSERT_STREQ(value_str(&v), "tom"); + + ASSERT_EQ(conf_doc_get(doc, "tom.age", &v), RET_OK); + ASSERT_EQ(value_int(&v), 100); + + str_init(&str, 100); + conf_doc_save_json(doc, &str); + + str_reset(&str); + + conf_doc_destroy(doc); +} + TEST(ConfJson, basic21) { value_t v; str_t str;