From 5ca66f5bda337964a5a509702ba78a979d2fe024 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Sat, 4 May 2019 15:26:53 +0800 Subject: [PATCH] Allow closing config elems with if from envvar The Cyclone DDS configuration is in principle an XML document, but it is possible to write configuration fragments directly in the CYCLONEDDS_URI environment variable. In that case, it is quite annoying to have to enter the full closing tags all the time, and so it now allows closing elements with a simple when not reading them from a file. While it would be trivial to also allow this when reading the configuration from a file, it seems that promulgating invalid XML would be bad form ... and besides, in that case editors can help keep everything in order. Signed-off-by: Erik Boasson --- src/core/ddsi/src/q_config.c | 2 +- src/ddsrt/include/dds/ddsrt/xmlparser.h | 5 ++++- src/ddsrt/src/xmlparser.c | 26 +++++++++++++++---------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index d9c37db..d12bc21 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -2685,7 +2685,7 @@ struct cfgst * config_init (const char *configfile) if (tok[0] == '<') { /* Read XML directly from input string */ qx = ddsrt_xmlp_new_string (tok, cfgst, &cb); - ddsrt_xmlp_set_requireEOF (qx, 0); + ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG); fp = NULL; } else { char *comma; diff --git a/src/ddsrt/include/dds/ddsrt/xmlparser.h b/src/ddsrt/include/dds/ddsrt/xmlparser.h index 120be63..e33815b 100644 --- a/src/ddsrt/include/dds/ddsrt/xmlparser.h +++ b/src/ddsrt/include/dds/ddsrt/xmlparser.h @@ -36,9 +36,12 @@ extern "C" { struct ddsrt_xmlp_state; +#define DDSRT_XMLP_REQUIRE_EOF 1u /* set by default; if not set, junk may follow top-level closing tag */ +#define DDSRT_XMLP_ANONYMOUS_CLOSE_TAG 2u /* clear by default; if set allow closing an element with instead of */ + DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_file (FILE *fp, void *varg, const struct ddsrt_xmlp_callbacks *cb); DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, const struct ddsrt_xmlp_callbacks *cb); - DDS_EXPORT void ddsrt_xmlp_set_requireEOF (struct ddsrt_xmlp_state *st, int require_eof); + DDS_EXPORT void ddsrt_xmlp_set_options (struct ddsrt_xmlp_state *st, unsigned options); DDS_EXPORT size_t ddsrt_xmlp_get_bufpos (const struct ddsrt_xmlp_state *st); DDS_EXPORT void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st); DDS_EXPORT int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st); diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c index e22bf09..ded4337 100644 --- a/src/ddsrt/src/xmlparser.c +++ b/src/ddsrt/src/xmlparser.c @@ -49,7 +49,7 @@ struct ddsrt_xmlp_state { size_t tpescp; /* still escape sequences in tpescp .. tpp */ int nest; /* current nesting level */ void *varg; /* user argument to callback functions */ - int require_eof; /* if false, junk may follow top-level closing tag */ + unsigned options; struct ddsrt_xmlp_callbacks cb; /* user-supplied callbacks (or stubs) */ }; @@ -108,7 +108,7 @@ static void ddsrt_xmlp_new_common (struct ddsrt_xmlp_state *st) st->peekpayload = NULL; st->nest = 0; st->error = 0; - st->require_eof = 1; + st->options = DDSRT_XMLP_REQUIRE_EOF; } static void ddsrt_xmlp_new_setCB (struct ddsrt_xmlp_state *st, void *varg, const struct ddsrt_xmlp_callbacks *cb) @@ -148,9 +148,9 @@ struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, return st; } -void ddsrt_xmlp_set_requireEOF (struct ddsrt_xmlp_state *st, int require_eof) +void ddsrt_xmlp_set_options (struct ddsrt_xmlp_state *st, unsigned options) { - st->require_eof = require_eof; + st->options = options; } size_t ddsrt_xmlp_get_bufpos (const struct ddsrt_xmlp_state *st) @@ -451,11 +451,14 @@ static int next_token_tag_withoutclose (struct ddsrt_xmlp_state *st, char **payl next_char (st); } /* we only do tag names that are identifiers */ - if (!qq_isidentfirst (peek_char (st))) { + if (peek_char (st) == '>' && (st->options & DDSRT_XMLP_ANONYMOUS_CLOSE_TAG)) { + return TOK_SHORTHAND_CLOSE_TAG; + } else if (!qq_isidentfirst (peek_char (st))) { return TOK_ERROR; + } else { + next_token_ident (st, payload); + return tok; } - next_token_ident (st, payload); - return tok; } } @@ -560,6 +563,9 @@ static int next_token (struct ddsrt_xmlp_state *st, char **payload) } } if (tok == TOK_ERROR) { + char msg[512]; + (void) snprintf (msg, sizeof (msg), "invalid token encountered"); + st->cb.error (st->varg, msg, st->line); st->error = 1; } return tok; @@ -674,10 +680,10 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) } } st->nest--; - if (next_token (st, &ename) != TOK_CLOSE_TAG || next_char (st) != '>') { + if (((tok = next_token (st, &ename)) != TOK_CLOSE_TAG && tok != TOK_SHORTHAND_CLOSE_TAG) || next_char (st) != '>') { PE_LOCAL_ERROR ("expecting closing tag", name); } - if (strcmp (name, ename) != 0) { + if (tok != TOK_SHORTHAND_CLOSE_TAG && strcmp (name, ename) != 0) { PE_LOCAL_ERROR ("open/close tag mismatch", ename); } ret = st->cb.elem_close (st->varg, eleminfo); @@ -709,7 +715,7 @@ int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st) return 0; } else { int ret = parse_element (st, 0); - if (ret < 0|| !st->require_eof || next_token (st, NULL) == TOK_EOF ) { + if (ret < 0|| !(st->options & DDSRT_XMLP_REQUIRE_EOF) || next_token (st, NULL) == TOK_EOF ) { return ret; } else { return -1;