added qse_xli_getnumpairsbyname()

This commit is contained in:
2013-03-10 16:25:36 +00:00
parent 096628f7a7
commit 357aec132a
4 changed files with 754 additions and 57 deletions

View File

@ -350,6 +350,33 @@ void qse_xli_clear (qse_xli_t* xli)
free_list (xli, &xli->root);
}
static qse_size_t count_pair_byname (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* name)
{
qse_xli_atom_t* p;
qse_size_t count = 0;
/* TODO: speed up. no linear search */
p = list->head;
while (p)
{
if (p->type == QSE_XLI_PAIR)
{
qse_xli_pair_t* pair = (qse_xli_pair_t*)p;
if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)
{
if (name == QSE_NULL ||
qse_strxcmp (name->ptr, name->len, pair->name) == 0) count++;
}
}
p = p->next;
}
return count;
}
static qse_xli_pair_t* find_pair_byname (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* name)
@ -403,8 +430,7 @@ static qse_xli_pair_t* find_pair_byindex (
return QSE_NULL;
}
qse_xli_pair_t* qse_xli_findpairbyname (
qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name)
qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name)
{
const qse_char_t* ptr;
qse_cstr_t seg;
@ -417,9 +443,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (
while (1)
{
seg.ptr = ptr;
while (*ptr != QSE_T('\0') &&
*ptr != QSE_T('.') &&
*ptr != QSE_T('[')) ptr++;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
if (ptr == seg.ptr) goto inval;
seg.len = ptr - seg.ptr;
@ -530,3 +554,139 @@ noent:
return QSE_NULL;
}
qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name)
{
const qse_char_t* ptr;
qse_cstr_t seg;
qse_xli_list_t* curlist;
qse_xli_pair_t* pair;
curlist = list? list: &xli->root;
ptr = name;
while (1)
{
seg.ptr = ptr;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
if (ptr == seg.ptr) goto inval;
seg.len = ptr - seg.ptr;
if (curlist->type != QSE_XLI_LIST)
{
/* check the type of curlist. this check is needed
* because of the unconditional switching at the bottom of the
* this loop. this implementation strategy has been chosen
* to provide the segment name easily. */
goto noent;
}
if (*ptr == QSE_T('['))
{
/* index is specified */
ptr++;
if (QSE_ISDIGIT(*ptr))
{
/* numeric index */
qse_size_t index = 0, count = 0;
do
{
index = index * 10 + (*ptr++ - QSE_T('0'));
count++;
}
while (QSE_ISDIGIT(*ptr));
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byindex (xli, curlist, &seg, index);
if (pair == QSE_NULL)
{
seg.len += count + 2; /* adjustment for error message */
goto noent;
}
}
else if (QSE_ISALPHA(*ptr))
{
/* word index */
qse_cstr_t idx;
idx.ptr = ptr;
do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-'));
idx.len = ptr - idx.ptr;
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
goto noent;
}
}
else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"'))
{
qse_cstr_t idx;
qse_char_t cc = *ptr++;
idx.ptr = ptr;
do ptr++; while (*ptr != cc && *ptr != QSE_T('\0'));
idx.len = ptr - idx.ptr;
if (*ptr != cc) goto inval;
if (*++ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 4; /* adjustment for error message */
goto noent;
}
}
else goto inval;
ptr++; /* skip ] */
if (*ptr == QSE_T('\0'))
{
/* no more segments */
return 1;
}
else if (*ptr != QSE_T('.')) goto inval;
}
else
{
pair = find_pair_byname (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
if (*ptr == QSE_T('\0'))
{
return count_pair_byname (xli, curlist, &seg, QSE_NULL);
}
else
{
pair = find_pair_byname (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
}
}
/* more segments to handle */
QSE_ASSERT (*ptr == QSE_T('.'));
ptr++;
/* switch to the value regardless of its type.
* check if it is a list in the beginning of the loop
* just after having gotten the next segment name */
curlist = (qse_xli_list_t*)pair->val;
}
return pair;
inval:
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return 0;
noent:
qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &seg);
return 0;
}