2 * fontconfig/src/fcxml.c
4 * Copyright © 2002 Keith Packard
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
33 #include <libxml/parser.h>
35 #define XML_Char xmlChar
36 #define XML_Parser xmlParserCtxtPtr
37 #define XML_ParserFree xmlFreeParserCtxt
38 #define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
39 #define XML_GetErrorCode xmlCtxtGetLastError
40 #define XML_ErrorString(Error) (Error)->message
42 #else /* ENABLE_LIBXML2 */
44 #ifndef HAVE_XMLPARSE_H
45 #define HAVE_XMLPARSE_H 0
54 #endif /* ENABLE_LIBXML2 */
58 extern FcChar8 fontconfig_instprefix[];
61 static FcChar8 *__fc_userdir = NULL;
62 static FcChar8 *__fc_userconf = NULL;
65 FcExprDestroy (FcExpr *e);
67 _FcConfigParse (FcConfig *config,
73 FcTestDestroy (FcTest *test)
75 FcExprDestroy (test->expr);
80 FcRuleDestroy (FcRule *rule)
82 FcRule *n = rule->next;
86 FcTestDestroy (rule->u.test);
89 FcEditDestroy (rule->u.edit);
101 FcExprCreateInteger (FcConfig *config, int i)
103 FcExpr *e = FcConfigAllocExpr (config);
113 FcExprCreateDouble (FcConfig *config, double d)
115 FcExpr *e = FcConfigAllocExpr (config);
125 FcExprCreateString (FcConfig *config, const FcChar8 *s)
127 FcExpr *e = FcConfigAllocExpr (config);
131 e->u.sval = FcStrdup (s);
136 static FcExprMatrix *
137 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
139 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
148 FcExprMatrixFreeShallow (FcExprMatrix *m)
157 FcExprMatrixFree (FcExprMatrix *m)
162 FcExprDestroy (m->xx);
163 FcExprDestroy (m->xy);
164 FcExprDestroy (m->yx);
165 FcExprDestroy (m->yy);
171 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
173 FcExpr *e = FcConfigAllocExpr (config);
177 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
183 FcExprCreateRange (FcConfig *config, FcRange *range)
185 FcExpr *e = FcConfigAllocExpr (config);
189 e->u.rval = FcRangeCopy (range);
195 FcExprCreateBool (FcConfig *config, FcBool b)
197 FcExpr *e = FcConfigAllocExpr (config);
207 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
209 FcExpr *e = FcConfigAllocExpr (config);
213 e->u.cval = FcCharSetCopy (charset);
219 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
221 FcExpr *e = FcConfigAllocExpr (config);
225 e->u.lval = FcLangSetCopy (langset);
231 FcExprCreateName (FcConfig *config, FcExprName name)
233 FcExpr *e = FcConfigAllocExpr (config);
243 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
245 FcExpr *e = FcConfigAllocExpr (config);
249 e->u.constant = FcStrdup (constant);
255 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
257 FcExpr *e = FcConfigAllocExpr (config);
261 e->u.tree.left = left;
262 e->u.tree.right = right;
268 FcExprDestroy (FcExpr *e)
272 switch (FC_OP_GET_OP (e->op)) {
281 FcExprMatrixFree (e->u.mexpr);
284 FcRangeDestroy (e->u.rval);
287 FcCharSetDestroy (e->u.cval);
290 FcLangSetDestroy (e->u.lval);
297 FcFree (e->u.constant);
300 case FcOpAssignReplace:
302 case FcOpPrependFirst:
318 case FcOpNotContains:
325 FcExprDestroy (e->u.tree.right);
332 FcExprDestroy (e->u.tree.left);
343 FcEditDestroy (FcEdit *e)
346 FcExprDestroy (e->expr);
350 typedef enum _FcElement {
360 FcElementDescription,
397 FcElementNotContains,
411 static const struct {
415 { "fontconfig", FcElementFontconfig },
416 { "dir", FcElementDir },
417 { "cachedir", FcElementCacheDir },
418 { "cache", FcElementCache },
419 { "include", FcElementInclude },
420 { "config", FcElementConfig },
421 { "match", FcElementMatch },
422 { "alias", FcElementAlias },
423 { "description", FcElementDescription },
425 { "rescan", FcElementRescan },
427 { "prefer", FcElementPrefer },
428 { "accept", FcElementAccept },
429 { "default", FcElementDefault },
430 { "family", FcElementFamily },
432 { "selectfont", FcElementSelectfont },
433 { "acceptfont", FcElementAcceptfont },
434 { "rejectfont", FcElementRejectfont },
435 { "glob", FcElementGlob },
436 { "pattern", FcElementPattern },
437 { "patelt", FcElementPatelt },
439 { "test", FcElementTest },
440 { "edit", FcElementEdit },
441 { "int", FcElementInt },
442 { "double", FcElementDouble },
443 { "string", FcElementString },
444 { "matrix", FcElementMatrix },
445 { "range", FcElementRange },
446 { "bool", FcElementBool },
447 { "charset", FcElementCharSet },
448 { "langset", FcElementLangSet },
449 { "name", FcElementName },
450 { "const", FcElementConst },
451 { "or", FcElementOr },
452 { "and", FcElementAnd },
453 { "eq", FcElementEq },
454 { "not_eq", FcElementNotEq },
455 { "less", FcElementLess },
456 { "less_eq", FcElementLessEq },
457 { "more", FcElementMore },
458 { "more_eq", FcElementMoreEq },
459 { "contains", FcElementContains },
460 { "not_contains", FcElementNotContains },
461 { "plus", FcElementPlus },
462 { "minus", FcElementMinus },
463 { "times", FcElementTimes },
464 { "divide", FcElementDivide },
465 { "not", FcElementNot },
466 { "if", FcElementIf },
467 { "floor", FcElementFloor },
468 { "ceil", FcElementCeil },
469 { "round", FcElementRound },
470 { "trunc", FcElementTrunc },
472 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
474 static const char *fcElementIgnoreName[16] = {
480 FcElementMap (const XML_Char *name)
484 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
485 if (!strcmp ((char *) name, fcElementMap[i].name))
486 return fcElementMap[i].element;
487 for (i = 0; fcElementIgnoreName[i] != NULL; i++)
488 if (!strncmp ((char *) name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
489 return FcElementNone;
490 return FcElementUnknown;
493 typedef struct _FcPStack {
494 struct _FcPStack *prev;
498 FcChar8 *attr_buf_static[16];
501 typedef enum _FcVStackTag {
528 typedef struct _FcVStack {
529 struct _FcVStack *prev;
530 FcPStack *pstack; /* related parse element */
537 FcExprMatrix *matrix;
554 typedef struct _FcConfigParse {
562 unsigned int pstack_static_used;
563 FcPStack pstack_static[8];
564 unsigned int vstack_static_used;
565 FcVStack vstack_static[64];
569 typedef enum _FcConfigSeverity {
570 FcSevereInfo, FcSevereWarning, FcSevereError
574 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
576 const char *s = "unknown";
579 va_start (args, fmt);
582 case FcSevereInfo: s = "info"; break;
583 case FcSevereWarning: s = "warning"; break;
584 case FcSevereError: s = "error"; break;
589 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
590 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
592 fprintf (stderr, "Fontconfig %s: line %d: ", s,
593 (int)XML_GetCurrentLineNumber (parse->parser));
594 if (severe >= FcSevereError)
595 parse->error = FcTrue;
598 fprintf (stderr, "Fontconfig %s: ", s);
599 vfprintf (stderr, fmt, args);
600 fprintf (stderr, "\n");
606 FcPopExpr (FcConfigParse *parse);
610 FcTypeName (FcType type)
639 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
641 if (value == FcTypeInteger)
642 value = FcTypeDouble;
643 if (type == FcTypeInteger)
647 if ((value == FcTypeLangSet && type == FcTypeString) ||
648 (value == FcTypeString && type == FcTypeLangSet) ||
649 (value == FcTypeDouble && type == FcTypeRange))
651 if (type == FcTypeUnknown)
653 /* It's perfectly fine to use user-define elements in expressions,
654 * so don't warn in that case. */
655 if (value == FcTypeUnknown)
657 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
658 FcTypeName (value), FcTypeName (type));
663 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
665 const FcObjectType *o;
668 /* If parsing the expression failed, some nodes may be NULL */
672 switch (FC_OP_GET_OP (expr->op)) {
675 FcTypecheckValue (parse, FcTypeDouble, type);
678 FcTypecheckValue (parse, FcTypeString, type);
681 FcTypecheckValue (parse, FcTypeMatrix, type);
684 FcTypecheckValue (parse, FcTypeBool, type);
687 FcTypecheckValue (parse, FcTypeCharSet, type);
690 FcTypecheckValue (parse, FcTypeLangSet, type);
693 FcTypecheckValue (parse, FcTypeRange, type);
698 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
700 FcTypecheckValue (parse, o->type, type);
703 c = FcNameGetConstant (expr->u.constant);
706 o = FcNameGetObjectType (c->object);
708 FcTypecheckValue (parse, o->type, type);
711 FcConfigMessage (parse, FcSevereWarning,
712 "invalid constant used : %s",
716 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
717 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
718 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
721 case FcOpAssignReplace:
730 case FcOpNotContains:
732 FcTypecheckValue (parse, FcTypeBool, type);
741 FcTypecheckExpr (parse, expr->u.tree.left, type);
742 FcTypecheckExpr (parse, expr->u.tree.right, type);
745 FcTypecheckValue (parse, FcTypeBool, type);
746 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
752 FcTypecheckValue (parse, FcTypeDouble, type);
753 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
761 FcTestCreate (FcConfigParse *parse,
764 const FcChar8 *field,
765 unsigned int compare,
768 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
772 const FcObjectType *o;
776 test->object = FcObjectFromName ((const char *) field);
779 o = FcNameGetObjectType (FcObjectName (test->object));
781 FcTypecheckExpr (parse, expr, o->type);
787 FcEditCreate (FcConfigParse *parse,
791 FcValueBinding binding)
793 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
797 const FcObjectType *o;
802 e->binding = binding;
803 o = FcNameGetObjectType (FcObjectName (e->object));
805 FcTypecheckExpr (parse, expr, o->type);
811 FcRuleCreate (FcRuleType type,
814 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
824 r->u.test = (FcTest *) p;
827 r->u.edit = (FcEdit *) p;
840 FcVStackCreateAndPush (FcConfigParse *parse)
844 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
845 new = &parse->vstack_static[parse->vstack_static_used++];
848 new = malloc (sizeof (FcVStack));
852 new->tag = FcVStackNone;
855 new->prev = parse->vstack;
856 new->pstack = parse->pstack ? parse->pstack->prev : 0;
863 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
865 FcVStack *vstack = FcVStackCreateAndPush (parse);
868 vstack->u.string = string;
874 FcVStackPushInteger (FcConfigParse *parse, int integer)
876 FcVStack *vstack = FcVStackCreateAndPush (parse);
879 vstack->u.integer = integer;
880 vstack->tag = FcVStackInteger;
885 FcVStackPushDouble (FcConfigParse *parse, double _double)
887 FcVStack *vstack = FcVStackCreateAndPush (parse);
890 vstack->u._double = _double;
891 vstack->tag = FcVStackDouble;
896 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
899 vstack = FcVStackCreateAndPush (parse);
902 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
903 vstack->tag = FcVStackMatrix;
908 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
910 FcVStack *vstack = FcVStackCreateAndPush (parse);
913 vstack->u.range = range;
914 vstack->tag = FcVStackRange;
919 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
921 FcVStack *vstack = FcVStackCreateAndPush (parse);
924 vstack->u.bool_ = bool_;
925 vstack->tag = FcVStackBool;
930 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
935 vstack = FcVStackCreateAndPush (parse);
938 vstack->u.charset = charset;
939 vstack->tag = FcVStackCharSet;
944 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
949 vstack = FcVStackCreateAndPush (parse);
952 vstack->u.langset = langset;
953 vstack->tag = FcVStackLangSet;
958 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
960 FcVStack *vstack = FcVStackCreateAndPush (parse);
963 vstack->u.name.object = object;
964 vstack->u.name.kind = kind;
965 vstack->tag = FcVStackName;
970 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
972 FcVStack *vstack = FcVStackCreateAndPush (parse);
975 vstack->u.test = test;
976 vstack->tag = FcVStackTest;
981 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
983 FcVStack *vstack = FcVStackCreateAndPush (parse);
986 vstack->u.expr = expr;
992 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
994 FcVStack *vstack = FcVStackCreateAndPush (parse);
997 vstack->u.edit = edit;
998 vstack->tag = FcVStackEdit;
1003 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
1005 FcVStack *vstack = FcVStackCreateAndPush (parse);
1008 vstack->u.pattern = pattern;
1009 vstack->tag = FcVStackPattern;
1014 FcVStackFetch (FcConfigParse *parse, int off)
1018 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
1023 FcVStackPeek (FcConfigParse *parse)
1025 FcVStack *vstack = parse->vstack;
1027 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1031 FcVStackPopAndDestroy (FcConfigParse *parse)
1033 FcVStack *vstack = parse->vstack;
1035 if (!vstack || vstack->pstack != parse->pstack)
1038 parse->vstack = vstack->prev;
1040 switch (vstack->tag) {
1045 case FcVStackFamily:
1047 case FcVStackString:
1048 case FcVStackConstant:
1050 FcStrFree (vstack->u.string);
1052 case FcVStackPattern:
1053 FcPatternDestroy (vstack->u.pattern);
1055 case FcVStackInteger:
1056 case FcVStackDouble:
1058 case FcVStackMatrix:
1059 FcExprMatrixFreeShallow (vstack->u.matrix);
1064 FcRangeDestroy (vstack->u.range);
1066 case FcVStackCharSet:
1067 FcCharSetDestroy (vstack->u.charset);
1069 case FcVStackLangSet:
1070 FcLangSetDestroy (vstack->u.langset);
1073 FcTestDestroy (vstack->u.test);
1076 case FcVStackPrefer:
1077 case FcVStackAccept:
1078 case FcVStackDefault:
1079 FcExprDestroy (vstack->u.expr);
1082 FcEditDestroy (vstack->u.edit);
1086 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1087 parse->vstack_static_used--;
1093 FcVStackClear (FcConfigParse *parse)
1095 while (FcVStackPeek (parse))
1096 FcVStackPopAndDestroy (parse);
1100 FcVStackElements (FcConfigParse *parse)
1103 FcVStack *vstack = parse->vstack;
1104 while (vstack && vstack->pstack == parse->pstack)
1107 vstack = vstack->prev;
1113 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1123 for (i = 0; attr[i]; i++)
1124 slen += strlen ((char *) attr[i]) + 1;
1127 slen += (i + 1) * sizeof (FcChar8 *);
1128 if (slen <= size_bytes)
1132 new = malloc (slen);
1135 FcConfigMessage (0, FcSevereError, "out of memory");
1139 s = (FcChar8 *) (new + (i + 1));
1140 for (i = 0; attr[i]; i++)
1143 strcpy ((char *) s, (char *) attr[i]);
1144 s += strlen ((char *) s) + 1;
1151 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1155 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1156 new = &parse->pstack_static[parse->pstack_static_used++];
1159 new = malloc (sizeof (FcPStack));
1164 new->prev = parse->pstack;
1165 new->element = element;
1166 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1167 FcStrBufInit (&new->str, 0, 0);
1168 parse->pstack = new;
1173 FcPStackPop (FcConfigParse *parse)
1179 FcConfigMessage (parse, FcSevereError, "mismatching element");
1183 /* Don't check the attributes for FcElementNone */
1184 if (parse->pstack->element != FcElementNone &&
1185 parse->pstack->attr)
1187 /* Warn about unused attrs. */
1188 FcChar8 **attrs = parse->pstack->attr;
1193 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1199 FcVStackClear (parse);
1200 old = parse->pstack;
1201 parse->pstack = old->prev;
1202 FcStrBufDestroy (&old->str);
1204 if (old->attr && old->attr != old->attr_buf_static)
1207 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1208 parse->pstack_static_used--;
1215 FcConfigParseInit (FcConfigParse *parse,
1216 const FcChar8 *name,
1222 parse->pstack_static_used = 0;
1224 parse->vstack_static_used = 0;
1225 parse->error = FcFalse;
1227 parse->config = config;
1228 parse->ruleset = FcRuleSetCreate (name);
1229 parse->parser = parser;
1230 parse->scanOnly = !enabled;
1231 FcRuleSetEnable (parse->ruleset, enabled);
1237 FcConfigCleanup (FcConfigParse *parse)
1239 while (parse->pstack)
1240 FcPStackPop (parse);
1241 FcRuleSetDestroy (parse->ruleset);
1242 parse->ruleset = NULL;
1245 static const FcChar8 *
1246 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1252 attrs = parse->pstack->attr;
1258 if (!strcmp ((char *) *attrs, attr))
1260 attrs[0][0] = '\0'; /* Mark as used. */
1269 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1271 FcConfigParse *parse = userData;
1274 element = FcElementMap (name);
1275 if (element == FcElementUnknown)
1276 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1278 if (!FcPStackPush (parse, element, attr))
1280 FcConfigMessage (parse, FcSevereError, "out of memory");
1287 FcParseRescan (FcConfigParse *parse)
1289 int n = FcVStackElements (parse);
1292 FcVStack *v = FcVStackFetch (parse, n);
1293 if (v->tag != FcVStackInteger)
1294 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1296 parse->config->rescanInterval = v->u.integer;
1301 FcParseInt (FcConfigParse *parse)
1308 s = FcStrBufDoneStatic (&parse->pstack->str);
1311 FcConfigMessage (parse, FcSevereError, "out of memory");
1315 l = (int) strtol ((char *) s, (char **)&end, 0);
1316 if (end != s + strlen ((char *) s))
1317 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1319 FcVStackPushInteger (parse, l);
1320 FcStrBufDestroy (&parse->pstack->str);
1324 * idea copied from glib g_ascii_strtod with
1325 * permission of the author (Alexander Larsson)
1331 FcStrtod (char *s, char **end)
1334 struct lconv *locale_data;
1336 const char *decimal_point;
1342 * Have to swap the decimal point to match the current locale
1343 * if that locale doesn't use 0x2e
1346 locale_data = localeconv ();
1347 decimal_point = locale_data->decimal_point;
1348 dlen = strlen (decimal_point);
1350 decimal_point = ".";
1354 if ((dot = strchr (s, 0x2e)) &&
1355 (decimal_point[0] != 0x2e ||
1356 decimal_point[1] != 0))
1359 int slen = strlen (s);
1361 if (slen + dlen > (int) sizeof (buf))
1371 strncpy (buf, s, dot - s);
1373 strcpy (buf + (dot - s), decimal_point);
1374 /* rest of number */
1375 strcpy (buf + (dot - s) + dlen, dot + 1);
1377 v = strtod (buf, &buf_end);
1379 buf_end = s + (buf_end - buf);
1381 buf_end -= dlen - 1;
1388 v = strtod (s, end);
1393 FcParseDouble (FcConfigParse *parse)
1400 s = FcStrBufDoneStatic (&parse->pstack->str);
1403 FcConfigMessage (parse, FcSevereError, "out of memory");
1407 d = FcStrtod ((char *) s, (char **)&end);
1408 if (end != s + strlen ((char *) s))
1409 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1411 FcVStackPushDouble (parse, d);
1412 FcStrBufDestroy (&parse->pstack->str);
1416 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1422 s = FcStrBufDone (&parse->pstack->str);
1425 FcConfigMessage (parse, FcSevereError, "out of memory");
1428 if (!FcVStackPushString (parse, tag, s))
1433 FcParseName (FcConfigParse *parse)
1435 const FcChar8 *kind_string;
1440 kind_string = FcConfigGetAttribute (parse, "target");
1442 kind = FcMatchDefault;
1445 if (!strcmp ((char *) kind_string, "pattern"))
1446 kind = FcMatchPattern;
1447 else if (!strcmp ((char *) kind_string, "font"))
1449 else if (!strcmp ((char *) kind_string, "default"))
1450 kind = FcMatchDefault;
1453 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1460 s = FcStrBufDone (&parse->pstack->str);
1463 FcConfigMessage (parse, FcSevereError, "out of memory");
1466 object = FcObjectFromName ((const char *) s);
1468 FcVStackPushName (parse, kind, object);
1474 FcParseMatrix (FcConfigParse *parse)
1478 m.yy = FcPopExpr (parse);
1479 m.yx = FcPopExpr (parse);
1480 m.xy = FcPopExpr (parse);
1481 m.xx = FcPopExpr (parse);
1483 if (FcPopExpr (parse))
1484 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1486 FcVStackPushMatrix (parse, &m);
1490 FcParseRange (FcConfigParse *parse)
1494 FcChar32 n[2] = {0, 0};
1496 double d[2] = {0.0L, 0.0L};
1497 FcBool dflag = FcFalse;
1499 while ((vstack = FcVStackPeek (parse)))
1503 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1506 switch ((int) vstack->tag) {
1507 case FcVStackInteger:
1509 d[count] = (double)vstack->u.integer;
1511 n[count] = vstack->u.integer;
1513 case FcVStackDouble:
1514 if (count == 0 && !dflag)
1515 d[1] = (double)n[1];
1516 d[count] = vstack->u._double;
1520 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1528 FcVStackPopAndDestroy (parse);
1532 FcConfigMessage (parse, FcSevereError, "invalid range");
1539 FcConfigMessage (parse, FcSevereError, "invalid range");
1542 r = FcRangeCreateDouble (d[0], d[1]);
1548 FcConfigMessage (parse, FcSevereError, "invalid range");
1551 r = FcRangeCreateInteger (n[0], n[1]);
1553 FcVStackPushRange (parse, r);
1557 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1559 FcBool result = FcFalse;
1561 if (!FcNameBool (bool_, &result))
1562 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1568 FcParseBool (FcConfigParse *parse)
1574 s = FcStrBufDoneStatic (&parse->pstack->str);
1577 FcConfigMessage (parse, FcSevereError, "out of memory");
1580 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1581 FcStrBufDestroy (&parse->pstack->str);
1585 FcParseCharSet (FcConfigParse *parse)
1588 FcCharSet *charset = FcCharSetCreate ();
1589 FcChar32 i, begin, end;
1592 while ((vstack = FcVStackPeek (parse)))
1594 switch ((int) vstack->tag) {
1595 case FcVStackInteger:
1596 if (!FcCharSetAddChar (charset, vstack->u.integer))
1598 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1604 begin = (FcChar32) vstack->u.range->begin;
1605 end = (FcChar32) vstack->u.range->end;
1609 for (i = begin; i <= end; i++)
1611 if (!FcCharSetAddChar (charset, i))
1613 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1621 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1624 FcVStackPopAndDestroy (parse);
1627 FcVStackPushCharSet (parse, charset);
1629 FcCharSetDestroy (charset);
1633 FcParseLangSet (FcConfigParse *parse)
1636 FcLangSet *langset = FcLangSetCreate ();
1639 while ((vstack = FcVStackPeek (parse)))
1641 switch ((int) vstack->tag) {
1642 case FcVStackString:
1643 if (!FcLangSetAdd (langset, vstack->u.string))
1645 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1651 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1654 FcVStackPopAndDestroy (parse);
1657 FcVStackPushLangSet (parse, langset);
1659 FcLangSetDestroy (langset);
1663 FcConfigLexBinding (FcConfigParse *parse,
1664 const FcChar8 *binding_string,
1665 FcValueBinding *binding_ret)
1667 FcValueBinding binding;
1669 if (!binding_string)
1670 binding = FcValueBindingWeak;
1673 if (!strcmp ((char *) binding_string, "weak"))
1674 binding = FcValueBindingWeak;
1675 else if (!strcmp ((char *) binding_string, "strong"))
1676 binding = FcValueBindingStrong;
1677 else if (!strcmp ((char *) binding_string, "same"))
1678 binding = FcValueBindingSame;
1681 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1685 *binding_ret = binding;
1690 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1693 FcExpr *left, *expr = 0, *new;
1695 while ((vstack = FcVStackPeek (parse)))
1697 if (vstack->tag != FcVStackFamily)
1699 FcConfigMessage (parse, FcSevereWarning, "non-family");
1700 FcVStackPopAndDestroy (parse);
1703 left = vstack->u.expr;
1704 vstack->tag = FcVStackNone;
1705 FcVStackPopAndDestroy (parse);
1708 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1711 FcConfigMessage (parse, FcSevereError, "out of memory");
1712 FcExprDestroy (left);
1713 FcExprDestroy (expr);
1723 if (!FcVStackPushExpr (parse, tag, expr))
1725 FcConfigMessage (parse, FcSevereError, "out of memory");
1726 FcExprDestroy (expr);
1732 FcParseFamily (FcConfigParse *parse)
1739 s = FcStrBufDoneStatic (&parse->pstack->str);
1742 FcConfigMessage (parse, FcSevereError, "out of memory");
1745 expr = FcExprCreateString (parse->config, s);
1746 FcStrBufDestroy (&parse->pstack->str);
1748 FcVStackPushExpr (parse, FcVStackFamily, expr);
1752 FcParseAlias (FcConfigParse *parse)
1754 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1757 FcRule *rule = NULL, *r;
1758 FcValueBinding binding;
1761 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1763 while ((vstack = FcVStackPeek (parse)))
1765 switch ((int) vstack->tag) {
1766 case FcVStackFamily:
1769 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1770 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1772 FcConfigMessage (parse, FcSevereError, "out of memory");
1777 new = vstack->u.expr;
1781 vstack->tag = FcVStackNone;
1784 case FcVStackPrefer:
1786 FcExprDestroy (prefer);
1787 prefer = vstack->u.expr;
1788 vstack->tag = FcVStackNone;
1790 case FcVStackAccept:
1792 FcExprDestroy (accept);
1793 accept = vstack->u.expr;
1794 vstack->tag = FcVStackNone;
1796 case FcVStackDefault:
1798 FcExprDestroy (def);
1799 def = vstack->u.expr;
1800 vstack->tag = FcVStackNone;
1805 r = FcRuleCreate (FcRuleTest, vstack->u.test);
1810 rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1811 vstack->tag = FcVStackNone;
1814 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1817 FcVStackPopAndDestroy (parse);
1821 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1823 FcExprDestroy (prefer);
1825 FcExprDestroy (accept);
1827 FcExprDestroy (def);
1829 FcRuleDestroy (rule);
1836 FcExprDestroy (family);
1838 FcRuleDestroy (rule);
1843 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1845 (FcChar8 *) FC_FAMILY,
1846 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1850 for (r = rule; r->next; r = r->next);
1851 r->next = FcRuleCreate (FcRuleTest, t);
1856 r = rule = FcRuleCreate (FcRuleTest, t);
1861 edit = FcEditCreate (parse,
1867 FcExprDestroy (prefer);
1870 r->next = FcRuleCreate (FcRuleEdit, edit);
1876 edit = FcEditCreate (parse,
1882 FcExprDestroy (accept);
1885 r->next = FcRuleCreate (FcRuleEdit, edit);
1891 edit = FcEditCreate (parse,
1897 FcExprDestroy (def);
1900 r->next = FcRuleCreate (FcRuleEdit, edit);
1904 if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
1905 FcRuleDestroy (rule);
1907 if (parse->config->maxObjects < n)
1908 parse->config->maxObjects = n;
1912 FcParseDescription (FcConfigParse *parse)
1914 const FcChar8 *domain;
1917 domain = FcConfigGetAttribute (parse, "domain");
1918 desc = FcStrBufDone (&parse->pstack->str);
1921 FcConfigMessage (parse, FcSevereError, "out of memory");
1924 FcRuleSetAddDescription (parse->ruleset, domain, desc);
1930 FcPopExpr (FcConfigParse *parse)
1932 FcVStack *vstack = FcVStackPeek (parse);
1936 switch ((int) vstack->tag) {
1939 case FcVStackString:
1940 case FcVStackFamily:
1941 expr = FcExprCreateString (parse->config, vstack->u.string);
1944 expr = FcExprCreateName (parse->config, vstack->u.name);
1946 case FcVStackConstant:
1947 expr = FcExprCreateConst (parse->config, vstack->u.string);
1950 /* XXX: What's the correct action here? (CDW) */
1952 case FcVStackPrefer:
1953 case FcVStackAccept:
1954 case FcVStackDefault:
1955 expr = vstack->u.expr;
1956 vstack->tag = FcVStackNone;
1958 case FcVStackInteger:
1959 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1961 case FcVStackDouble:
1962 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1964 case FcVStackMatrix:
1965 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1968 expr = FcExprCreateRange (parse->config, vstack->u.range);
1971 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1973 case FcVStackCharSet:
1974 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1976 case FcVStackLangSet:
1977 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1982 expr = vstack->u.expr;
1983 vstack->tag = FcVStackNone;
1990 FcVStackPopAndDestroy (parse);
1995 * This builds a tree of binary operations. Note
1996 * that every operator is defined so that if only
1997 * a single operand is contained, the value of the
1998 * whole expression is the value of the operand.
2000 * This code reduces in that case to returning that
2004 FcPopBinary (FcConfigParse *parse, FcOp op)
2006 FcExpr *left, *expr = 0, *new;
2008 while ((left = FcPopExpr (parse)))
2012 new = FcExprCreateOp (parse->config, left, op, expr);
2015 FcConfigMessage (parse, FcSevereError, "out of memory");
2016 FcExprDestroy (left);
2017 FcExprDestroy (expr);
2029 FcParseBinary (FcConfigParse *parse, FcOp op)
2031 FcExpr *expr = FcPopBinary (parse, op);
2033 FcVStackPushExpr (parse, FcVStackExpr, expr);
2037 * This builds a a unary operator, it consumes only
2042 FcPopUnary (FcConfigParse *parse, FcOp op)
2044 FcExpr *operand, *new = 0;
2046 if ((operand = FcPopExpr (parse)))
2048 new = FcExprCreateOp (parse->config, operand, op, 0);
2051 FcExprDestroy (operand);
2052 FcConfigMessage (parse, FcSevereError, "out of memory");
2059 FcParseUnary (FcConfigParse *parse, FcOp op)
2061 FcExpr *expr = FcPopUnary (parse, op);
2063 FcVStackPushExpr (parse, FcVStackExpr, expr);
2067 FcParseDir (FcConfigParse *parse)
2069 const FcChar8 *attr, *data;
2070 FcChar8 *prefix = NULL, *p;
2072 FcChar8 buffer[1000];
2075 attr = FcConfigGetAttribute (parse, "prefix");
2076 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2078 prefix = FcConfigXdgDataHome ();
2079 /* home directory might be disabled.
2080 * simply ignore this element.
2085 data = FcStrBufDoneStatic (&parse->pstack->str);
2088 FcConfigMessage (parse, FcSevereError, "out of memory");
2094 size_t plen = strlen ((const char *)prefix);
2095 size_t dlen = strlen ((const char *)data);
2097 p = realloc (prefix, plen + 1 + dlen + 1);
2100 FcConfigMessage (parse, FcSevereError, "out of memory");
2104 prefix[plen] = FC_DIR_SEPARATOR;
2105 memcpy (&prefix[plen + 1], data, dlen);
2106 prefix[plen + 1 + dlen] = 0;
2110 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2114 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2116 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2120 * Must use the multi-byte aware function to search
2121 * for backslash because East Asian double-byte code
2122 * pages have characters with backslash as the second
2125 p = _mbsrchr (data, '\\');
2127 strcat ((char *) data, "\\fonts");
2129 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2133 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2135 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2138 p = _mbsrchr (data, '\\');
2140 strcat ((char *) data, "\\..\\share\\fonts");
2142 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2146 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2147 if (rc == 0 || rc > sizeof (buffer) - 20)
2149 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2152 if (data [strlen ((const char *) data) - 1] != '\\')
2153 strcat ((char *) data, "\\");
2154 strcat ((char *) data, "fonts");
2157 if (strlen ((char *) data) == 0)
2158 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2159 else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
2161 if (!FcConfigAddFontDir (parse->config, data))
2162 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2164 FcStrBufDestroy (&parse->pstack->str);
2172 FcParseCacheDir (FcConfigParse *parse)
2174 const FcChar8 *attr;
2175 FcChar8 *prefix = NULL, *p, *data = NULL;
2177 attr = FcConfigGetAttribute (parse, "prefix");
2178 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2180 prefix = FcConfigXdgCacheHome ();
2181 /* home directory might be disabled.
2182 * simply ignore this element.
2187 data = FcStrBufDone (&parse->pstack->str);
2190 FcConfigMessage (parse, FcSevereError, "out of memory");
2196 size_t plen = strlen ((const char *)prefix);
2197 size_t dlen = strlen ((const char *)data);
2199 p = realloc (prefix, plen + 1 + dlen + 1);
2202 FcConfigMessage (parse, FcSevereError, "out of memory");
2207 prefix[plen] = FC_DIR_SEPARATOR;
2208 memcpy (&prefix[plen + 1], data, dlen);
2209 prefix[plen + 1 + dlen] = 0;
2214 else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2216 size_t plen = strlen ((const char *)fontconfig_instprefix);
2217 size_t dlen = strlen ((const char *)data);
2219 prefix = malloc (plen + 1 + dlen + 1);
2222 FcConfigMessage (parse, FcSevereError, "out of memory");
2225 strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2226 prefix[plen] = FC_DIR_SEPARATOR;
2227 memcpy (&prefix[plen + 1], data, dlen);
2228 prefix[plen + 1 + dlen] = 0;
2232 else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2237 data = malloc (1000);
2240 FcConfigMessage (parse, FcSevereError, "out of memory");
2243 rc = GetTempPath (800, (LPSTR) data);
2244 if (rc == 0 || rc > 800)
2246 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2249 if (data [strlen ((const char *) data) - 1] != '\\')
2250 strcat ((char *) data, "\\");
2251 strcat ((char *) data, "fontconfig\\cache");
2253 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2255 char szFPath[MAX_PATH + 1];
2258 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2260 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2263 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2264 len = strlen(szFPath) + 1;
2269 FcConfigMessage (parse, FcSevereError, "out of memory");
2272 strncpy((char *) data, szFPath, len);
2275 if (strlen ((char *) data) == 0)
2276 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2277 else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
2279 if (!FcConfigAddCacheDir (parse->config, data))
2280 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2282 FcStrBufDestroy (&parse->pstack->str);
2290 FcConfigPathFini (void)
2295 s = fc_atomic_ptr_get (&__fc_userdir);
2296 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2301 s = fc_atomic_ptr_get (&__fc_userconf);
2302 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2308 FcParseInclude (FcConfigParse *parse)
2311 const FcChar8 *attr;
2312 FcBool ignore_missing = FcFalse;
2314 FcBool deprecated = FcFalse;
2316 FcChar8 *prefix = NULL, *p;
2317 FcChar8 *userdir = NULL, *userconf = NULL;
2321 s = FcStrBufDoneStatic (&parse->pstack->str);
2324 FcConfigMessage (parse, FcSevereError, "out of memory");
2327 attr = FcConfigGetAttribute (parse, "ignore_missing");
2328 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2329 ignore_missing = FcTrue;
2330 attr = FcConfigGetAttribute (parse, "deprecated");
2332 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2333 deprecated = FcTrue;
2335 attr = FcConfigGetAttribute (parse, "prefix");
2336 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2338 prefix = FcConfigXdgConfigHome ();
2339 /* home directory might be disabled.
2340 * simply ignore this element.
2347 size_t plen = strlen ((const char *)prefix);
2348 size_t dlen = strlen ((const char *)s);
2351 p = realloc (prefix, plen + 1 + dlen + 1);
2354 FcConfigMessage (parse, FcSevereError, "out of memory");
2358 prefix[plen] = FC_DIR_SEPARATOR;
2359 memcpy (&prefix[plen + 1], s, dlen);
2360 prefix[plen + 1 + dlen] = 0;
2362 if (FcFileIsDir (s))
2365 userdir = fc_atomic_ptr_get (&__fc_userdir);
2369 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2377 else if (FcFileIsFile (s))
2380 userconf = fc_atomic_ptr_get (&__fc_userconf);
2384 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2394 /* No config dir nor file on the XDG directory spec compliant place
2395 * so need to guess what it is supposed to be.
2397 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2403 /* flush the ruleset into the queue */
2404 ruleset = parse->ruleset;
2405 parse->ruleset = FcRuleSetCreate (ruleset->name);
2406 FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2407 FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2408 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
2412 FcPtrListIterInit (ruleset->subst[k], &iter);
2413 if (FcPtrListIterIsValid (ruleset->subst[k], &iter))
2415 FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2416 FcRuleSetReference (ruleset);
2417 FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2420 FcRuleSetDestroy (ruleset);
2421 if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
2422 parse->error = FcTrue;
2427 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2429 filename = FcConfigFilename(s);
2430 if (deprecated == FcTrue &&
2433 !FcFileIsLink (filename))
2435 if (FcFileIsDir (filename))
2437 FcChar8 *parent = FcStrDirname (userdir);
2439 if (!FcFileIsDir (parent))
2440 FcMakeDirectory (parent);
2442 if (FcFileIsDir (userdir) ||
2443 rename ((const char *)filename, (const char *)userdir) != 0 ||
2444 symlink ((const char *)userdir, (const char *)filename) != 0)
2448 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2449 warn_confd = FcTrue;
2455 FcChar8 *parent = FcStrDirname (userconf);
2457 if (!FcFileIsDir (parent))
2458 FcMakeDirectory (parent);
2460 if (FcFileIsFile (userconf) ||
2461 rename ((const char *)filename, (const char *)userconf) != 0 ||
2462 symlink ((const char *)userconf, (const char *)filename) != 0)
2466 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2473 FcStrFree(filename);
2476 FcStrBufDestroy (&parse->pstack->str);
2483 typedef struct _FcOpMap {
2489 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2493 for (i = 0; i < nmap; i++)
2494 if (!strcmp ((char *) op, map[i].name))
2499 static const FcOpMap fcCompareOps[] = {
2500 { "eq", FcOpEqual },
2501 { "not_eq", FcOpNotEqual },
2502 { "less", FcOpLess },
2503 { "less_eq", FcOpLessEqual },
2504 { "more", FcOpMore },
2505 { "more_eq", FcOpMoreEqual },
2506 { "contains", FcOpContains },
2507 { "not_contains", FcOpNotContains }
2510 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2513 FcConfigLexCompare (const FcChar8 *compare)
2515 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2519 FcParseTest (FcConfigParse *parse)
2521 const FcChar8 *kind_string;
2523 const FcChar8 *qual_string;
2525 const FcChar8 *name;
2526 const FcChar8 *compare_string;
2530 const FcChar8 *iblanks_string;
2533 kind_string = FcConfigGetAttribute (parse, "target");
2535 kind = FcMatchDefault;
2538 if (!strcmp ((char *) kind_string, "pattern"))
2539 kind = FcMatchPattern;
2540 else if (!strcmp ((char *) kind_string, "font"))
2542 else if (!strcmp ((char *) kind_string, "scan"))
2544 else if (!strcmp ((char *) kind_string, "default"))
2545 kind = FcMatchDefault;
2548 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2552 qual_string = FcConfigGetAttribute (parse, "qual");
2557 if (!strcmp ((char *) qual_string, "any"))
2559 else if (!strcmp ((char *) qual_string, "all"))
2561 else if (!strcmp ((char *) qual_string, "first"))
2563 else if (!strcmp ((char *) qual_string, "not_first"))
2564 qual = FcQualNotFirst;
2567 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2571 name = FcConfigGetAttribute (parse, "name");
2574 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2577 compare_string = FcConfigGetAttribute (parse, "compare");
2578 if (!compare_string)
2579 compare = FcOpEqual;
2582 compare = FcConfigLexCompare (compare_string);
2583 if (compare == FcOpInvalid)
2585 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2589 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2594 if (!FcNameBool (iblanks_string, &f))
2596 FcConfigMessage (parse,
2598 "invalid test ignore-blanks \"%s\"", iblanks_string);
2601 flags |= FcOpFlagIgnoreBlanks;
2603 expr = FcPopBinary (parse, FcOpComma);
2606 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2609 if (expr->op == FcOpComma)
2611 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2613 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2616 FcConfigMessage (parse, FcSevereError, "out of memory");
2619 FcVStackPushTest (parse, test);
2622 static const FcOpMap fcModeOps[] = {
2623 { "assign", FcOpAssign },
2624 { "assign_replace", FcOpAssignReplace },
2625 { "prepend", FcOpPrepend },
2626 { "prepend_first", FcOpPrependFirst },
2627 { "append", FcOpAppend },
2628 { "append_last", FcOpAppendLast },
2629 { "delete", FcOpDelete },
2630 { "delete_all", FcOpDeleteAll },
2633 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2636 FcConfigLexMode (const FcChar8 *mode)
2638 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2642 FcParseEdit (FcConfigParse *parse)
2644 const FcChar8 *name;
2645 const FcChar8 *mode_string;
2647 FcValueBinding binding;
2651 name = FcConfigGetAttribute (parse, "name");
2654 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2657 mode_string = FcConfigGetAttribute (parse, "mode");
2662 mode = FcConfigLexMode (mode_string);
2663 if (mode == FcOpInvalid)
2665 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2669 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2672 expr = FcPopBinary (parse, FcOpComma);
2673 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2676 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2677 FcExprDestroy (expr);
2680 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2681 mode, expr, binding);
2684 FcConfigMessage (parse, FcSevereError, "out of memory");
2685 FcExprDestroy (expr);
2688 if (!FcVStackPushEdit (parse, edit))
2689 FcEditDestroy (edit);
2693 FcParseMatch (FcConfigParse *parse)
2695 const FcChar8 *kind_name;
2698 FcRule *rule = NULL, *r;
2701 kind_name = FcConfigGetAttribute (parse, "target");
2703 kind = FcMatchPattern;
2706 if (!strcmp ((char *) kind_name, "pattern"))
2707 kind = FcMatchPattern;
2708 else if (!strcmp ((char *) kind_name, "font"))
2710 else if (!strcmp ((char *) kind_name, "scan"))
2714 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2718 while ((vstack = FcVStackPeek (parse)))
2720 switch ((int) vstack->tag) {
2722 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2726 vstack->tag = FcVStackNone;
2729 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2731 FcConfigMessage (parse, FcSevereError,
2732 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2733 FcObjectName(vstack->u.edit->object));
2735 FcRuleDestroy (rule);
2738 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2742 vstack->tag = FcVStackNone;
2745 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2748 FcVStackPopAndDestroy (parse);
2752 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2755 if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1)
2757 FcConfigMessage (parse, FcSevereError, "out of memory");
2758 FcRuleDestroy (rule);
2761 if (parse->config->maxObjects < n)
2762 parse->config->maxObjects = n;
2766 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2770 while ((vstack = FcVStackPeek (parse)))
2772 switch ((int) vstack->tag) {
2774 if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2776 element == FcElementAcceptfont))
2778 FcConfigMessage (parse, FcSevereError, "out of memory");
2782 if (parse->scanOnly && vstack->u.string)
2784 FcStrFree (vstack->u.string);
2785 vstack->tag = FcVStackNone;
2789 case FcVStackPattern:
2790 if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2792 element == FcElementAcceptfont))
2794 FcConfigMessage (parse, FcSevereError, "out of memory");
2798 if (parse->scanOnly && vstack->u.pattern)
2799 FcPatternDestroy (vstack->u.pattern);
2800 vstack->tag = FcVStackNone;
2804 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2807 FcVStackPopAndDestroy (parse);
2813 FcPopValue (FcConfigParse *parse)
2815 FcVStack *vstack = FcVStackPeek (parse);
2818 value.type = FcTypeVoid;
2823 switch ((int) vstack->tag) {
2824 case FcVStackString:
2825 value.u.s = FcStrdup (vstack->u.string);
2827 value.type = FcTypeString;
2829 case FcVStackConstant:
2830 if (FcNameConstant (vstack->u.string, &value.u.i))
2831 value.type = FcTypeInteger;
2833 case FcVStackInteger:
2834 value.u.i = vstack->u.integer;
2835 value.type = FcTypeInteger;
2837 case FcVStackDouble:
2838 value.u.d = vstack->u._double;
2839 value.type = FcTypeDouble;
2842 value.u.b = vstack->u.bool_;
2843 value.type = FcTypeBool;
2845 case FcVStackCharSet:
2846 value.u.c = FcCharSetCopy (vstack->u.charset);
2848 value.type = FcTypeCharSet;
2850 case FcVStackLangSet:
2851 value.u.l = FcLangSetCopy (vstack->u.langset);
2853 value.type = FcTypeLangSet;
2856 value.u.r = FcRangeCopy (vstack->u.range);
2858 value.type = FcTypeRange;
2861 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2865 FcVStackPopAndDestroy (parse);
2871 FcParsePatelt (FcConfigParse *parse)
2874 FcPattern *pattern = FcPatternCreate ();
2879 FcConfigMessage (parse, FcSevereError, "out of memory");
2883 name = (char *) FcConfigGetAttribute (parse, "name");
2886 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2887 FcPatternDestroy (pattern);
2893 value = FcPopValue (parse);
2894 if (value.type == FcTypeVoid)
2896 if (!FcPatternAdd (pattern, name, value, FcTrue))
2898 FcConfigMessage (parse, FcSevereError, "out of memory");
2899 FcValueDestroy(value);
2902 FcValueDestroy(value);
2905 FcVStackPushPattern (parse, pattern);
2909 FcParsePattern (FcConfigParse *parse)
2912 FcPattern *pattern = FcPatternCreate ();
2916 FcConfigMessage (parse, FcSevereError, "out of memory");
2920 while ((vstack = FcVStackPeek (parse)))
2922 switch ((int) vstack->tag) {
2923 case FcVStackPattern:
2924 if (!FcPatternAppend (pattern, vstack->u.pattern))
2926 FcConfigMessage (parse, FcSevereError, "out of memory");
2927 FcPatternDestroy (pattern);
2932 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2935 FcVStackPopAndDestroy (parse);
2938 FcVStackPushPattern (parse, pattern);
2942 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2944 FcConfigParse *parse = userData;
2949 switch (parse->pstack->element) {
2952 case FcElementFontconfig:
2957 case FcElementCacheDir:
2958 FcParseCacheDir (parse);
2960 case FcElementCache:
2961 data = FcStrBufDoneStatic (&parse->pstack->str);
2964 FcConfigMessage (parse, FcSevereError, "out of memory");
2967 /* discard this data; no longer used */
2968 FcStrBufDestroy (&parse->pstack->str);
2970 case FcElementInclude:
2971 FcParseInclude (parse);
2973 case FcElementConfig:
2975 case FcElementMatch:
2976 FcParseMatch (parse);
2978 case FcElementAlias:
2979 FcParseAlias (parse);
2981 case FcElementDescription:
2982 FcParseDescription (parse);
2985 case FcElementRescan:
2986 FcParseRescan (parse);
2989 case FcElementPrefer:
2990 FcParseFamilies (parse, FcVStackPrefer);
2992 case FcElementAccept:
2993 FcParseFamilies (parse, FcVStackAccept);
2995 case FcElementDefault:
2996 FcParseFamilies (parse, FcVStackDefault);
2998 case FcElementFamily:
2999 FcParseFamily (parse);
3003 FcParseTest (parse);
3006 FcParseEdit (parse);
3012 case FcElementDouble:
3013 FcParseDouble (parse);
3015 case FcElementString:
3016 FcParseString (parse, FcVStackString);
3018 case FcElementMatrix:
3019 FcParseMatrix (parse);
3021 case FcElementRange:
3022 FcParseRange (parse);
3025 FcParseBool (parse);
3027 case FcElementCharSet:
3028 FcParseCharSet (parse);
3030 case FcElementLangSet:
3031 FcParseLangSet (parse);
3033 case FcElementSelectfont:
3035 case FcElementAcceptfont:
3036 case FcElementRejectfont:
3037 FcParseAcceptRejectFont (parse, parse->pstack->element);
3040 FcParseString (parse, FcVStackGlob);
3042 case FcElementPattern:
3043 FcParsePattern (parse);
3045 case FcElementPatelt:
3046 FcParsePatelt (parse);
3049 FcParseName (parse);
3051 case FcElementConst:
3052 FcParseString (parse, FcVStackConstant);
3055 FcParseBinary (parse, FcOpOr);
3058 FcParseBinary (parse, FcOpAnd);
3061 FcParseBinary (parse, FcOpEqual);
3063 case FcElementNotEq:
3064 FcParseBinary (parse, FcOpNotEqual);
3067 FcParseBinary (parse, FcOpLess);
3069 case FcElementLessEq:
3070 FcParseBinary (parse, FcOpLessEqual);
3073 FcParseBinary (parse, FcOpMore);
3075 case FcElementMoreEq:
3076 FcParseBinary (parse, FcOpMoreEqual);
3078 case FcElementContains:
3079 FcParseBinary (parse, FcOpContains);
3081 case FcElementNotContains:
3082 FcParseBinary (parse, FcOpNotContains);
3085 FcParseBinary (parse, FcOpPlus);
3087 case FcElementMinus:
3088 FcParseBinary (parse, FcOpMinus);
3090 case FcElementTimes:
3091 FcParseBinary (parse, FcOpTimes);
3093 case FcElementDivide:
3094 FcParseBinary (parse, FcOpDivide);
3097 FcParseUnary (parse, FcOpNot);
3100 FcParseBinary (parse, FcOpQuest);
3102 case FcElementFloor:
3103 FcParseUnary (parse, FcOpFloor);
3106 FcParseUnary (parse, FcOpCeil);
3108 case FcElementRound:
3109 FcParseUnary (parse, FcOpRound);
3111 case FcElementTrunc:
3112 FcParseUnary (parse, FcOpTrunc);
3114 case FcElementUnknown:
3117 (void) FcPStackPop (parse);
3121 FcCharacterData (void *userData, const XML_Char *s, int len)
3123 FcConfigParse *parse = userData;
3127 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
3128 FcConfigMessage (parse, FcSevereError, "out of memory");
3132 FcStartDoctypeDecl (void *userData,
3133 const XML_Char *doctypeName,
3134 const XML_Char *sysid FC_UNUSED,
3135 const XML_Char *pubid FC_UNUSED,
3136 int has_internal_subset FC_UNUSED)
3138 FcConfigParse *parse = userData;
3140 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
3141 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3144 #ifdef ENABLE_LIBXML2
3147 FcInternalSubsetDecl (void *userData,
3148 const XML_Char *doctypeName,
3149 const XML_Char *sysid,
3150 const XML_Char *pubid)
3152 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3156 FcExternalSubsetDecl (void *userData,
3157 const XML_Char *doctypeName,
3158 const XML_Char *sysid,
3159 const XML_Char *pubid)
3161 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3164 #else /* ENABLE_LIBXML2 */
3167 FcEndDoctypeDecl (void *userData FC_UNUSED)
3171 #endif /* ENABLE_LIBXML2 */
3174 FcSortCmpStr (const void *a, const void *b)
3176 const FcChar8 *as = *((FcChar8 **) a);
3177 const FcChar8 *bs = *((FcChar8 **) b);
3178 return FcStrCmp (as, bs);
3182 FcConfigParseAndLoadDir (FcConfig *config,
3183 const FcChar8 *name,
3190 FcBool ret = FcTrue;
3195 d = opendir ((char *) dir);
3199 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3205 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3212 strcpy ((char *) file, (char *) dir);
3213 strcat ((char *) file, "/");
3214 base = file + strlen ((char *) file);
3216 files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3223 if (FcDebug () & FC_DBG_CONFIG)
3224 printf ("\tScanning config dir %s\n", dir);
3227 FcConfigAddConfigDir (config, dir);
3229 while (ret && (e = readdir (d)))
3232 #define TAIL ".conf"
3235 * Add all files of the form [0-9]*.conf
3237 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3238 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3240 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3242 strcpy ((char *) base, (char *) e->d_name);
3243 if (!FcStrSetAdd (files, file))
3253 qsort (files->strs, files->num, sizeof (FcChar8 *),
3254 (int (*)(const void *, const void *)) FcSortCmpStr);
3255 for (i = 0; ret && i < files->num; i++)
3256 ret = _FcConfigParse (config, files->strs[i], complain, load);
3259 FcStrSetDestroy (files);
3265 return ret || !complain;
3269 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3270 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3274 FcConfigParseAndLoadFromMemoryInternal (FcConfig *config,
3275 const FcChar8 *filename,
3276 const FcChar8 *buffer,
3283 FcConfigParse parse;
3284 FcBool error = FcTrue;
3286 FcPtrListIter liter;
3288 #ifdef ENABLE_LIBXML2
3298 len = strlen ((const char *) buffer);
3299 if (FcDebug () & FC_DBG_CONFIG)
3300 printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3302 #ifdef ENABLE_LIBXML2
3303 memset(&sax, 0, sizeof(sax));
3305 sax.internalSubset = FcInternalSubsetDecl;
3306 sax.externalSubset = FcExternalSubsetDecl;
3307 sax.startElement = FcStartElement;
3308 sax.endElement = FcEndElement;
3309 sax.characters = FcCharacterData;
3311 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3313 p = XML_ParserCreate ("UTF-8");
3319 if (!FcConfigParseInit (&parse, filename, config, p, load))
3322 #ifndef ENABLE_LIBXML2
3324 XML_SetUserData (p, &parse);
3326 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3327 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3328 XML_SetCharacterDataHandler (p, FcCharacterData);
3330 #endif /* ENABLE_LIBXML2 */
3332 #ifndef ENABLE_LIBXML2
3335 buf = XML_GetBuffer (p, BUFSIZ);
3338 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3351 memcpy (buf, s, buflen);
3355 #ifdef ENABLE_LIBXML2
3356 if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3358 if (!XML_ParseBuffer (p, buflen, buflen == 0))
3361 FcConfigMessage (&parse, FcSevereError, "%s",
3362 XML_ErrorString (XML_GetErrorCode (p)));
3365 #ifndef ENABLE_LIBXML2
3366 } while (buflen != 0);
3368 error = parse.error;
3371 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3375 FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3376 if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
3378 FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3379 FcRuleSetReference (parse.ruleset);
3380 FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3384 FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3385 FcRuleSetReference (parse.ruleset);
3386 FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3388 FcConfigCleanup (&parse);
3392 if (error && complain)
3394 FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3397 if (FcDebug () & FC_DBG_CONFIG)
3398 printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3403 _FcConfigParse (FcConfig *config,
3404 const FcChar8 *name,
3408 FcChar8 *filename = NULL, *realfilename = NULL;
3413 FcBool ret = FcFalse;
3416 if (!pGetSystemWindowsDirectory)
3418 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3419 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3420 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3422 if (!pSHGetFolderPathA)
3424 HMODULE hSh = LoadLibraryA("shfolder.dll");
3425 /* the check is done later, because there is no provided fallback */
3427 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3431 filename = FcConfigFilename (name);
3434 realfilename = FcConfigRealFilename (config, name);
3437 if (FcStrSetMember (config->availConfigFiles, realfilename))
3439 FcStrFree (filename);
3440 FcStrFree (realfilename);
3446 if (!FcStrSetAdd (config->configFiles, filename))
3449 if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3452 if (FcFileIsDir (realfilename))
3454 ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3455 FcStrFree (filename);
3456 FcStrFree (realfilename);
3460 FcStrBufInit (&sbuf, NULL, 0);
3462 fd = FcOpen ((char *) realfilename, O_RDONLY);
3467 len = read (fd, buf, BUFSIZ);
3471 char ebuf[BUFSIZ+1];
3474 strerror_r (errno_, ebuf, BUFSIZ);
3476 char *tmp = strerror (errno_);
3477 size_t len = strlen (tmp);
3478 strncpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3479 ebuf[FC_MIN (BUFSIZ, len)] = 0;
3483 FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3487 FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3491 ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3492 complain = FcFalse; /* no need to reclaim here */
3494 FcStrBufDestroy (&sbuf);
3497 FcStrFree (filename);
3499 FcStrFree (realfilename);
3500 if (!ret && complain)
3503 FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\"", load ? "load" : "scan", name);
3505 FcConfigMessage (0, FcSevereError, "Cannot %s default config file", load ? "load" : "scan");
3512 FcConfigParseOnly (FcConfig *config,
3513 const FcChar8 *name,
3516 return _FcConfigParse (config, name, complain, FcFalse);
3520 FcConfigParseAndLoad (FcConfig *config,
3521 const FcChar8 *name,
3524 return _FcConfigParse (config, name, complain, FcTrue);
3528 FcConfigParseAndLoadFromMemory (FcConfig *config,
3529 const FcChar8 *buffer,
3532 return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3536 #include "fcaliastail.h"