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:
Jeff Teunissen 2004-01-06 11:09:40 +00:00
parent 91fdd90674
commit d1b4c5df72
2 changed files with 145 additions and 37 deletions

View file

@ -37,6 +37,37 @@
inrange((ch), '0', '9') ? ((ch) - 0x30) \ inrange((ch), '0', '9') ? ((ch) - 0x30) \
: (inrange((ch), 'a', 'f') ? ((ch) - 0x57) : ((ch) - 0x37)) : (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 typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types
/* /*
@ -78,10 +109,52 @@ typedef struct plbinary_s plbinary_t;
struct hashtab_s; 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 *); 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 *); 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); 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_D_AddObject (plitem_t *, plitem_t *, plitem_t *);
plitem_t *PL_A_AddObject (plitem_t *, plitem_t *); plitem_t *PL_A_AddObject (plitem_t *, plitem_t *);
plitem_t *PL_A_InsertObjectAtIndex (plitem_t *, plitem_t *, int ind); 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_NewData (void *, int);
plitem_t *PL_NewString (const char *); 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 typedef struct pldata_s { // Unparsed property list string
const char *ptr; const char *ptr;

View file

@ -57,7 +57,7 @@ dict_free (void *i, void *unused)
{ {
dictkey_t *item = (dictkey_t *) i; dictkey_t *item = (dictkey_t *) i;
free (item->key); free (item->key);
PL_FreeItem (item->value); // Make descended stuff get freed PL_Free (item->value); // Make descended stuff get freed
free (item); free (item);
} }
@ -113,7 +113,7 @@ PL_NewString (const char *str)
} }
void void
PL_FreeItem (plitem_t *item) PL_Free (plitem_t *item)
{ {
switch (item->type) { switch (item->type) {
case QFDictionary: case QFDictionary:
@ -124,7 +124,7 @@ PL_FreeItem (plitem_t *item)
int i = ((plarray_t *) item->data)->numvals; int i = ((plarray_t *) item->data)->numvals;
while (i-- > 0) { 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 (((plarray_t *) item->data)->values);
free (item->data); free (item->data);
@ -156,6 +156,29 @@ PL_ObjectForKey (plitem_t *item, const char *key)
return k ? k->value : NULL; 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 * plitem_t *
PL_ObjectAtIndex (plitem_t *item, int index) 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) if (key->type != QFString)
return NULL; return NULL;
k = malloc (sizeof (dictkey_t)); 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) if (!k)
return NULL; return NULL;
k->key = strdup ((char *) key->data); k->key = strdup ((char *) key->data);
k->value = value; k->value = value; // FIXME: see above
Hash_Add ((hashtab_t *)dict->data, k); Hash_Add ((hashtab_t *)dict->data, k);
}
return dict; return dict;
} }
@ -465,42 +493,42 @@ PL_ParsePropertyListItem (pldata_t *pl)
plitem_t *value; plitem_t *value;
if (!(key = PL_ParsePropertyListItem (pl))) { if (!(key = PL_ParsePropertyListItem (pl))) {
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (!(PL_SkipSpace (pl))) { if (!(PL_SkipSpace (pl))) {
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (key->type != QFString) { if (key->type != QFString) {
pl->error = "Key is not a string"; pl->error = "Key is not a string";
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (pl->ptr[pl->pos] != '=') { if (pl->ptr[pl->pos] != '=') {
pl->error = "Unexpected character (expected '=')"; pl->error = "Unexpected character (expected '=')";
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
pl->pos++; pl->pos++;
// If there is no value, lose the key // If there is no value, lose the key
if (!(value = PL_ParsePropertyListItem (pl))) { if (!(value = PL_ParsePropertyListItem (pl))) {
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (!(PL_SkipSpace (pl))) { if (!(PL_SkipSpace (pl))) {
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
@ -508,25 +536,25 @@ PL_ParsePropertyListItem (pldata_t *pl)
pl->pos++; pl->pos++;
} else if (pl->ptr[pl->pos] != '}') { } else if (pl->ptr[pl->pos] != '}') {
pl->error = "Unexpected character (wanted ';' or '}')"; pl->error = "Unexpected character (wanted ';' or '}')";
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
// Add the key/value pair to the dictionary // Add the key/value pair to the dictionary
if (!PL_D_AddObject (item, key, value)) { if (!PL_D_AddObject (item, key, value)) {
PL_FreeItem (key); PL_Free (key);
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
PL_FreeItem (key); PL_Free (key);
} }
if (pl->pos >= pl->end) { // Catch the error if (pl->pos >= pl->end) { // Catch the error
pl->error = "Unexpected end of string when parsing dictionary"; pl->error = "Unexpected end of string when parsing dictionary";
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
pl->pos++; pl->pos++;
@ -546,13 +574,13 @@ PL_ParsePropertyListItem (pldata_t *pl)
plitem_t *value; plitem_t *value;
if (!(value = PL_ParsePropertyListItem (pl))) { if (!(value = PL_ParsePropertyListItem (pl))) {
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (!(PL_SkipSpace (pl))) { if (!(PL_SkipSpace (pl))) {
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
@ -560,15 +588,15 @@ PL_ParsePropertyListItem (pldata_t *pl)
pl->pos++; pl->pos++;
} else if (pl->ptr[pl->pos] != ')') { } else if (pl->ptr[pl->pos] != ')') {
pl->error = "Unexpected character (wanted ',' or ')')"; pl->error = "Unexpected character (wanted ',' or ')')";
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
if (!PL_A_AddObject (item, value)) { if (!PL_A_AddObject (item, value)) {
pl->error = "Unexpected character (too many items in array)"; pl->error = "Unexpected character (too many items in array)";
PL_FreeItem (value); PL_Free (value);
PL_FreeItem (item); PL_Free (item);
return NULL; return NULL;
} }
} }