[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. \return Returns an object equivalent to the passed-in string.
\note You are responsible for freeing the returned object. \note You are responsible for freeing the returned object.
*/ */
plitem_t *PL_GetPropertyList (const char *string, plitem_t *PL_GetPropertyList (const char *string, struct hashctx_s **hashctx);
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. /** 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 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)); QFile *file = QFile_GetFile (pr, P_INT (pr, 0));
plitem_t *plitem; plitem_t *plitem;
long offset; long offset;
@ -205,19 +205,61 @@ bi_PL_GetFromFile (progs_t *pr, void *_res)
Qread (file, buf, len); Qread (file, buf, len);
buf[len] = 0; buf[len] = 0;
plitem = PL_GetPropertyList (buf, pr->hashctx); plitem = get (buf, pr->hashctx);
free (buf); free (buf);
R_INT (pr) = plist_retain (res, plitem); 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 static void
bi_PL_GetPropertyList (progs_t *pr, void *_res) bi_PL_GetPropertyList (progs_t *pr, void *_res)
{ {
plist_resources_t *res = _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 static void
@ -481,6 +523,10 @@ plist_compare (const void *k1, const void *k2, void *unused)
static builtin_t builtins[] = { static builtin_t builtins[] = {
bi(PL_GetFromFile, 1, p(ptr)), bi(PL_GetFromFile, 1, p(ptr)),
bi(PL_GetPropertyList, 1, p(string)), 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_WritePropertyList, 1, p(ptr)),
bi(PL_Type, 1, p(ptr)), bi(PL_Type, 1, p(ptr)),
bi(PL_Line, 1, p(ptr)), bi(PL_Line, 1, p(ptr)),

View file

@ -936,8 +936,9 @@ pl_parsepropertylistitem (pldata_t *pl)
} }
} }
VISIBLE plitem_t * static plitem_t *
PL_GetPropertyList (const char *string, hashctx_t **hashctx) pl_parseitem (const char *string, hashctx_t **hashctx,
plitem_t *(*parse) (pldata_t *))
{ {
plitem_t *newpl = NULL; plitem_t *newpl = NULL;
@ -951,7 +952,7 @@ PL_GetPropertyList (const char *string, hashctx_t **hashctx)
.hashctx = hashctx, .hashctx = hashctx,
}; };
if (!(newpl = pl_parsepropertylistitem (&pl))) { if (!(newpl = parse (&pl))) {
if (pl.errmsg) { if (pl.errmsg) {
Sys_Printf ("plist: %d,%d: %s\n", pl.line, pl.pos - pl.line_start, Sys_Printf ("plist: %d,%d: %s\n", pl.line, pl.pos - pl.line_start,
pl.errmsg->str); pl.errmsg->str);
@ -962,6 +963,57 @@ PL_GetPropertyList (const char *string, hashctx_t **hashctx)
return newpl; 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 static void
write_tabs (dstring_t *dstr, int num) write_tabs (dstring_t *dstr, int num)
{ {

View file

@ -700,18 +700,14 @@ qfs_load_config (void)
goto no_config; goto no_config;
len = Qfilesize (f); 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); Qclose (f);
// convert the config file to a plist dictionary
buf[0] = '{';
buf[len + 1] = '}';
buf[len + 2] = 0;
if (qfs_gd_plist) if (qfs_gd_plist)
PL_Free (qfs_gd_plist); PL_Free (qfs_gd_plist);
qfs_gd_plist = PL_GetPropertyList (buf, 0); qfs_gd_plist = PL_GetDictionary (buf, 0);
free (buf); free (buf);
if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary) if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary)
return; // done return; // done