mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-21 09:51:41 +00:00
[util] Add plist parser for dictionary -> array
PL_ParseLabeledArray works the same way as PL_ParseArray, but instead takes a dictionary object. The keys of the items are ignored, and the order is not preserved (at this stage), but this is a cleaner solution to getting an array of objects when the definitions of those objects need to be accessible by name as well.
This commit is contained in:
parent
bc763da9f6
commit
0dcd946063
2 changed files with 98 additions and 4 deletions
|
@ -396,6 +396,45 @@ int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict,
|
|||
int PL_ParseArray (const plfield_t *field, const plitem_t *array,
|
||||
void *data, plitem_t *messages, void *context);
|
||||
|
||||
/** Parse a dictionary object into a dynamic array (see darray.h).
|
||||
|
||||
This is useful when the dictionary object is meant to be a labeled list
|
||||
rather than a representation of a structure.
|
||||
|
||||
For each object in the array, the field item is used to determine how to
|
||||
parse the object. If the array is empty, the destination will be
|
||||
initialized to an empty array.
|
||||
|
||||
When an error occurs (incorrect item type (item type does not match the
|
||||
type specified in the element object) or the element object's \a parser
|
||||
returns 0), processing continues but the error result is returned.
|
||||
|
||||
Can be used recursively to parse deep hierarchies.
|
||||
|
||||
\param field Pointer to a single field that has the field data pointer
|
||||
set to reference a plelement_t object used to describe
|
||||
the contents of the array.
|
||||
\param dict The dict object to parse
|
||||
\param data Pointer to the pointer to which the dynamic array will
|
||||
be written. The dynamic array is allocated using
|
||||
DARRAY_ALLOCFIXED_OBJ().
|
||||
\param messages Array object supplied by the caller used for storing
|
||||
messages. The messages may or may not indicate errors (its
|
||||
contents are not checked). This function itself will add
|
||||
only string objects.
|
||||
If there are any errors, suitable messages will be found in
|
||||
the \a messages object. However, just because there are no
|
||||
errors doesn't mean that \a messages will remain empty as
|
||||
a field's \a parser may add other messages. The standard
|
||||
message format is "[line number]: [message]". If the line
|
||||
number is 0, then the actual line is unknown (due to the
|
||||
source item not being parsed from a file or string).
|
||||
\param context Additional context data passed to the parser and allocator.
|
||||
\return 0 if there are any errors, 1 if there are no errors.
|
||||
*/
|
||||
int PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict,
|
||||
void *data, plitem_t *messages, void *context);
|
||||
|
||||
/** Parse a dictionary object into a hash table.
|
||||
|
||||
For each key in the dictionary, the element object is used to determine
|
||||
|
|
|
@ -1211,10 +1211,7 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) {
|
||||
// empty struct: leave as default
|
||||
return 1;
|
||||
}
|
||||
l = list = Hash_GetList ((hashtab_t *) dict->data);
|
||||
|
||||
while ((current = (dictkey_t *) *l++)) {
|
||||
const plfield_t *f;
|
||||
|
@ -1299,6 +1296,64 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data,
|
|||
return result;
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict,
|
||||
void *data, plitem_t *messages, void *context)
|
||||
{
|
||||
void **list, **l;
|
||||
dictkey_t *current;
|
||||
int result = 1;
|
||||
plparser_t parser;
|
||||
plelement_t *element = (plelement_t *) field->data;
|
||||
typedef struct arr_s DARRAY_TYPE(byte) arr_t;
|
||||
arr_t *arr;
|
||||
plfield_t f = { 0, 0, element->type, element->parser, element->data };
|
||||
|
||||
if (dict->type != QFDictionary) {
|
||||
PL_Message (messages, dict, "error: not a dictionary object");
|
||||
return 0;
|
||||
}
|
||||
if (f.parser) {
|
||||
parser = f.parser;
|
||||
} else {
|
||||
parser = pl_default_parser;
|
||||
}
|
||||
|
||||
list = Hash_GetList ((hashtab_t *) dict->data);
|
||||
|
||||
int numvals = 0;
|
||||
for (l = list; *l; l++) {
|
||||
numvals++;
|
||||
}
|
||||
|
||||
arr = DARRAY_ALLOCFIXED_OBJ (arr_t, numvals * element->stride,
|
||||
element->alloc, context);
|
||||
memset (arr->a, 0, arr->size);
|
||||
// the array is allocated using bytes, but need the actual number of
|
||||
// elements in the array
|
||||
arr->size = arr->maxSize = numvals;
|
||||
|
||||
for (int i = 0; i < numvals; i++) {
|
||||
current = list[i];
|
||||
plitem_t *item = current->value;
|
||||
void *eledata = &arr->a[i * element->stride];
|
||||
|
||||
if (!PL_CheckType (element->type, item->type)) {
|
||||
char index[16];
|
||||
snprintf (index, sizeof(index) - 1, "%d", i);
|
||||
index[15] = 0;
|
||||
PL_TypeMismatch (messages, item, index, element->type, item->type);
|
||||
result = 0;
|
||||
} else {
|
||||
if (!parser (&f, item, eledata, messages, context)) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*(arr_t **) data = arr;
|
||||
return result;
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data,
|
||||
plitem_t *messages, void *context)
|
||||
|
|
Loading…
Reference in a new issue