Skip to content

Commit

Permalink
Fixed various bugs in setting lookups by name/path.
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperrealm committed Nov 22, 2022
1 parent 0a5cfd9 commit 5ff6aec
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 45 deletions.
2 changes: 1 addition & 1 deletion doc/libconfig.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,7 @@ These methods construct @code{SettingTypeException} objects for the given @var{s
@tindex SettingRangeException
A @code{SettingRangeException} is thrown when an attempt is made to
read a 64-bit integer configuration setting into an integer variable,
and that value of the setting is outside the range of an integer.
and the value of that setting is outside the range of an integer.

@deftypemethod SettingRangeException {} SettingRangeException (@w{const Setting &@var{setting}})
@deftypemethodx SettingRangeException {} SettingRangeException (@w{const Setting &@var{setting}}, @w{int @var{index}})
Expand Down
79 changes: 35 additions & 44 deletions lib/libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,32 +125,6 @@ static void __config_locale_restore(void)

/* ------------------------------------------------------------------------- */

static int __config_name_compare(const char *a, const char *b)
{
const char *p, *q;

for(p = a, q = b; ; p++, q++)
{
int pd = ((! *p) || strchr(PATH_TOKENS, *p));
int qd = ((! *q) || strchr(PATH_TOKENS, *q));

if(pd && qd)
break;
else if(pd)
return(-1);
else if(qd)
return(1);
else if(*p < *q)
return(-1);
else if(*p > *q)
return(1);
}

return(0);
}

/* ------------------------------------------------------------------------- */

static void __config_indent(FILE *stream, int depth, unsigned short w)
{
if(w)
Expand Down Expand Up @@ -385,8 +359,12 @@ static void __config_list_add(config_list_t *list, config_setting_t *setting)

/* ------------------------------------------------------------------------- */

/* This function takes the length of the name to be searched for, so that one
* component of a longer path can be passed in.
*/
static config_setting_t *__config_list_search(config_list_t *list,
const char *name,
size_t namelen,
unsigned int *idx)
{
config_setting_t **found = NULL;
Expand All @@ -400,7 +378,8 @@ static config_setting_t *__config_list_search(config_list_t *list,
if(! (*found)->name)
continue;

if(! __config_name_compare(name, (*found)->name))
if((strlen((*found)->name) == namelen)
&& !strncmp(name, (*found)->name, namelen))
{
if(idx)
*idx = i;
Expand Down Expand Up @@ -1226,27 +1205,37 @@ config_setting_t *config_setting_lookup(config_setting_t *setting,
const char *p = path;
config_setting_t *found = setting;

for(;;)
while(*p && found)
{
while(*p && strchr(PATH_TOKENS, *p))
p++;

if(! *p)
break;
if(strchr(PATH_TOKENS, *p))
++p;

if(*p == '[')
found = config_setting_get_elem(found, atoi(++p));
else
found = config_setting_get_member(found, p);
{
char *q;
long index = strtol(++p, &q, 10);
if(*q != ']')
return NULL;

if(! found)
break;
p = ++q;
found = config_setting_get_elem(found, index);
}
else if(found->type == CONFIG_TYPE_GROUP)
{
const char *q = p;

while(! strchr(PATH_TOKENS, *p))
p++;
while(*q && !strchr(PATH_TOKENS, *q))
++q;

found = __config_list_search(found->value.list, p, (size_t)(q - p),
NULL);
p = q;
}
else
break;
}

return(*p || (found == setting) ? NULL : found);
return((*p || (found == setting)) ? NULL : found);
}

/* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -1565,7 +1554,7 @@ config_setting_t *config_setting_get_member(const config_setting_t *setting,
if(setting->type != CONFIG_TYPE_GROUP)
return(NULL);

return(__config_list_search(setting->value.list, name, NULL));
return(__config_list_search(setting->value.list, name, strlen(name), NULL));
}

/* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -1676,9 +1665,11 @@ int config_setting_remove(config_setting_t *parent, const char *name)
break;
}

}while(*++settingName);
}
while(*++settingName);

if(!(setting = __config_list_search(setting->parent->value.list, settingName, &idx)))
if(!(setting = __config_list_search(setting->parent->value.list, settingName,
strlen(settingName), &idx)))
return(CONFIG_FALSE);

__config_list_remove(setting->parent->value.list, idx);
Expand Down
6 changes: 6 additions & 0 deletions tests/testdata/nesting.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

foo = (
{ string: "orange", number: 3, flag: false, array: [7, 13] },
{ string: "blue", number: 11, flag: true, array: [1, 2, 3, 4] },
{ string: "red", number: 7, flag: false, array: [77, 88] }
)
94 changes: 94 additions & 0 deletions tests/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,15 @@ TT_TEST(EscapedStrings)
TT_ASSERT_TRUE(ok);
TT_ASSERT_STR_EQ("abc\"def\"", str);

ok = config_lookup_string(&cfg, "escape_seqs.dquote.[0]", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "escape_seqs.dquote.extrajunk", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "escape_seqs.dquote.", &str);
TT_ASSERT_TRUE(ok);

config_destroy(&cfg);
}

Expand Down Expand Up @@ -545,6 +554,90 @@ TT_TEST(OverrideSetting)

/* ------------------------------------------------------------------------- */

TT_TEST(SettingLookups)
{
config_t cfg;
int ok;
int ival;
const char *str;
config_setting_t *setting, *parent;

config_init(&cfg);
config_set_options(&cfg, CONFIG_OPTION_ALLOW_OVERRIDES);
config_set_include_dir(&cfg, "./testdata");

ok = config_read_file(&cfg, "testdata/nesting.cfg");
if(!ok)
{
printf("error: %s:%d\n", config_error_text(&cfg),
config_error_line(&cfg));
}
TT_ASSERT_TRUE(ok);

ok = config_lookup_string(&cfg, "foo.[0].string", &str);
TT_ASSERT_TRUE(ok);
TT_ASSERT_STR_EQ("orange", str);

ok = config_lookup_int(&cfg, "foo.[1].array.[3]", &ival);
TT_ASSERT_TRUE(ok);
TT_ASSERT_INT_EQ(4, ival);

ok = config_lookup_bool(&cfg, "foo.[1].flag", &ival);
TT_ASSERT_TRUE(ok);
TT_ASSERT_INT_EQ(CONFIG_TRUE, ival);

ok = config_lookup_int(&cfg, "foo.[2].number", &ival);
TT_ASSERT_TRUE(ok);
TT_ASSERT_INT_EQ(7, ival);

ok = config_lookup_string(&cfg, "foo.[0].string.blah", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "foo.[0].string.[0]", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "foo.[0].[1]", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "foo.[0].array.[0].blah", &str);
TT_ASSERT_FALSE(ok);

ok = config_lookup_string(&cfg, "[0]", &str);
TT_ASSERT_FALSE(ok);

setting = config_lookup(&cfg, "foo.[0].array.[0]");
TT_ASSERT_PTR_NOTNULL(setting);

setting = config_lookup(&cfg, "foo.[0].array.[0");
TT_ASSERT_PTR_NULL(setting);

setting = config_lookup(&cfg, "/foo.[0].array.[0]");
TT_ASSERT_PTR_NOTNULL(setting);

setting = config_lookup(&cfg, "/foo/[0]/array/[0]");
TT_ASSERT_PTR_NOTNULL(setting);

parent = config_lookup(&cfg, ".foo");
TT_ASSERT_PTR_NOTNULL(parent);

setting = config_setting_lookup(parent, ".[0]");
TT_ASSERT_PTR_NOTNULL(setting);

setting = config_setting_lookup(parent, ".[0].array");
TT_ASSERT_PTR_NOTNULL(setting);

setting = config_setting_lookup(parent, ".[0].array.[1]");
TT_ASSERT_PTR_NOTNULL(setting);

setting = config_setting_lookup(parent, "[0].array.[1000]");
TT_ASSERT_PTR_NULL(setting);

setting = config_setting_lookup(parent, "[0].array.[0].blah");
TT_ASSERT_PTR_NULL(setting);
}

/* ------------------------------------------------------------------------- */

int main(int argc, char **argv)
{
int failures;
Expand All @@ -563,6 +656,7 @@ int main(int argc, char **argv)
TT_SUITE_TEST(LibConfigTests, RemoveSetting);
TT_SUITE_TEST(LibConfigTests, EscapedStrings);
TT_SUITE_TEST(LibConfigTests, OverrideSetting);
TT_SUITE_TEST(LibConfigTests, SettingLookups);
TT_SUITE_RUN(LibConfigTests);
failures = TT_SUITE_NUM_FAILURES(LibConfigTests);
TT_SUITE_END(LibConfigTests);
Expand Down

0 comments on commit 5ff6aec

Please sign in to comment.