mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 12:52:46 +00:00
Change PL_D_AddObject() so that it replaces values instead of stacking them.
Add PL_D_AllKeys(), which returns a list of all keys in a dictionary. Rename PL_FreeItem() to PL_Free() -- what was I smoking? Document some of the property list system for doxygen.
This commit is contained in:
parent
91fdd90674
commit
d1b4c5df72
2 changed files with 145 additions and 37 deletions
|
@ -37,6 +37,37 @@
|
|||
inrange((ch), '0', '9') ? ((ch) - 0x30) \
|
||||
: (inrange((ch), 'a', 'f') ? ((ch) - 0x57) : ((ch) - 0x37))
|
||||
|
||||
/**
|
||||
There are four types of data that can be stored in a property list:
|
||||
|
||||
QFDictionary A list of values, each associated with a key (a C string).
|
||||
QFArray A list of indexed values
|
||||
QFString A string.
|
||||
QFBinary Random binary data. The parser doesn't load these yet.
|
||||
|
||||
In textual form, a dictionary looks like:
|
||||
|
||||
{
|
||||
key = value;
|
||||
}
|
||||
|
||||
An array looks like:
|
||||
|
||||
(
|
||||
value1,
|
||||
value2
|
||||
)
|
||||
|
||||
An unquoted string may contain only alphanumeric characters and/or the
|
||||
underscore character, '_'. Quoted strings may contain whitespace, C escape
|
||||
sequences, and so on. The quote character is '"'.
|
||||
|
||||
QFBinary data (though not loaded currently) is hex-encoded and contained
|
||||
within angle brackets, < >. The length of the encoded data must be an even
|
||||
number, so while <FF00> is valid, <F00> isn't.
|
||||
|
||||
Property lists may contain C-style or BCPL-style comments.
|
||||
*/
|
||||
typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types
|
||||
|
||||
/*
|
||||
|
@ -78,10 +109,52 @@ typedef struct plbinary_s plbinary_t;
|
|||
|
||||
struct hashtab_s;
|
||||
|
||||
/**
|
||||
\fn plitem_t *PL_GetPropertyList (const char *string)
|
||||
\brief Create an in-memory representation of the contents of a property list
|
||||
|
||||
\param string the saved plist, as read from a file.
|
||||
|
||||
\return Returns an object equivalent to the passed-in string.
|
||||
You are responsible for freeing the object returned.
|
||||
*/
|
||||
plitem_t *PL_GetPropertyList (const char *);
|
||||
|
||||
/**
|
||||
\fn plitem_t *PL_ObjectForKey (plitem_t *dict, const char *key)
|
||||
\brief Retrieve a value from a dictionary object.
|
||||
|
||||
\param dict The dictionary to retrieve a value from
|
||||
\param key The unique key associated with the value
|
||||
|
||||
\return You are NOT responsible for freeing the returned object. It will
|
||||
be destroyed when its container is.
|
||||
*/
|
||||
plitem_t *PL_ObjectForKey (plitem_t *, const char *);
|
||||
|
||||
/**
|
||||
\fn plitem_t *PL_ObjectAtIndex (plitem_t *array, int idx)
|
||||
\brief Retrieve a value from an array object.
|
||||
|
||||
\param array The array to get the value from
|
||||
\param idx The index within the array to retrieve
|
||||
|
||||
\return You are NOT responsible for freeing the returned object. It will
|
||||
be destroyed when its container is.
|
||||
*/
|
||||
plitem_t *PL_ObjectAtIndex (plitem_t *, int);
|
||||
|
||||
/**
|
||||
\fn plitem_t *PL_D_AllKeys (plitem_t *dict)
|
||||
\brief Retrieve a list of all keys in a dictionary.
|
||||
|
||||
\param dict The dictionary to list
|
||||
|
||||
\return Returns an Array containing Strings. You are responsible for
|
||||
freeing this array.
|
||||
*/
|
||||
plitem_t *PL_D_AllKeys (plitem_t *);
|
||||
|
||||
plitem_t *PL_D_AddObject (plitem_t *, plitem_t *, plitem_t *);
|
||||
plitem_t *PL_A_AddObject (plitem_t *, plitem_t *);
|
||||
plitem_t *PL_A_InsertObjectAtIndex (plitem_t *, plitem_t *, int ind);
|
||||
|
@ -91,7 +164,14 @@ plitem_t *PL_NewArray (void);
|
|||
plitem_t *PL_NewData (void *, int);
|
||||
plitem_t *PL_NewString (const char *);
|
||||
|
||||
void PL_FreeItem (struct plitem_s *);
|
||||
/**
|
||||
\fn void PL_Free (plitem_t *object)
|
||||
\brief Free a property list object
|
||||
|
||||
This function takes care of freeing any referenced property list data, so
|
||||
only call it on top-level objects.
|
||||
*/
|
||||
void PL_Free (plitem_t *);
|
||||
|
||||
typedef struct pldata_s { // Unparsed property list string
|
||||
const char *ptr;
|
||||
|
|
|
@ -57,7 +57,7 @@ dict_free (void *i, void *unused)
|
|||
{
|
||||
dictkey_t *item = (dictkey_t *) i;
|
||||
free (item->key);
|
||||
PL_FreeItem (item->value); // Make descended stuff get freed
|
||||
PL_Free (item->value); // Make descended stuff get freed
|
||||
free (item);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ PL_NewString (const char *str)
|
|||
}
|
||||
|
||||
void
|
||||
PL_FreeItem (plitem_t *item)
|
||||
PL_Free (plitem_t *item)
|
||||
{
|
||||
switch (item->type) {
|
||||
case QFDictionary:
|
||||
|
@ -124,7 +124,7 @@ PL_FreeItem (plitem_t *item)
|
|||
int i = ((plarray_t *) item->data)->numvals;
|
||||
|
||||
while (i-- > 0) {
|
||||
PL_FreeItem (((plarray_t *) item->data)->values[i]);
|
||||
PL_Free (((plarray_t *) item->data)->values[i]);
|
||||
}
|
||||
free (((plarray_t *) item->data)->values);
|
||||
free (item->data);
|
||||
|
@ -156,6 +156,29 @@ PL_ObjectForKey (plitem_t *item, const char *key)
|
|||
return k ? k->value : NULL;
|
||||
}
|
||||
|
||||
plitem_t *
|
||||
PL_D_AllKeys (plitem_t *dict)
|
||||
{
|
||||
void **list;
|
||||
dictkey_t *current;
|
||||
plitem_t *array;
|
||||
|
||||
if (dict->type != QFDictionary)
|
||||
return NULL;
|
||||
|
||||
if (!(list = Hash_GetList ((hashtab_t *) dict->data)))
|
||||
return NULL;
|
||||
|
||||
if (!(array = PL_NewArray ()))
|
||||
return NULL;
|
||||
|
||||
while ((current = (dictkey_t *) *list++)) {
|
||||
PL_A_AddObject (array, PL_NewString (current->key));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
plitem_t *
|
||||
PL_ObjectAtIndex (plitem_t *item, int index)
|
||||
{
|
||||
|
@ -178,15 +201,20 @@ PL_D_AddObject (plitem_t *dict, plitem_t *key, plitem_t *value)
|
|||
if (key->type != QFString)
|
||||
return NULL;
|
||||
|
||||
if ((k = Hash_Find ((hashtab_t *)dict->data, key->data))) {
|
||||
PL_Free ((plitem_t *) k->value);
|
||||
k->value = value; // FIXME: should this be a copy?
|
||||
} else {
|
||||
k = malloc (sizeof (dictkey_t));
|
||||
|
||||
if (!k)
|
||||
return NULL;
|
||||
|
||||
k->key = strdup ((char *) key->data);
|
||||
k->value = value;
|
||||
k->value = value; // FIXME: see above
|
||||
|
||||
Hash_Add ((hashtab_t *)dict->data, k);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
@ -465,42 +493,42 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
plitem_t *value;
|
||||
|
||||
if (!(key = PL_ParsePropertyListItem (pl))) {
|
||||
PL_FreeItem (item);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(PL_SkipSpace (pl))) {
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (key->type != QFString) {
|
||||
pl->error = "Key is not a string";
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pl->ptr[pl->pos] != '=') {
|
||||
pl->error = "Unexpected character (expected '=')";
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
pl->pos++;
|
||||
|
||||
// If there is no value, lose the key
|
||||
if (!(value = PL_ParsePropertyListItem (pl))) {
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(PL_SkipSpace (pl))) {
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -508,25 +536,25 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
pl->pos++;
|
||||
} else if (pl->ptr[pl->pos] != '}') {
|
||||
pl->error = "Unexpected character (wanted ';' or '}')";
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the key/value pair to the dictionary
|
||||
if (!PL_D_AddObject (item, key, value)) {
|
||||
PL_FreeItem (key);
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (key);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
PL_FreeItem (key);
|
||||
PL_Free (key);
|
||||
}
|
||||
|
||||
if (pl->pos >= pl->end) { // Catch the error
|
||||
pl->error = "Unexpected end of string when parsing dictionary";
|
||||
PL_FreeItem (item);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
pl->pos++;
|
||||
|
@ -546,13 +574,13 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
plitem_t *value;
|
||||
|
||||
if (!(value = PL_ParsePropertyListItem (pl))) {
|
||||
PL_FreeItem (item);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(PL_SkipSpace (pl))) {
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -560,15 +588,15 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
pl->pos++;
|
||||
} else if (pl->ptr[pl->pos] != ')') {
|
||||
pl->error = "Unexpected character (wanted ',' or ')')";
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PL_A_AddObject (item, value)) {
|
||||
pl->error = "Unexpected character (too many items in array)";
|
||||
PL_FreeItem (value);
|
||||
PL_FreeItem (item);
|
||||
PL_Free (value);
|
||||
PL_Free (item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue