[plist] Add parsing for bare dictionaries and arrays

Requiring top-level {} or () for (usually) hand-written files is awkward
and even a little error prone, and certainly ugly at times. With this,
loaders that expect a particular format can specify the format a little
more directly.
This commit is contained in:
Bill Currie 2023-03-12 14:31:17 +09:00
parent e57a06f37b
commit ea77df2daa
4 changed files with 137 additions and 17 deletions

View file

@ -143,8 +143,34 @@ typedef struct plelement_s {
\return Returns an object equivalent to the passed-in string.
\note You are responsible for freeing the returned object.
*/
plitem_t *PL_GetPropertyList (const char *string,
struct hashctx_s **hashctx);
plitem_t *PL_GetPropertyList (const char *string, struct hashctx_s **hashctx);
/** Create a property list from a bare dictionary list.
The input is treated as a list of dictionary key-value pairs without the
enclosing { or }.
\param string dicitionary list string.
\param hashctx Hashlink chain to use when creating dictionaries (see
Hash_NewTable()). May be null.
\return Returns a dictionary object.
\note You are responsible for freeing the returned object.
*/
plitem_t *PL_GetDictionary (const char *string, struct hashctx_s **hashctx);
/** Create a property list from a bare array list.
The input is treated as a list of array values without the enclosing ( or ).
\param string array list string.
\param hashctx Hashlink chain to use when creating dictionaries (see
Hash_NewTable()). May be null.
\return Returns an array object.
\note You are responsible for freeing the returned object.
*/
plitem_t *PL_GetArray (const char *string, struct hashctx_s **hashctx);
/** Create a property list string from the in-memory representation.

View file

@ -188,9 +188,9 @@ plist_retain (plist_resources_t *res, plitem_t *plitem)
}
static void
bi_PL_GetFromFile (progs_t *pr, void *_res)
bi_pl_getfromfile (progs_t *pr, plist_resources_t *res,
plitem_t *get (const char *, struct hashctx_s **))
{
plist_resources_t *res = _res;
QFile *file = QFile_GetFile (pr, P_INT (pr, 0));
plitem_t *plitem;
long offset;
@ -205,19 +205,61 @@ bi_PL_GetFromFile (progs_t *pr, void *_res)
Qread (file, buf, len);
buf[len] = 0;
plitem = PL_GetPropertyList (buf, pr->hashctx);
plitem = get (buf, pr->hashctx);
free (buf);
R_INT (pr) = plist_retain (res, plitem);
}
static void
bi_pl_get (progs_t *pr, plist_resources_t *res,
plitem_t *get (const char *, struct hashctx_s **))
{
plitem_t *plitem = get (P_GSTRING (pr, 0), pr->hashctx);
R_INT (pr) = plist_retain (res, plitem);
}
static void
bi_PL_GetFromFile (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
bi_pl_getfromfile (pr, res, PL_GetPropertyList);
}
static void
bi_PL_GetPropertyList (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0), pr->hashctx);
bi_pl_get (pr, res, PL_GetPropertyList);
}
R_INT (pr) = plist_retain (res, plitem);
static void
bi_PL_GetDictionaryFromFile (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
bi_pl_getfromfile (pr, res, PL_GetDictionary);
}
static void
bi_PL_GetDictionary (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
bi_pl_get (pr, res, PL_GetDictionary);
}
static void
bi_PL_GetArrayFromFile (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
bi_pl_getfromfile (pr, res, PL_GetArray);
}
static void
bi_PL_GetArray (progs_t *pr, void *_res)
{
plist_resources_t *res = _res;
bi_pl_get (pr, res, PL_GetArray);
}
static void
@ -481,6 +523,10 @@ plist_compare (const void *k1, const void *k2, void *unused)
static builtin_t builtins[] = {
bi(PL_GetFromFile, 1, p(ptr)),
bi(PL_GetPropertyList, 1, p(string)),
bi(PL_GetDictionary, 1, p(string)),
bi(PL_GetDictionaryFromFile, 1, p(string)),
bi(PL_GetArray, 1, p(string)),
bi(PL_GetArrayFromFile, 1, p(string)),
bi(PL_WritePropertyList, 1, p(ptr)),
bi(PL_Type, 1, p(ptr)),
bi(PL_Line, 1, p(ptr)),

View file

@ -936,8 +936,9 @@ pl_parsepropertylistitem (pldata_t *pl)
}
}
VISIBLE plitem_t *
PL_GetPropertyList (const char *string, hashctx_t **hashctx)
static plitem_t *
pl_parseitem (const char *string, hashctx_t **hashctx,
plitem_t *(*parse) (pldata_t *))
{
plitem_t *newpl = NULL;
@ -951,7 +952,7 @@ PL_GetPropertyList (const char *string, hashctx_t **hashctx)
.hashctx = hashctx,
};
if (!(newpl = pl_parsepropertylistitem (&pl))) {
if (!(newpl = parse (&pl))) {
if (pl.errmsg) {
Sys_Printf ("plist: %d,%d: %s\n", pl.line, pl.pos - pl.line_start,
pl.errmsg->str);
@ -962,6 +963,57 @@ PL_GetPropertyList (const char *string, hashctx_t **hashctx)
return newpl;
}
VISIBLE plitem_t *
PL_GetPropertyList (const char *string, hashctx_t **hashctx)
{
return pl_parseitem (string, hashctx, pl_parsepropertylistitem);
}
static plitem_t *
pl_getdictionary (pldata_t *pl)
{
plitem_t *dict = PL_NewDictionary (pl->hashctx);
dict->line = pl->line;
while (pl_skipspace (pl, 1)) {
if (!pl_parsekeyvalue (pl, dict, 1)) {
PL_Free (dict);
return NULL;
}
}
return dict;
}
VISIBLE plitem_t *
PL_GetDictionary (const char *string, hashctx_t **hashctx)
{
return pl_parseitem (string, hashctx, pl_getdictionary);
}
static plitem_t *
pl_getarray (pldata_t *pl)
{
plitem_t *array = PL_NewArray ();
array->line = pl->line;
while (pl_skipspace (pl, 1)) {
if (!pl_parsevalue (pl, array, 1)) {
PL_Free (array);
return NULL;
}
}
return array;
}
VISIBLE plitem_t *
PL_GetArray (const char *string, hashctx_t **hashctx)
{
return pl_parseitem (string, hashctx, pl_getarray);
}
static void
write_tabs (dstring_t *dstr, int num)
{

View file

@ -700,18 +700,14 @@ qfs_load_config (void)
goto no_config;
len = Qfilesize (f);
buf = malloc (len + 3); // +3 for { } and \0
buf = malloc (len + 1); // +1 for nul
Qread (f, buf + 1, len);
Qread (f, buf, len);
Qclose (f);
// convert the config file to a plist dictionary
buf[0] = '{';
buf[len + 1] = '}';
buf[len + 2] = 0;
if (qfs_gd_plist)
PL_Free (qfs_gd_plist);
qfs_gd_plist = PL_GetPropertyList (buf, 0);
qfs_gd_plist = PL_GetDictionary (buf, 0);
free (buf);
if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary)
return; // done