From 81300f89f8ca473a90840a0dfce5998fe037852d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Jan 2021 14:02:33 +0900 Subject: [PATCH] [util] Allow multiple types for pl fields I want to be able to use name references, but that requires string items, so anything that would normally be dictionary or array (or binary, even) would also need to accept string. This seemed to be the cleanest solution. Any custom parser would then need to check the type and act appropriately, but any inappropriate types have already been pre-filtered by the standard parsers. --- include/QF/qfplist.h | 5 +++- libs/util/qfplist.c | 66 ++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 972f69dc3..20c7671bb 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -44,7 +44,10 @@ typedef enum { QFArray, ///< The property list item represents an array. QFBinary, ///< The property list item represents arbitrary binary ///< data. - QFString ///< The property list item represents a C string. + QFString, ///< The property list item represents a C string. + + QFMultiType = (1 << 31) ///< if bit 31 is set, the type indicates a mask + ///< of allowed types for plfield_t } pltype_t; /** Generic property list item. diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 3e64e3c3e..c3fc5a756 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -227,6 +227,8 @@ PL_Free (plitem_t *item) case QFString: free (item->data); break; + case QFMultiType: + break; } free (item); } @@ -1138,11 +1140,48 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, case QFString: *(char **)data = (char *)item->data; return 1; + case QFMultiType: + break; } PL_Message (messages, 0, "invalid item type: %d", field->type); return 0; } +static int +types_match (pltype_t field_type, pltype_t item_type) +{ + if (field_type & QFMultiType) { + // field_type is a mask of allowed types + return field_type & (1 << item_type); + } else { + // exact match + return field_type == item_type; + } +} + +static void +type_mismatch (plitem_t *messages, const plitem_t *item, const char *name, + pltype_t field_type, pltype_t item_type) +{ + const int num_types = sizeof (pl_types) / sizeof (pl_types[0]); + if (field_type & QFMultiType) { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected on of:", + name, pl_types[item_type]); + field_type &= ~QFMultiType; + for (int type = 0; field_type && type < num_types; + type++, field_type >>= 1) { + if (field_type & 1) { + PL_Message (messages, item, " %s", pl_types[type]); + } + } + } else { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected %s", name, + pl_types[item_type], pl_types[field_type]); + } +} + VISIBLE int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages, void *context) @@ -1174,11 +1213,9 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, } else { parser = pl_default_parser; } - if (item->type != f->type) { - PL_Message (messages, item, "error: %s is the wrong type" - " Got %s, expected %s",current->key, - pl_types[f->type], - pl_types[item->type]); + if (!types_match (f->type, item->type)) { + type_mismatch (messages, item, current->key, + f->type, item->type); result = 0; } else { if (!parser (f, item, flddata, messages, context)) { @@ -1231,12 +1268,11 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *item = plarray->values[i]; void *eledata = &arr->a[i * element->stride]; - if (item->type != element->type) { - PL_Message (messages, item, - "error: element %d is the wrong type" - " Got %s, expected %s", i, - pl_types[element->type], - pl_types[item->type]); + if (!types_match (element->type, item->type)) { + char index[16]; + snprintf (index, sizeof(index) - 1, "%d", i); + index[15] = 0; + type_mismatch (messages, item, index, element->type, item->type); result = 0; } else { if (!parser (&f, item, eledata, messages, context)) { @@ -1284,12 +1320,8 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, const char *key = current->key; plitem_t *item = current->value; - if (item->type != element->type) { - PL_Message (messages, item, - "error: element %s is the wrong type" - " Got %s, expected %s", key, - pl_types[element->type], - pl_types[item->type]); + if (!types_match (element->type, item->type)) { + type_mismatch (messages, item, key, element->type, item->type); result = 0; continue; }