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);
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;
}
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;
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);
if (streq(token, ",")) {
state = STATE_NAME;
- allowed_delimiters = NULL;
+ allowed_delimiters = "#";
allowed_chars = VALID_CHARS_IDENTIFIER;
} else {
assert(streq(token, ")"));
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;
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;
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);
if (r < 0)
return r;
+ assert(!interface->name);
interface->name = TAKE_PTR(token);
+
state = STATE_PRE_SYMBOL;
allowed_delimiters = "#";
allowed_chars = VALID_CHARS_RESERVED;
}
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;
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);
}