Prefix matching for config XML in CYCLONEDDS_URI

Allow unique prefix matches for elements and attributes specified in
directly in CYCLONEDDS_URI.  That mode already has a few niceties for
quickly specifying some configuration overrides, this is simply one
more.

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2019-10-03 13:42:46 +02:00 committed by eboasson
parent a25b69be7d
commit aa5236dea4

View file

@ -116,6 +116,10 @@ struct cfgst {
been inserted */
enum implicit_toplevel implicit_toplevel;
/* Whether unique prefix matching on a name is allowed (again for environment
variables) */
bool partial_match_allowed;
/* current input, mask with 1 bit set */
uint32_t source;
@ -2237,10 +2241,17 @@ static void free_configured_elements (struct cfgst *cfgst, void *parent, struct
free_configured_element (cfgst, parent, ce);
}
static int matching_name_index (const char *name_w_aliases, const char *name)
static int matching_name_index (const char *name_w_aliases, const char *name, size_t *partial)
{
const char *ns = name_w_aliases, *p = strchr (ns, '|');
const char *ns = name_w_aliases;
const char *aliases = strchr (ns, '|');
const char *p = aliases;
int idx = 0;
if (partial)
{
/* may be set later on */
*partial = 0;
}
while (p)
{
if (ddsrt_strncasecmp (ns, name, (size_t) (p - ns)) == 0 && name[p - ns] == 0)
@ -2253,7 +2264,24 @@ static int matching_name_index (const char *name_w_aliases, const char *name)
p = strchr (ns, '|');
idx++;
}
return (ddsrt_strcasecmp (ns, name) == 0) ? idx : -1;
if (ddsrt_strcasecmp (ns, name) == 0)
return idx;
else
{
if (partial)
{
/* try a partial match on the primary name (the aliases are for backwards compatibility,
and as partial matches are for hackability, I am of the opinion that backwards
compatibility on those is a bit over the top) */
size_t max_len = strlen (name);
if (aliases && (size_t) (aliases - name_w_aliases) < max_len)
max_len = (size_t) (aliases - name_w_aliases);
if (ddsrt_strncasecmp (name_w_aliases, name, max_len) == 0)
*partial = max_len;
/* it may be a partial match, but it is still not a match */
}
return -1;
}
}
static const struct cfgelem *lookup_element (const char *target, bool *isattr)
@ -2284,7 +2312,7 @@ static const struct cfgelem *lookup_element (const char *target, bool *isattr)
}
for (; cfgelem->name; cfgelem++)
{
if (matching_name_index (cfgelem->name, p) >= 0)
if (matching_name_index (cfgelem->name, p, NULL) >= 0)
{
/* not supporting chained redirects */
assert (cfgelem->name[0] != '>');
@ -2327,6 +2355,8 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
const struct cfgelem *cfgelem = cfgst_tos (cfgst);
const struct cfgelem *cfg_subelem;
int moved = 0;
size_t partial = 0;
const struct cfgelem *partial_match = NULL;
if (cfgelem == NULL)
{
@ -2337,11 +2367,12 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
for (cfg_subelem = cfgelem->children; cfg_subelem && cfg_subelem->name && strcmp (cfg_subelem->name, "*") != 0; cfg_subelem++)
{
const char *csename = cfg_subelem->name;
size_t partial1;
int idx;
moved = (csename[0] == '>');
if (moved)
csename++;
idx = matching_name_index (csename, name);
idx = matching_name_index (csename, name, &partial1);
if (idx > 0)
{
if (csename[0] == '|')
@ -2355,15 +2386,34 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
}
}
if (idx >= 0)
{
/* an exact match is always good */
break;
}
if (partial1 > partial)
{
/* a longer prefix match is a candidate ... */
partial = partial1;
partial_match = cfg_subelem;
}
else if (partial1 > 0 && partial1 == partial)
{
/* ... but an ambiguous prefix match won't do */
partial_match = NULL;
}
}
if (cfg_subelem == NULL || cfg_subelem->name == NULL)
{
cfg_error (cfgst, "%s: unknown element", name);
cfgst_push (cfgst, 0, NULL, NULL);
return 0;
if (partial_match != NULL && cfgst->partial_match_allowed)
cfg_subelem = partial_match;
else
{
cfg_error (cfgst, "%s: unknown element", name);
cfgst_push (cfgst, 0, NULL, NULL);
return 0;
}
}
else if (strcmp (cfg_subelem->name, "*") == 0)
if (strcmp (cfg_subelem->name, "*") == 0)
{
/* Push a marker that we are to ignore this part of the DOM tree */
cfgst_push (cfgst, 0, NULL, NULL);
@ -2695,6 +2745,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi
}
cfgst->implicit_toplevel = (fp == NULL) ? ITL_ALLOWED : ITL_DISALLOWED;
cfgst->partial_match_allowed = (fp == NULL);
cfgst->first_data_in_source = true;
cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg);
ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error;