mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
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:
parent
3a94567913
commit
118645fd51
2 changed files with 118 additions and 64 deletions
|
@ -3,7 +3,7 @@
|
|||
|
||||
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
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
@ -26,60 +26,63 @@
|
|||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __qfplist_h_
|
||||
#define __qfplist_h_
|
||||
#ifndef __QF_qfplist_h_
|
||||
#define __QF_qfplist_h_
|
||||
|
||||
#include <glob.h>
|
||||
|
||||
#include "QF/qtypes.h"
|
||||
|
||||
// Ugly defines for fast checking and conversion from char to number
|
||||
#define inrange(ch,min,max) ((ch) >= (min) && (ch) <= (max))
|
||||
#define char2num(ch) \
|
||||
inrange(ch, '0', '9') ? (ch - 0x30) \
|
||||
: (inrange(ch, 'a', 'f') ? (ch - 0x57) : (ch - 0x37))
|
||||
inrange((ch), '0', '9') ? ((ch) - 0x30) \
|
||||
: (inrange((ch), 'a', 'f') ? ((ch) - 0x57) : ((ch) - 0x37))
|
||||
|
||||
// Maximum number of items in an array
|
||||
#define MAX_ARRAY_INDEX 128
|
||||
|
||||
typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types
|
||||
|
||||
/*
|
||||
Generic property list item
|
||||
*/
|
||||
struct plitem_s {
|
||||
struct plitem_s *next; // Pointer to next item
|
||||
pltype_t type; // Type
|
||||
union shared { // Type-dependant data
|
||||
struct dict_s *dict;
|
||||
struct array_s *array;
|
||||
void *binary;
|
||||
char *string;
|
||||
} data;
|
||||
pltype_t type; // Type
|
||||
void *data;
|
||||
};
|
||||
typedef struct plitem_s plitem_t;
|
||||
|
||||
/*
|
||||
Dictionaries
|
||||
*/
|
||||
struct dict_s {
|
||||
int numkeys; // Number of items in dictionary
|
||||
struct dictkey_s *keys;
|
||||
};
|
||||
|
||||
struct dictkey_s {
|
||||
struct dictkey_s *next;
|
||||
struct plitem_s *key;
|
||||
struct plitem_s *value;
|
||||
char *key;
|
||||
plitem_t *value;
|
||||
};
|
||||
typedef struct dictkey_s dictkey_t;
|
||||
|
||||
/*
|
||||
Arrays
|
||||
*/
|
||||
struct array_s {
|
||||
int numvals; // Number of items in array
|
||||
struct plarray_s {
|
||||
int numvals; // Number of items in array
|
||||
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;
|
||||
typedef struct dict_s dict_t;
|
||||
typedef struct dictkey_s dictkey_t;
|
||||
typedef struct array_s array_t;
|
||||
/*
|
||||
Typeless, unformatted binary data (not supported yet)
|
||||
*/
|
||||
struct plbinary_s {
|
||||
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
|
||||
const char *ptr;
|
||||
|
@ -89,8 +92,6 @@ typedef struct pldata_s { // Unparsed property list string
|
|||
char *error;
|
||||
} pldata_t;
|
||||
|
||||
plitem_t *PL_GetPropertyList (const char *);
|
||||
|
||||
/*
|
||||
Internal prototypes
|
||||
|
||||
|
@ -99,4 +100,4 @@ plitem_t *PL_GetPropertyList (const char *);
|
|||
static char *PL_ParseQuotedString (pldata_t *);
|
||||
static char *PL_ParseUnquotedString (pldata_t *);
|
||||
*/
|
||||
#endif // __qfplist_h_
|
||||
#endif // __QF_qfplist_h_
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
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
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "QF/hash.h"
|
||||
#include "QF/qfplist.h"
|
||||
#include "QF/qtypes.h"
|
||||
|
||||
|
@ -42,6 +43,58 @@ static qboolean PL_SkipSpace (pldata_t *);
|
|||
static char *PL_ParseQuotedString (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
|
||||
PL_SkipSpace (pldata_t *pl)
|
||||
{
|
||||
|
@ -262,7 +315,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
|
||||
switch (pl->ptr[pl->pos]) {
|
||||
case '{': {
|
||||
dict_t *dict = calloc (1, sizeof (dict_t));
|
||||
hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL);
|
||||
|
||||
pl->pos++;
|
||||
|
||||
|
@ -272,12 +325,24 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
|
||||
if (!(key = PL_ParsePropertyListItem (pl)))
|
||||
return NULL;
|
||||
|
||||
if (!(PL_SkipSpace (pl))) {
|
||||
free (key->data);
|
||||
free (key);
|
||||
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] != '=') {
|
||||
pl->error = "Unexpected character (wanted '=')";
|
||||
free (key->data);
|
||||
free (key);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -285,58 +350,46 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
|
||||
// If there is no value, lose the key
|
||||
if (!(value = PL_ParsePropertyListItem (pl))) {
|
||||
free (key->data);
|
||||
free (key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(PL_SkipSpace (pl))) {
|
||||
free (key->data);
|
||||
free (key);
|
||||
free (value->data);
|
||||
free (value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pl->ptr[pl->pos] == ';') {
|
||||
pl->pos++;
|
||||
} else if (pl->ptr[pl->pos] != '}') {
|
||||
pl->error = "Unexpected character (wanted ';' or '}')";
|
||||
free (key->data);
|
||||
free (key);
|
||||
free (value->data);
|
||||
free (value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the key/value pair to the dict
|
||||
if (!(dict->keys)) { // No keys, add one
|
||||
{ // Add the key/value pair to the dictionary
|
||||
dictkey_t *k = calloc (1, sizeof (dictkey_t));
|
||||
|
||||
if (!k) {
|
||||
free (key->data);
|
||||
free (key);
|
||||
free (value->data);
|
||||
free (value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k->key = key;
|
||||
k->key = (char *) key->data;
|
||||
k->value = value;
|
||||
|
||||
dict->keys = 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;
|
||||
}
|
||||
}
|
||||
Hash_Add (dict, k);
|
||||
}
|
||||
dict->numkeys++;
|
||||
}
|
||||
|
||||
if (pl->pos >= pl->end) { // Catch the error
|
||||
|
@ -349,12 +402,12 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
|
||||
item = calloc (1, sizeof (plitem_t));
|
||||
item->type = QFDictionary;
|
||||
item->data.dict = dict;
|
||||
item->data = dict;
|
||||
return item;
|
||||
}
|
||||
|
||||
case '(': {
|
||||
array_t *a = calloc (1, sizeof (array_t));
|
||||
plarray_t *a = calloc (1, sizeof (plarray_t));
|
||||
|
||||
pl->pos++;
|
||||
|
||||
|
@ -385,7 +438,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
|
||||
item = calloc (1, sizeof (plitem_t));
|
||||
item->type = QFArray;
|
||||
item->data.array = a;
|
||||
item->data = a;
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -401,7 +454,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
} else {
|
||||
item = calloc (1, sizeof (plitem_t));
|
||||
item->type = QFString;
|
||||
item->data.string = str;
|
||||
item->data = str;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
@ -414,7 +467,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
} else {
|
||||
item = calloc (1, sizeof (plitem_t));
|
||||
item->type = QFString;
|
||||
item->data.string = str;
|
||||
item->data = str;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue