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:
parent
a25b69be7d
commit
aa5236dea4
1 changed files with 60 additions and 9 deletions
|
@ -116,6 +116,10 @@ struct cfgst {
|
||||||
been inserted */
|
been inserted */
|
||||||
enum implicit_toplevel implicit_toplevel;
|
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 */
|
/* current input, mask with 1 bit set */
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
|
|
||||||
|
@ -2237,10 +2241,17 @@ static void free_configured_elements (struct cfgst *cfgst, void *parent, struct
|
||||||
free_configured_element (cfgst, parent, ce);
|
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;
|
int idx = 0;
|
||||||
|
if (partial)
|
||||||
|
{
|
||||||
|
/* may be set later on */
|
||||||
|
*partial = 0;
|
||||||
|
}
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
if (ddsrt_strncasecmp (ns, name, (size_t) (p - ns)) == 0 && name[p - ns] == 0)
|
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, '|');
|
p = strchr (ns, '|');
|
||||||
idx++;
|
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)
|
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++)
|
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 */
|
/* not supporting chained redirects */
|
||||||
assert (cfgelem->name[0] != '>');
|
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 *cfgelem = cfgst_tos (cfgst);
|
||||||
const struct cfgelem *cfg_subelem;
|
const struct cfgelem *cfg_subelem;
|
||||||
int moved = 0;
|
int moved = 0;
|
||||||
|
size_t partial = 0;
|
||||||
|
const struct cfgelem *partial_match = NULL;
|
||||||
|
|
||||||
if (cfgelem == 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++)
|
for (cfg_subelem = cfgelem->children; cfg_subelem && cfg_subelem->name && strcmp (cfg_subelem->name, "*") != 0; cfg_subelem++)
|
||||||
{
|
{
|
||||||
const char *csename = cfg_subelem->name;
|
const char *csename = cfg_subelem->name;
|
||||||
|
size_t partial1;
|
||||||
int idx;
|
int idx;
|
||||||
moved = (csename[0] == '>');
|
moved = (csename[0] == '>');
|
||||||
if (moved)
|
if (moved)
|
||||||
csename++;
|
csename++;
|
||||||
idx = matching_name_index (csename, name);
|
idx = matching_name_index (csename, name, &partial1);
|
||||||
if (idx > 0)
|
if (idx > 0)
|
||||||
{
|
{
|
||||||
if (csename[0] == '|')
|
if (csename[0] == '|')
|
||||||
|
@ -2355,15 +2386,34 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
/* an exact match is always good */
|
||||||
break;
|
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)
|
if (cfg_subelem == NULL || cfg_subelem->name == NULL)
|
||||||
{
|
{
|
||||||
cfg_error (cfgst, "%s: unknown element", name);
|
if (partial_match != NULL && cfgst->partial_match_allowed)
|
||||||
cfgst_push (cfgst, 0, NULL, NULL);
|
cfg_subelem = partial_match;
|
||||||
return 0;
|
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 */
|
/* Push a marker that we are to ignore this part of the DOM tree */
|
||||||
cfgst_push (cfgst, 0, NULL, NULL);
|
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->implicit_toplevel = (fp == NULL) ? ITL_ALLOWED : ITL_DISALLOWED;
|
||||||
|
cfgst->partial_match_allowed = (fp == NULL);
|
||||||
cfgst->first_data_in_source = true;
|
cfgst->first_data_in_source = true;
|
||||||
cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg);
|
cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg);
|
||||||
ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error;
|
ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue