From ce2d2260c9e8195b8d8bf4e798c8c2d3c29098ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Apr 2024 15:33:02 +0200 Subject: [PATCH] varlink: parse comments too --- src/shared/varlink-idl.c | 89 ++++++++++++++++++++++++++++++++----- src/test/test-varlink-idl.c | 15 +++++++ 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/shared/varlink-idl.c b/src/shared/varlink-idl.c index f249ff5955..e100137a75 100644 --- a/src/shared/varlink-idl.c +++ b/src/shared/varlink-idl.c @@ -657,8 +657,10 @@ static int varlink_idl_subparse_token( static int varlink_idl_subparse_comment( const char **p, unsigned *line, - unsigned *column) { + unsigned *column, + char **ret) { + _cleanup_free_ char *comment = NULL; size_t l; assert(p); @@ -667,9 +669,30 @@ static int varlink_idl_subparse_comment( assert(column); l = strcspn(*p, NEWLINE); + + if (!utf8_is_valid_n(*p, l)) + return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Comment is not valid UTF-8.", *line, *column); + + if (ret) { + /* Remove a single space as prefix of a comment, if one is specified. This is because we + * generally expect comments to be formatted as "# foobar" rather than "#foobar", and will + * ourselves format them that way. We accept the comments without the space too however. We + * will not strip more than one space, to allow indented comment blocks. */ + + if (**p == ' ') + comment = strndup(*p + 1, l - 1); + else + comment = strndup(*p, l); + if (!comment) + return -ENOMEM; + } + advance_line_column(*p, l + 1, line, column); *p += l; + if (ret) + *ret = TAKE_PTR(comment); + return 1; } @@ -856,7 +879,7 @@ static int varlink_idl_subparse_struct_or_enum( return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Unexpected token '%s'.", *line, *column, token); state = STATE_NAME; - allowed_delimiters = ")"; + allowed_delimiters = ")#"; allowed_chars = VALID_CHARS_IDENTIFIER; break; @@ -865,7 +888,23 @@ static int varlink_idl_subparse_struct_or_enum( if (!token) return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Premature EOF.", *line, *column); - if (streq(token, ")")) + else if (streq(token, "#")) { + _cleanup_free_ char *comment = NULL; + + r = varlink_idl_subparse_comment(p, line, column, &comment); + if (r < 0) + return r; + + r = varlink_symbol_realloc(symbol, *n_fields + 1); + if (r < 0) + return r; + + VarlinkField *field = (*symbol)->fields + (*n_fields)++; + *field = (VarlinkField) { + .name = TAKE_PTR(comment), + .field_type = _VARLINK_FIELD_COMMENT, + }; + } else if (streq(token, ")")) state = STATE_DONE; else { field_name = TAKE_PTR(token); @@ -929,7 +968,7 @@ static int varlink_idl_subparse_struct_or_enum( if (streq(token, ",")) { state = STATE_NAME; - allowed_delimiters = NULL; + allowed_delimiters = "#"; allowed_chars = VALID_CHARS_IDENTIFIER; } else { assert(streq(token, ")")); @@ -947,7 +986,7 @@ static int varlink_idl_subparse_struct_or_enum( return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Premature EOF.", *line, *column); if (streq(token, ",")) { state = STATE_NAME; - allowed_delimiters = NULL; + allowed_delimiters = "#"; allowed_chars = VALID_CHARS_IDENTIFIER; } else if (streq(token, ")")) state = STATE_DONE; @@ -1062,9 +1101,24 @@ int varlink_idl_parse( if (!token) return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Premature EOF.", *line, *column); if (streq(token, "#")) { - r = varlink_idl_subparse_comment(&text, line, column); + _cleanup_free_ char *comment = NULL; + + r = varlink_idl_subparse_comment(&text, line, column, &comment); if (r < 0) return r; + + r = varlink_interface_realloc(&interface, n_symbols + 1); + if (r < 0) + return r; + + r = varlink_symbol_realloc(&symbol, 0); + if (r < 0) + return r; + + symbol->symbol_type = _VARLINK_INTERFACE_COMMENT; + symbol->name = TAKE_PTR(comment); + + interface->symbols[n_symbols++] = TAKE_PTR(symbol); } else if (streq(token, "interface")) { state = STATE_INTERFACE; allowed_delimiters = NULL; @@ -1074,9 +1128,6 @@ int varlink_idl_parse( break; case STATE_INTERFACE: - assert(!interface); - assert(n_symbols == 0); - if (!token) return varlink_idl_log(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Premature EOF.", *line, *column); @@ -1084,7 +1135,9 @@ int varlink_idl_parse( if (r < 0) return r; + assert(!interface->name); interface->name = TAKE_PTR(token); + state = STATE_PRE_SYMBOL; allowed_delimiters = "#"; allowed_chars = VALID_CHARS_RESERVED; @@ -1097,9 +1150,25 @@ int varlink_idl_parse( } if (streq(token, "#")) { - r = varlink_idl_subparse_comment(&text, line, column); + _cleanup_free_ char *comment = NULL; + + r = varlink_idl_subparse_comment(&text, line, column, &comment); if (r < 0) return r; + + r = varlink_interface_realloc(&interface, n_symbols + 1); + if (r < 0) + return r; + + assert(!symbol); + r = varlink_symbol_realloc(&symbol, 0); + if (r < 0) + return r; + + symbol->symbol_type = _VARLINK_SYMBOL_COMMENT; + symbol->name = TAKE_PTR(comment); + + interface->symbols[n_symbols++] = TAKE_PTR(symbol); } else if (streq(token, "method")) { state = STATE_METHOD; allowed_chars = VALID_CHARS_IDENTIFIER; diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index 6a28edf467..f8c8080ee5 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -123,6 +123,21 @@ static void test_parse_format_one(const VarlinkInterface *iface) { assert_se(varlink_idl_parse(text, NULL, NULL, &parsed) >= 0); assert_se(varlink_idl_consistent(parsed, LOG_ERR) >= 0); assert_se(varlink_idl_format(parsed, &text2) >= 0); + + ASSERT_STREQ(text, text2); + + text = mfree(text); + text2 = mfree(text2); + parsed = varlink_interface_free(parsed); + + /* Do the same thing, but aggressively line break, and make sure this is roundtrippable as well */ + assert_se(varlink_idl_dump(stdout, /* use_colors=*/ true, 23, iface) >= 0); + assert_se(varlink_idl_consistent(iface, LOG_ERR) >= 0); + assert_se(varlink_idl_format_full(iface, 23, &text) >= 0); + assert_se(varlink_idl_parse(text, NULL, NULL, &parsed) >= 0); + assert_se(varlink_idl_consistent(parsed, LOG_ERR) >= 0); + assert_se(varlink_idl_format_full(parsed, 23, &text2) >= 0); + ASSERT_STREQ(text, text2); } -- 2.25.1