fontconfig/fontconfig-hotfix.patch
Akira TAGOH cec02510f8 cherry pick some upstream patches
Skip leading white space in style.
  Remove abort from FcCompareSize.
  Fix memory leaks
  Check qual and compare for family tests.
-
2020-12-23 22:12:12 +09:00

773 lines
23 KiB
Diff

From 93c93689f5da4ceaa675e006df63283e25b91d49 Mon Sep 17 00:00:00 2001
From: Akira TAGOH <akira@tagoh.org>
Date: Fri, 4 Dec 2020 18:18:03 +0900
Subject: [PATCH 01/12] Add back fullname property at scan matching phase
There seems to be a lot of config files using fullname property in the world.
To keep the backward compatibility, fullname property is back to a cache at
the scan matching phase but will be rebuilt once it is done according to family
and style property in the pattern no matter what changes one made in fullname
property during that.
Ref. https://bugzilla.redhat.com/show_bug.cgi?id=1902881
---
src/fcfreetype.c | 21 ++++++++++++++++++++-
src/fcopentype.c | 2 ++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
index a7809cb..4b545bf 100644
--- a/src/fcfreetype.c
+++ b/src/fcfreetype.c
@@ -1087,6 +1087,8 @@ static const FT_UShort nameid_order[] = {
TT_NAME_ID_WWS_FAMILY,
TT_NAME_ID_TYPOGRAPHIC_FAMILY,
TT_NAME_ID_FONT_FAMILY,
+ TT_NAME_ID_MAC_FULL_NAME,
+ TT_NAME_ID_FULL_NAME,
TT_NAME_ID_WWS_SUBFAMILY,
TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
TT_NAME_ID_FONT_SUBFAMILY,
@@ -1222,6 +1224,8 @@ FcFreeTypeQueryFaceInternal (const FT_Face face,
int nfamily_lang = 0;
int nstyle = 0;
int nstyle_lang = 0;
+ int nfullname = 0;
+ int nfullname_lang = 0;
unsigned int p, n;
FcChar8 *style = 0;
@@ -1443,7 +1447,8 @@ FcFreeTypeQueryFaceInternal (const FT_Face face,
* and treat the instance's nameid as FONT_SUBFAMILY.
* Postscript name is automatically handled by FreeType. */
if (nameid == TT_NAME_ID_WWS_SUBFAMILY ||
- nameid == TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY)
+ nameid == TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY ||
+ nameid == TT_NAME_ID_FULL_NAME)
continue;
if (nameid == TT_NAME_ID_FONT_SUBFAMILY)
@@ -1474,6 +1479,20 @@ FcFreeTypeQueryFaceInternal (const FT_Face face,
np = &nfamily;
nlangp = &nfamily_lang;
break;
+ case TT_NAME_ID_MAC_FULL_NAME:
+ case TT_NAME_ID_FULL_NAME:
+ if (variable)
+ break;
+ if (FcDebug () & FC_DBG_SCANV)
+ printf ("found full (n %2d p %d e %d l 0x%04x)",
+ sname.name_id, sname.platform_id,
+ sname.encoding_id, sname.language_id);
+
+ obj = FC_FULLNAME_OBJECT;
+ objlang = FC_FULLNAMELANG_OBJECT;
+ np = &nfullname;
+ nlangp = &nfullname_lang;
+ break;
case TT_NAME_ID_WWS_SUBFAMILY:
case TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY:
case TT_NAME_ID_FONT_SUBFAMILY:
diff --git a/src/fcopentype.c b/src/fcopentype.c
index 9382a1b..59cce45 100644
--- a/src/fcopentype.c
+++ b/src/fcopentype.c
@@ -76,12 +76,14 @@ FcPatternAddFullname (FcPattern *pat)
FcStrBufChar (&sbuf, ' ');
FcStrBufString (&sbuf, style);
}
+ FcPatternObjectDel (pat, FC_FULLNAME_OBJECT);
if (!FcPatternObjectAddString (pat, FC_FULLNAME_OBJECT, FcStrBufDoneStatic (&sbuf)))
{
FcStrBufDestroy (&sbuf);
return FcFalse;
}
FcStrBufDestroy (&sbuf);
+ FcPatternObjectDel (pat, FC_FULLNAMELANG_OBJECT);
if (!FcPatternObjectAddString (pat, FC_FULLNAMELANG_OBJECT, (const FcChar8 *) "en"))
return FcFalse;
}
--
2.29.2
From 3d6926380dc3c8597dc2fd9d34087da9b39dfdd9 Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Fri, 4 Dec 2020 15:00:08 -0500
Subject: [PATCH 02/12] Skip leading whitespace in style name.
Found by Clang-Tidy. The intent seems to have been to skip all leading
whitespace in the 'style' string, but instead this loop was an odd
looking no-op. Remove the 'break' from the loop so that it will
continue until end of string or a non-space character is found.
---
src/fcopentype.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/fcopentype.c b/src/fcopentype.c
index 59cce45..39c05e9 100644
--- a/src/fcopentype.c
+++ b/src/fcopentype.c
@@ -66,8 +66,7 @@ FcPatternAddFullname (FcPattern *pat)
if (FcPatternObjectGetString (pat, FC_STYLE_OBJECT, n, &style) != FcResultMatch)
return FcFalse;
len = strlen ((const char *) style);
- for (i = 0; style[i] != 0 && isspace (style[i]); i++)
- break;
+ for (i = 0; style[i] != 0 && isspace (style[i]); i++);
memcpy (style, &style[i], len - i);
FcStrBufInit (&sbuf, NULL, 0);
FcStrBufString (&sbuf, family);
--
2.29.2
From 97d541855429629f40a0accdd2b06b7dce7ba2db Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Fri, 4 Dec 2020 15:42:28 -0500
Subject: [PATCH 03/12] Remove abort from FcCompareSize.
There doesn't appear to be a good reason to abort when 'v1' has type
FcTypeRange. If there does turn out to be a good reason for this then it
should be better documented and the code for handling this case removed.
At worst it seems -1 should be returned as it is for other unknown
types. It is possible this is left over debug code from the initial
implementation.
---
src/fcmatch.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/fcmatch.c b/src/fcmatch.c
index df6db71..53c3b0e 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -235,7 +235,6 @@ FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
b1 = e1 = value1.u.d;
break;
case FcTypeRange:
- abort();
b1 = value1.u.r->begin;
e1 = value1.u.r->end;
break;
--
2.29.2
From d55eaa6b3148691f32ec19c5c36dfc8818a6385f Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Fri, 11 Dec 2020 11:54:43 -0500
Subject: [PATCH 07/12] Fix leaks in fcxml.c, fc-match.c, and tests.
Fix leaks reported by AddressSanitizer when running 'make check'.
---
fc-match/fc-match.c | 8 +++++++-
src/fcxml.c | 4 +++-
test/test-bz106632.c | 8 ++++++++
test/test-issue180.c | 4 +++-
4 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/fc-match/fc-match.c b/fc-match/fc-match.c
index 4362ec1..f31047e 100644
--- a/fc-match/fc-match.c
+++ b/fc-match/fc-match.c
@@ -117,6 +117,7 @@ main (int argc, char **argv)
int brief = 0;
int sort = 0, all = 0;
const FcChar8 *format = NULL;
+ const FcChar8 *format_optarg = NULL;
int i;
FcObjectSet *os = 0;
FcFontSet *fs;
@@ -146,7 +147,7 @@ main (int argc, char **argv)
brief = 1;
break;
case 'f':
- format = (FcChar8 *) strdup (optarg);
+ format = format_optarg = (FcChar8 *) strdup (optarg);
break;
case 'V':
fprintf (stderr, "fontconfig version %d.%d.%d\n",
@@ -269,5 +270,10 @@ main (int argc, char **argv)
FcFini ();
+ if (format_optarg) {
+ free ((void*)format_optarg);
+ format_optarg = NULL;
+ }
+
return 0;
}
diff --git a/src/fcxml.c b/src/fcxml.c
index 3f22581..9efe157 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -2307,7 +2307,9 @@ FcParseCacheDir (FcConfigParse *parse)
if (data[0] == 0)
{
FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
- return;
+ FcStrFree (data);
+ data = prefix;
+ goto bail;
}
if (prefix)
{
diff --git a/test/test-bz106632.c b/test/test-bz106632.c
index 0f37b9c..c610d73 100644
--- a/test/test-bz106632.c
+++ b/test/test-bz106632.c
@@ -221,6 +221,7 @@ main (void)
ret = 1;
goto bail;
}
+ FcFontSetDestroy (fs);
fprintf (stderr, "D: Removing %s\n", fontdir);
snprintf (cmd, 512, "sleep 1; rm -f %s%s*; sleep 1", fontdir, FC_DIR_SEPARATOR_S);
(void) system (cmd);
@@ -243,6 +244,8 @@ main (void)
ret = 3;
goto bail;
}
+ FcConfigDestroy (config);
+
config = FcConfigCreate ();
if (!FcConfigParseAndLoadFromMemory (config, (const FcChar8 *) conf, FcTrue))
{
@@ -266,6 +269,7 @@ main (void)
ret = 1;
goto bail;
}
+ FcFontSetDestroy (fs);
fprintf (stderr, "D: Copying %s to %s\n", FONTFILE, fontdir);
snprintf (cmd, 512, "sleep 1; cp -a %s %s; sleep 1", FONTFILE, fontdir);
(void) system (cmd);
@@ -288,6 +292,8 @@ main (void)
ret = 3;
goto bail;
}
+ FcConfigDestroy (config);
+
config = FcConfigCreate ();
if (!FcConfigParseAndLoadFromMemory (config, (const FcChar8 *) conf, FcTrue))
{
@@ -311,6 +317,8 @@ main (void)
ret = 1;
goto bail;
}
+ FcFontSetDestroy (fs);
+ FcConfigDestroy (config);
bail:
fprintf (stderr, "Cleaning up\n");
diff --git a/test/test-issue180.c b/test/test-issue180.c
index 2832d3b..9d0795e 100644
--- a/test/test-issue180.c
+++ b/test/test-issue180.c
@@ -53,7 +53,9 @@ main (void)
fprintf (stderr, "There was one or more cachedirs\n");
return 1;
}
+ FcStrListDone (l);
FcConfigDestroy (cfg);
+
cfg = FcConfigCreate ();
if (!FcConfigParseAndLoadFromMemory (cfg, doc2, FcTrue))
{
@@ -66,7 +68,7 @@ main (void)
fprintf (stderr, "There was one or more cachedirs (with prefix)\n");
return 1;
}
-
+ FcStrListDone (l);
FcConfigDestroy (cfg);
return 0;
--
2.29.2
From 5cd11d19dfb2d901e1f6b690ae504d3bf5f5ff69 Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Thu, 10 Dec 2020 14:12:05 -0500
Subject: [PATCH 08/12] Fix wild frees and leak of fs in test-conf.
Reported by AddressSanitizer when running test-conf. The `query`,
`result`, and `result_fs` were not initialized to NULL so could result
in a wild free when first initialized.
The `method` was also not initialized to NULL so comparisons could be
made against random data if it had not yet been assigned.
The outer `fs` was never destroyed, but is also not used, so remove.
---
test/test-conf.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/test/test-conf.c b/test/test-conf.c
index d4de21a..6097983 100644
--- a/test/test-conf.c
+++ b/test/test-conf.c
@@ -158,7 +158,6 @@ static FcBool
run_test (FcConfig *config, json_object *root)
{
json_object *tests;
- FcFontSet *fs;
int i, n, fail = 0;
if (!json_object_object_get_ex (root, "tests", &tests) ||
@@ -167,15 +166,15 @@ run_test (FcConfig *config, json_object *root)
fprintf (stderr, "W: No test cases defined\n");
return FcFalse;
}
- fs = FcFontSetCreate ();
n = json_object_array_length (tests);
for (i = 0; i < n; i++)
{
json_object *obj = json_object_array_get_idx (tests, i);
json_object_iter iter;
- FcPattern *query, *result;
- FcFontSet *result_fs;
- const char *method;
+ FcPattern *query = NULL;
+ FcPattern *result = NULL;
+ FcFontSet *result_fs = NULL;
+ const char *method = NULL;
if (json_object_get_type (obj) != json_type_object)
continue;
--
2.29.2
From b35c72dbc7da5b61a84766cfa431c95c1d1b35bd Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Tue, 15 Dec 2020 17:39:05 -0500
Subject: [PATCH 09/12] Always run-test-conf, but skip if not built.
The test-conf test requires libjson-c to be available in order to be
built. However, there has been no user indication that additional tests
could be built if the json-c development files were available.
Continue to not build test-conf if json-c is not available, but do run
the test harness. The test harness is updated to SKIP the test if the
test-conf binary is unavailable.
---
test/Makefile.am | 2 +-
test/run-test-conf.sh | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/test/Makefile.am b/test/Makefile.am
index 5a998b3..1a9b293 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -101,8 +101,8 @@ if ENABLE_JSONC
check_PROGRAMS += test-conf
test_conf_CFLAGS = $(JSONC_CFLAGS)
test_conf_LDADD = $(top_builddir)/src/libfontconfig.la $(JSONC_LIBS)
-TESTS += run-test-conf.sh
endif
+TESTS += run-test-conf.sh
check_PROGRAMS += test-bz106618
test_bz106618_LDADD = $(top_builddir)/src/libfontconfig.la
diff --git a/test/run-test-conf.sh b/test/run-test-conf.sh
index 437bafa..e085e82 100644
--- a/test/run-test-conf.sh
+++ b/test/run-test-conf.sh
@@ -33,6 +33,12 @@ BUILDTESTDIR=${builddir-"$MyPWD"}
RUNNER=../test/test-conf$EXEEXT
+if [ ! -f ${RUNNER} ]; then
+ echo "${RUNNER} not found!\n"
+ echo "Building this test requires libjson-c development files to be available."
+ exit 77 # SKIP
+fi
+
for i in \
60-generic.conf \
90-synthetic.conf \
--
2.29.2
From 921ede9f460fb661146182809557a1da2dd7afd7 Mon Sep 17 00:00:00 2001
From: Ben Wagner <bungeman@chromium.org>
Date: Tue, 15 Dec 2020 16:30:14 -0500
Subject: [PATCH 10/12] Fix test-conf string to integer conversion.
The test-conf build_pattern attempted to convert known constant strings
into integer values. However, it did so by always converting the string
value to an integer if possible and then complaining if the key wasn't
of the expected type. This lead to error messages on "style": "Regular"
since "Regular" was recognized as "weight".
Instead, only attempt conversion from string to integer if the key is
the name of an object which can take an integer type. This eliminates
the spurious non-fatal errors reported when parsing
test-90-synthetic.json.
This also fixes an issue where the created value was given the type of
the object found, but the integer field was assigned. Instead, check
that the object type can take an integer and always set the value type
to integer.
---
test/test-conf.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/test/test-conf.c b/test/test-conf.c
index 6097983..288bb5b 100644
--- a/test/test-conf.c
+++ b/test/test-conf.c
@@ -69,22 +69,25 @@ build_pattern (json_object *obj)
}
else if (json_object_get_type (iter.val) == json_type_string)
{
- const FcConstant *c = FcNameGetConstant ((const FcChar8 *) json_object_get_string (iter.val));
- FcBool b;
-
- if (c)
+ const FcObjectType *o = FcNameGetObjectType (iter.key);
+ if (o && (o->type == FcTypeRange || o->type == FcTypeDouble || o->type == FcTypeInteger))
{
- const FcObjectType *o;
-
+ const FcConstant *c = FcNameGetConstant ((const FcChar8 *) json_object_get_string (iter.val));
+ if (!c) {
+ fprintf (stderr, "E: value is not a known constant\n");
+ fprintf (stderr, " key: %s\n", iter.key);
+ fprintf (stderr, " val: %s\n", json_object_get_string (iter.val));
+ continue;
+ }
if (strcmp (c->object, iter.key) != 0)
{
- fprintf (stderr, "E: invalid object type for const\n");
- fprintf (stderr, " actual result: %s\n", iter.key);
- fprintf (stderr, " expected result: %s\n", c->object);
+ fprintf (stderr, "E: value is a constant of different object\n");
+ fprintf (stderr, " key: %s\n", iter.key);
+ fprintf (stderr, " val: %s\n", json_object_get_string (iter.val));
+ fprintf (stderr, " key implied by value: %s\n", c->object);
continue;
}
- o = FcNameGetObjectType (c->object);
- v.type = o->type;
+ v.type = FcTypeInteger;
v.u.i = c->value;
}
else if (strcmp (json_object_get_string (iter.val), "DontCare") == 0)
--
2.29.2
From df29933e1a06b7aa7af229bd7cd03c62d957f15f Mon Sep 17 00:00:00 2001
From: Szunti <Szunti@users.noreply.github.com>
Date: Sun, 6 Dec 2020 12:52:44 +0100
Subject: [PATCH 11/12] Check qual and compare for family tests
Fixes #267. Hash table lookups assumed qual="any" compare="eq".
Add a test too.
---
src/fccfg.c | 16 ++-
test/Makefile.am | 4 +
test/meson.build | 1 +
test/test-family-matching.c | 228 ++++++++++++++++++++++++++++++++++++
4 files changed, 248 insertions(+), 1 deletion(-)
create mode 100644 test/test-family-matching.c
diff --git a/src/fccfg.c b/src/fccfg.c
index 7b857bf..00a94e5 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -1714,6 +1714,7 @@ FcConfigMatchValueList (FcPattern *p,
FcExpr *e = t->expr;
FcValue value;
FcValueList *v;
+ FcOp op;
while (e)
{
@@ -1731,10 +1732,23 @@ FcConfigMatchValueList (FcPattern *p,
if (t->object == FC_FAMILY_OBJECT && table)
{
- if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
+ op = FC_OP_GET_OP (t->op);
+ if (op == FcOpEqual || op == FcOpListing)
{
+ if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
+ {
ret = 0;
goto done;
+ }
+ }
+ if (op == FcOpNotEqual && t->qual == FcQualAll)
+ {
+ ret = 0;
+ if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
+ {
+ ret = values;
+ }
+ goto done;
}
}
for (v = values; v; v = FcValueListNext(v))
diff --git a/test/Makefile.am b/test/Makefile.am
index 1a9b293..30d8c2a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -167,6 +167,10 @@ check_PROGRAMS += test-issue180
test_issue180_LDADD = $(top_builddir)/src/libfontconfig.la
TESTS += test-issue180
+check_PROGRAMS += test-family-matching
+test_family_matching_LDADD = $(top_builddir)/src/libfontconfig.la
+TESTS += test-family-matching
+
EXTRA_DIST=run-test.sh run-test-conf.sh $(LOG_COMPILER) $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names
CLEANFILES = \
diff --git a/test/meson.build b/test/meson.build
index 96b30a9..59de427 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -6,6 +6,7 @@ tests = [
['test-bz106618.c'],
['test-bz1744377.c'],
['test-issue180.c'],
+ ['test-family-matching.c'],
]
if host_machine.system() != 'windows'
diff --git a/test/test-family-matching.c b/test/test-family-matching.c
new file mode 100644
index 0000000..9fab36c
--- /dev/null
+++ b/test/test-family-matching.c
@@ -0,0 +1,228 @@
+/*
+ * fontconfig/test/test-family-matching.c
+ *
+ * Copyright © 2020 Zoltan Vandrus
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. The authors make no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fontconfig/fontconfig.h>
+
+#define FC_TEST_RESULT "testresult"
+
+typedef enum _TestMatchResult {
+ TestMatch,
+ TestNoMatch,
+ TestMatchError
+} TestMatchResult;
+
+typedef enum _TestResult {
+ TestPassed,
+ TestFailed,
+ TestError
+} TestResult;
+
+static TestMatchResult
+TestMatchPattern (const char *test, FcPattern *p)
+{
+ const FcChar8 *xml_pre = (const FcChar8 *) ""
+ "<fontconfig>\n"
+ " <match>\n"
+ "";
+
+ const FcChar8 *xml_post = (const FcChar8 *) ""
+ " <edit name=\""FC_TEST_RESULT"\">\n"
+ " <bool>true</bool>\n"
+ " </edit>\n"
+ " </match>\n"
+ "</fontconfig>\n"
+ "";
+
+ FcChar8 *xml, *concat;
+ FcConfig *cfg;
+ FcResult result;
+ FcBool dummy;
+ TestResult ret = TestMatchError;
+
+ FcPattern *pat = FcPatternDuplicate (p);
+ if (!pat)
+ {
+ fprintf (stderr, "Unable to duplicate pattern.\n");
+ goto bail0;
+ }
+
+ concat = FcStrPlus (xml_pre, (const FcChar8 *) test);
+ if (!concat)
+ {
+ fprintf (stderr, "Concatenation failed.\n");
+ goto bail0;
+ }
+
+ xml = FcStrPlus (concat, xml_post);
+ FcStrFree (concat);
+ if (!xml)
+ {
+ fprintf (stderr, "Concatenation failed.\n");
+ goto bail0;
+ }
+
+ cfg = FcConfigCreate ();
+ if (!cfg)
+ {
+ fprintf (stderr, "Unable to create a new empty config.\n");
+ return TestMatchError;
+ }
+
+ if (!FcConfigParseAndLoadFromMemory (cfg, xml, FcTrue))
+ {
+ fprintf (stderr, "Unable to load a config from memory.\n");
+ goto bail1;
+ }
+
+ if (!FcConfigSubstitute (cfg, pat, FcMatchPattern))
+ {
+ fprintf (stderr, "Unable to substitute config.\n");
+ goto bail1;
+ }
+
+ result = FcPatternGetBool (pat, FC_TEST_RESULT, 0, &dummy);
+ switch (result) {
+ case FcResultMatch:
+ ret = TestMatch;
+ break;
+ case FcResultNoMatch:
+ ret = TestNoMatch;
+ break;
+ default:
+ fprintf (stderr, "Unable to check pattern.\n");
+ break;
+ }
+
+bail1:
+ FcConfigDestroy (cfg);
+bail0:
+ FcPatternDestroy (pat);
+ return ret;
+}
+
+static TestResult
+TestShouldMatchPattern(const char* test, FcPattern *pat, int negate)
+{
+ switch (TestMatchPattern (test, pat)) {
+ case TestMatch:
+ if (!negate) {
+ return TestPassed;
+ }
+ else
+ {
+ printf ("Following test unexpectedly matched:\n%s", test);
+ printf ("on\n");
+ FcPatternPrint (pat);
+ return TestFailed;
+ }
+ break;
+ case TestNoMatch:
+ if (!negate) {
+ printf ("Following test should have matched:\n%s", test);
+ printf ("on\n");
+ FcPatternPrint (pat);
+ return TestFailed;
+ }
+ else
+ {
+ return TestPassed;
+ }
+ break;
+ case TestMatchError:
+ return TestError;
+ break;
+ default:
+ fprintf (stderr, "This shouldn't have been reached.\n");
+ return TestError;
+ }
+}
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+static TestResult
+UpdateResult (TestResult* res, TestResult resNew)
+{
+ *res = MAX(*res, resNew);
+ return *res;
+}
+
+static TestResult
+TestFamily (void)
+{
+ const char *test;
+ TestResult res = TestPassed;
+
+ FcPattern *pat = FcPatternBuild (NULL,
+ FC_FAMILY, FcTypeString, "family1",
+ FC_FAMILY, FcTypeString, "family2",
+ FC_FAMILY, FcTypeString, "family3",
+ NULL);
+
+ if (!pat)
+ {
+ fprintf (stderr, "Unable to build pattern.\n");
+ return TestError;
+ }
+
+ #define SHOULD_MATCH(p,t) \
+ UpdateResult (&res, TestShouldMatchPattern (t, p, 0))
+ #define SHOULD_NOT_MATCH(p,t) \
+ UpdateResult (&res, TestShouldMatchPattern (t, p, 1))
+
+ test = "<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n"
+ " <string>foo</string>\n"
+ "</test>\n"
+ "";
+ SHOULD_MATCH(pat, test);
+
+ test = ""
+ "<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n"
+ " <string>family2</string>\n"
+ "</test>\n"
+ "";
+ SHOULD_NOT_MATCH(pat, test);
+
+ test = ""
+ "<test qual=\"any\" name=\"family\" compare=\"eq\">\n"
+ " <string>family3</string>\n"
+ "</test>\n"
+ "";
+ SHOULD_MATCH(pat, test);
+
+ test = ""
+ "<test qual=\"any\" name=\"family\" compare=\"eq\">\n"
+ " <string>foo</string>\n"
+ "</test>\n"
+ "";
+ SHOULD_NOT_MATCH(pat, test);
+
+ return res;
+}
+
+int
+main (void)
+{
+ return (TestFamily ());
+}
--
2.29.2