Property list updates. Objects of type QFDictionary are now hash tables

(and thus have a new simpler PL_ObjectForKey() function to get a value for
a key). Also, you can now call PL_FreeItem() on a plitem_t to free a
property list item and all of its descendants (if it has any).

Binary plist values are still not supported.
This commit is contained in:
Jeff Teunissen 2001-06-19 02:10:47 +00:00
parent 3a94567913
commit 118645fd51
2 changed files with 118 additions and 64 deletions

View file

@ -3,7 +3,7 @@
Property list management types and prototypes Property list management types and prototypes
Copyright (C) 2000 Jeff Teunissen <deek@dusknet.dhs.org> Copyright (C) 2000 Jeff Teunissen <deek@d2dc.net>
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
@ -26,60 +26,63 @@
$Id$ $Id$
*/ */
#ifndef __qfplist_h_ #ifndef __QF_qfplist_h_
#define __qfplist_h_ #define __QF_qfplist_h_
#include <glob.h>
#include "QF/qtypes.h" #include "QF/qtypes.h"
// Ugly defines for fast checking and conversion from char to number // Ugly defines for fast checking and conversion from char to number
#define inrange(ch,min,max) ((ch) >= (min) && (ch) <= (max)) #define inrange(ch,min,max) ((ch) >= (min) && (ch) <= (max))
#define char2num(ch) \ #define char2num(ch) \
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))
// Maximum number of items in an array // Maximum number of items in an array
#define MAX_ARRAY_INDEX 128 #define MAX_ARRAY_INDEX 128
typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types
/*
Generic property list item
*/
struct plitem_s { struct plitem_s {
struct plitem_s *next; // Pointer to next item
pltype_t type; // Type pltype_t type; // Type
union shared { // Type-dependant data void *data;
struct dict_s *dict;
struct array_s *array;
void *binary;
char *string;
} data;
}; };
typedef struct plitem_s plitem_t;
/* /*
Dictionaries Dictionaries
*/ */
struct dict_s {
int numkeys; // Number of items in dictionary
struct dictkey_s *keys;
};
struct dictkey_s { struct dictkey_s {
struct dictkey_s *next; char *key;
struct plitem_s *key; plitem_t *value;
struct plitem_s *value;
}; };
typedef struct dictkey_s dictkey_t;
/* /*
Arrays Arrays
*/ */
struct array_s { struct plarray_s {
int numvals; // Number of items in array int numvals; // Number of items in array
struct plitem_s *values[MAX_ARRAY_INDEX+1]; // Array data struct plitem_s *values[MAX_ARRAY_INDEX+1]; // Array data
}; };
typedef struct plarray_s plarray_t;
// now that we've defined the structs, define their types so we can use them /*
typedef struct plitem_s plitem_t; Typeless, unformatted binary data (not supported yet)
typedef struct dict_s dict_t; */
typedef struct dictkey_s dictkey_t; struct plbinary_s {
typedef struct array_s array_t; size_t size;
void *data;
};
typedef struct plbinary_s plbinary_t;
plitem_t *PL_GetPropertyList (const char *);
plitem_t *PL_ObjectForKey (struct hashtab_s *, const char *);
void PL_FreeItem (struct plitem_s *);
typedef struct pldata_s { // Unparsed property list string typedef struct pldata_s { // Unparsed property list string
const char *ptr; const char *ptr;
@ -89,8 +92,6 @@ typedef struct pldata_s { // Unparsed property list string
char *error; char *error;
} pldata_t; } pldata_t;
plitem_t *PL_GetPropertyList (const char *);
/* /*
Internal prototypes Internal prototypes
@ -99,4 +100,4 @@ plitem_t *PL_GetPropertyList (const char *);
static char *PL_ParseQuotedString (pldata_t *); static char *PL_ParseQuotedString (pldata_t *);
static char *PL_ParseUnquotedString (pldata_t *); static char *PL_ParseUnquotedString (pldata_t *);
*/ */
#endif // __qfplist_h_ #endif // __QF_qfplist_h_

View file

@ -3,7 +3,7 @@
Property list management Property list management
Copyright (C) 2000 Jeff Teunissen <deek@dusknet.dhs.org> Copyright (C) 2000 Jeff Teunissen <deek@d2dc.net>
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
@ -34,6 +34,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "QF/hash.h"
#include "QF/qfplist.h" #include "QF/qfplist.h"
#include "QF/qtypes.h" #include "QF/qtypes.h"
@ -42,6 +43,58 @@ static qboolean PL_SkipSpace (pldata_t *);
static char *PL_ParseQuotedString (pldata_t *); static char *PL_ParseQuotedString (pldata_t *);
static char *PL_ParseUnquotedString (pldata_t *); static char *PL_ParseUnquotedString (pldata_t *);
void
PL_FreeItem (plitem_t *item)
{
switch (item->type) {
case QFDictionary:
Hash_DelTable (item->data);
break;
case QFArray: {
int i = ((plarray_t *) item->data)->numvals;
while (--i) {
PL_FreeItem (((plarray_t *) item->data)->values[i]);
}
free (item->data);
}
break;
case QFBinary:
free (((plbinary_t *) item->data)->data);
free (item->data);
break;
case QFString:
free (item->data);
break;
}
free (item);
}
static const char *
dict_get_key (void *i, void *unused)
{
dictkey_t *item = (dictkey_t *) i;
return item->key;
}
static void
dict_free (void *i, void *unused)
{
dictkey_t *item = (dictkey_t *) i;
free (item->key);
PL_FreeItem (item->value); // Make descended stuff get freed
free (item);
}
plitem_t *
PL_ObjectForKey (hashtab_t *table, const char *key)
{
return (plitem_t *) Hash_Find (table, key);
}
static qboolean static qboolean
PL_SkipSpace (pldata_t *pl) PL_SkipSpace (pldata_t *pl)
{ {
@ -262,7 +315,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
switch (pl->ptr[pl->pos]) { switch (pl->ptr[pl->pos]) {
case '{': { case '{': {
dict_t *dict = calloc (1, sizeof (dict_t)); hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL);
pl->pos++; pl->pos++;
@ -272,12 +325,24 @@ PL_ParsePropertyListItem (pldata_t *pl)
if (!(key = PL_ParsePropertyListItem (pl))) if (!(key = PL_ParsePropertyListItem (pl)))
return NULL; return NULL;
if (!(PL_SkipSpace (pl))) { if (!(PL_SkipSpace (pl))) {
free (key->data);
free (key); free (key);
return NULL; return NULL;
} }
if (key->type != QFString) {
pl->error = "Key is not a string";
free (key->data);
free (key);
return NULL;
}
if (pl->ptr[pl->pos] != '=') { if (pl->ptr[pl->pos] != '=') {
pl->error = "Unexpected character (wanted '=')"; pl->error = "Unexpected character (wanted '=')";
free (key->data);
free (key); free (key);
return NULL; return NULL;
} }
@ -285,58 +350,46 @@ PL_ParsePropertyListItem (pldata_t *pl)
// 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))) {
free (key->data);
free (key); free (key);
return NULL; return NULL;
} }
if (!(PL_SkipSpace (pl))) { if (!(PL_SkipSpace (pl))) {
free (key->data);
free (key); free (key);
free (value->data);
free (value); free (value);
return NULL; return NULL;
} }
if (pl->ptr[pl->pos] == ';') { if (pl->ptr[pl->pos] == ';') {
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 '}')";
free (key->data);
free (key); free (key);
free (value->data);
free (value); free (value);
return NULL; return NULL;
} }
// Add the key/value pair to the dict { // Add the key/value pair to the dictionary
if (!(dict->keys)) { // No keys, add one
dictkey_t *k = calloc (1, sizeof (dictkey_t)); dictkey_t *k = calloc (1, sizeof (dictkey_t));
if (!k) { if (!k) {
free (key->data);
free (key); free (key);
free (value->data);
free (value); free (value);
return NULL; return NULL;
} }
k->key = key; k->key = (char *) key->data;
k->value = value; k->value = value;
dict->keys = k; Hash_Add (dict, k);
} else {
dictkey_t *k;
for (k = dict->keys; k; k = k->next) { // add to end
if (k->next == NULL) {
dictkey_t *k2 = calloc (1, sizeof (dictkey_t));
if (!k2) {
free (key);
free (value);
return NULL;
} }
k2->key = key;
k2->value = value;
k = k2;
break;
}
}
}
dict->numkeys++;
} }
if (pl->pos >= pl->end) { // Catch the error if (pl->pos >= pl->end) { // Catch the error
@ -349,12 +402,12 @@ PL_ParsePropertyListItem (pldata_t *pl)
item = calloc (1, sizeof (plitem_t)); item = calloc (1, sizeof (plitem_t));
item->type = QFDictionary; item->type = QFDictionary;
item->data.dict = dict; item->data = dict;
return item; return item;
} }
case '(': { case '(': {
array_t *a = calloc (1, sizeof (array_t)); plarray_t *a = calloc (1, sizeof (plarray_t));
pl->pos++; pl->pos++;
@ -385,7 +438,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
item = calloc (1, sizeof (plitem_t)); item = calloc (1, sizeof (plitem_t));
item->type = QFArray; item->type = QFArray;
item->data.array = a; item->data = a;
return item; return item;
} }
@ -401,7 +454,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
} else { } else {
item = calloc (1, sizeof (plitem_t)); item = calloc (1, sizeof (plitem_t));
item->type = QFString; item->type = QFString;
item->data.string = str; item->data = str;
return item; return item;
} }
} }
@ -414,7 +467,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
} else { } else {
item = calloc (1, sizeof (plitem_t)); item = calloc (1, sizeof (plitem_t));
item->type = QFString; item->type = QFString;
item->data.string = str; item->data = str;
return item; return item;
} }
} }