added qse_xli_getnumpairsbyname()
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user