mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-23 19:01:06 +00:00
[util] Add a PL dictionary to hash table parser
This commit is contained in:
parent
55c1ed124d
commit
fefb32bf13
2 changed files with 147 additions and 3 deletions
|
@ -147,7 +147,7 @@ int PL_Line (const plitem_t *item) __attribute__((pure));
|
|||
\return the size in bytes of the binary object 0 if binary isn't a binary
|
||||
object.
|
||||
*/
|
||||
size_t PL_BinarySize (const plitem_t *item) __attribute__((pure));
|
||||
size_t PL_BinarySize (const plitem_t *binary) __attribute__((pure));
|
||||
|
||||
/** Retrieve the data from a binary object.
|
||||
|
||||
|
@ -323,9 +323,9 @@ void PL_Free (plitem_t *item);
|
|||
|
||||
Can be used recursively to parse deep hierarchies.
|
||||
|
||||
\param dict The dictionary object to parse
|
||||
\param fields Array of field items describing the structure. Terminated
|
||||
by a field item with a null \a name pointer.
|
||||
\param dict The dictionary object to parse
|
||||
\param data Pointer to the structure into which the data will be
|
||||
parsed.
|
||||
\param messages Array object supplied by the caller used for storing
|
||||
|
@ -344,8 +344,90 @@ void PL_Free (plitem_t *item);
|
|||
*/
|
||||
int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict,
|
||||
void *data, plitem_t *messages, void *context);
|
||||
int PL_ParseArray (const plfield_t *fields, const plitem_t *dict,
|
||||
|
||||
/** Parse an array object into a dynamic arrah (see darray.h).
|
||||
|
||||
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 array The array 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().
|
||||
\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.
|
||||
\return 0 if there are any errors, 1 if there are no errors.
|
||||
*/
|
||||
int PL_ParseArray (const plfield_t *field, const plitem_t *array,
|
||||
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
|
||||
how to parse the object associated with that key. Duplicate keys are an
|
||||
error: they must be unique. A suitable message is added to the
|
||||
\a messages object. If the dictionary object is empty, the destination
|
||||
table is left unmodified.
|
||||
|
||||
When an error occurs (duplicate keys, incorrect type, 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.
|
||||
|
||||
Hash_Add() is used to add objects to the hash table, and Hash_Find() is
|
||||
used to check for duplicates. Hash_Free() is used to free unused
|
||||
objects. The means that the hash table is expected to use standard
|
||||
objects with embedded keys (the parser is expected to put the key in the
|
||||
object) and to have a free function.
|
||||
|
||||
The parser's data paramenter points to a pre-allocated block of memory
|
||||
of the sized indicated by the element object's size field, using the
|
||||
element object's alloc callback. The name field in the field paramenter
|
||||
is set to the object's key and remains owned by the dictionary.
|
||||
|
||||
\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 dictionary.
|
||||
\param dict The dictionary object to parse
|
||||
\param data Pointer to the structure into which the data will be
|
||||
parsed.
|
||||
\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.
|
||||
\return 0 if there are any errors, 1 if there are no errors.
|
||||
*/
|
||||
int PL_ParseSymtab (const plfield_t *field, const plitem_t *dict,
|
||||
void *data, plitem_t *messages, void *context);
|
||||
void __attribute__((format(printf,3,4)))
|
||||
PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...);
|
||||
|
||||
|
|
|
@ -1247,3 +1247,65 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data,
|
|||
*(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)
|
||||
{
|
||||
void **list, **l;
|
||||
dictkey_t *current;
|
||||
int result = 1;
|
||||
plparser_t parser;
|
||||
__auto_type tab = (hashtab_t *) data;
|
||||
|
||||
plelement_t *element = (plelement_t *) field->data;
|
||||
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 {
|
||||
PL_Message (messages, dict, "no parser set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) {
|
||||
// empty struct: leave as default
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *obj = element->alloc (element->stride);
|
||||
while ((current = (dictkey_t *) *l++)) {
|
||||
const char *key = current->key;
|
||||
plitem_t *item = current->value;
|
||||
|
||||
if (item->type != element->type) {
|
||||
PL_Message (messages, item,
|
||||
"error: element %s is the wrong type"
|
||||
" Got %s, expected %s", key,
|
||||
pl_types[element->type],
|
||||
pl_types[item->type]);
|
||||
result = 0;
|
||||
continue;
|
||||
}
|
||||
f.name = key;
|
||||
if (Hash_Find (tab, key)) {
|
||||
PL_Message (messages, item, "duplicate name");
|
||||
result = 0;
|
||||
} else {
|
||||
if (!parser (&f, item, obj, messages, context)) {
|
||||
result = 0;
|
||||
} else {
|
||||
Hash_Add (tab, obj);
|
||||
obj = element->alloc (element->stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
Hash_Free (tab, obj);
|
||||
free (list);
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue