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.
32 #include <libxml/parser.h>
34 #define XML_Char xmlChar
35 #define XML_Parser xmlParserCtxtPtr
36 #define XML_ParserFree xmlFreeParserCtxt
37 #define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
38 #define XML_GetErrorCode xmlCtxtGetLastError
39 #define XML_ErrorString(Error) (Error)->message
41 #else /* ENABLE_LIBXML2 */
43 #ifndef HAVE_XMLPARSE_H
44 #define HAVE_XMLPARSE_H 0
53 #endif /* ENABLE_LIBXML2 */
57 extern FcChar8 fontconfig_instprefix[];
60 static FcChar8 *__fc_userdir = NULL;
61 static FcChar8 *__fc_userconf = NULL;
64 FcExprDestroy (FcExpr *e);
67 FcTestDestroy (FcTest *test)
69 FcExprDestroy (test->expr);
74 FcRuleDestroy (FcRule *rule)
76 FcRule *n = rule->next;
80 FcTestDestroy (rule->u.test);
83 FcEditDestroy (rule->u.edit);
95 FcExprCreateInteger (FcConfig *config, int i)
97 FcExpr *e = FcConfigAllocExpr (config);
107 FcExprCreateDouble (FcConfig *config, double d)
109 FcExpr *e = FcConfigAllocExpr (config);
119 FcExprCreateString (FcConfig *config, const FcChar8 *s)
121 FcExpr *e = FcConfigAllocExpr (config);
125 e->u.sval = FcStrdup (s);
130 static FcExprMatrix *
131 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
133 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
142 FcExprMatrixFreeShallow (FcExprMatrix *m)
151 FcExprMatrixFree (FcExprMatrix *m)
156 FcExprDestroy (m->xx);
157 FcExprDestroy (m->xy);
158 FcExprDestroy (m->yx);
159 FcExprDestroy (m->yy);
165 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
167 FcExpr *e = FcConfigAllocExpr (config);
171 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
177 FcExprCreateRange (FcConfig *config, FcRange *range)
179 FcExpr *e = FcConfigAllocExpr (config);
183 e->u.rval = FcRangeCopy (range);
189 FcExprCreateBool (FcConfig *config, FcBool b)
191 FcExpr *e = FcConfigAllocExpr (config);
201 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
203 FcExpr *e = FcConfigAllocExpr (config);
207 e->u.cval = FcCharSetCopy (charset);
213 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
215 FcExpr *e = FcConfigAllocExpr (config);
219 e->u.lval = FcLangSetCopy (langset);
225 FcExprCreateName (FcConfig *config, FcExprName name)
227 FcExpr *e = FcConfigAllocExpr (config);
237 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
239 FcExpr *e = FcConfigAllocExpr (config);
243 e->u.constant = FcStrdup (constant);
249 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
251 FcExpr *e = FcConfigAllocExpr (config);
255 e->u.tree.left = left;
256 e->u.tree.right = right;
262 FcExprDestroy (FcExpr *e)
266 switch (FC_OP_GET_OP (e->op)) {
275 FcExprMatrixFree (e->u.mexpr);
278 FcRangeDestroy (e->u.rval);
281 FcCharSetDestroy (e->u.cval);
284 FcLangSetDestroy (e->u.lval);
291 FcFree (e->u.constant);
294 case FcOpAssignReplace:
296 case FcOpPrependFirst:
312 case FcOpNotContains:
319 FcExprDestroy (e->u.tree.right);
326 FcExprDestroy (e->u.tree.left);
337 FcEditDestroy (FcEdit *e)
340 FcExprDestroy (e->expr);
344 typedef enum _FcElement {
391 FcElementNotContains,
405 static const struct {
409 { "fontconfig", FcElementFontconfig },
410 { "dir", FcElementDir },
411 { "cachedir", FcElementCacheDir },
412 { "cache", FcElementCache },
413 { "include", FcElementInclude },
414 { "config", FcElementConfig },
415 { "match", FcElementMatch },
416 { "alias", FcElementAlias },
418 { "blank", FcElementBlank },
419 { "rescan", FcElementRescan },
421 { "prefer", FcElementPrefer },
422 { "accept", FcElementAccept },
423 { "default", FcElementDefault },
424 { "family", FcElementFamily },
426 { "selectfont", FcElementSelectfont },
427 { "acceptfont", FcElementAcceptfont },
428 { "rejectfont", FcElementRejectfont },
429 { "glob", FcElementGlob },
430 { "pattern", FcElementPattern },
431 { "patelt", FcElementPatelt },
433 { "test", FcElementTest },
434 { "edit", FcElementEdit },
435 { "int", FcElementInt },
436 { "double", FcElementDouble },
437 { "string", FcElementString },
438 { "matrix", FcElementMatrix },
439 { "range", FcElementRange },
440 { "bool", FcElementBool },
441 { "charset", FcElementCharSet },
442 { "langset", FcElementLangSet },
443 { "name", FcElementName },
444 { "const", FcElementConst },
445 { "or", FcElementOr },
446 { "and", FcElementAnd },
447 { "eq", FcElementEq },
448 { "not_eq", FcElementNotEq },
449 { "less", FcElementLess },
450 { "less_eq", FcElementLessEq },
451 { "more", FcElementMore },
452 { "more_eq", FcElementMoreEq },
453 { "contains", FcElementContains },
454 { "not_contains", FcElementNotContains },
455 { "plus", FcElementPlus },
456 { "minus", FcElementMinus },
457 { "times", FcElementTimes },
458 { "divide", FcElementDivide },
459 { "not", FcElementNot },
460 { "if", FcElementIf },
461 { "floor", FcElementFloor },
462 { "ceil", FcElementCeil },
463 { "round", FcElementRound },
464 { "trunc", FcElementTrunc },
466 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
469 FcElementMap (const XML_Char *name)
473 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
474 if (!strcmp ((char *) name, fcElementMap[i].name))
475 return fcElementMap[i].element;
476 return FcElementUnknown;
479 typedef struct _FcPStack {
480 struct _FcPStack *prev;
484 FcChar8 *attr_buf_static[16];
487 typedef enum _FcVStackTag {
514 typedef struct _FcVStack {
515 struct _FcVStack *prev;
516 FcPStack *pstack; /* related parse element */
523 FcExprMatrix *matrix;
540 typedef struct _FcConfigParse {
547 unsigned int pstack_static_used;
548 FcPStack pstack_static[8];
549 unsigned int vstack_static_used;
550 FcVStack vstack_static[64];
553 typedef enum _FcConfigSeverity {
554 FcSevereInfo, FcSevereWarning, FcSevereError
558 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
560 const char *s = "unknown";
563 va_start (args, fmt);
566 case FcSevereInfo: s = "info"; break;
567 case FcSevereWarning: s = "warning"; break;
568 case FcSevereError: s = "error"; break;
573 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
574 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
576 fprintf (stderr, "Fontconfig %s: line %d: ", s,
577 (int)XML_GetCurrentLineNumber (parse->parser));
578 if (severe >= FcSevereError)
579 parse->error = FcTrue;
582 fprintf (stderr, "Fontconfig %s: ", s);
583 vfprintf (stderr, fmt, args);
584 fprintf (stderr, "\n");
590 FcPopExpr (FcConfigParse *parse);
594 FcTypeName (FcType type)
623 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
625 if (value == FcTypeInteger)
626 value = FcTypeDouble;
627 if (type == FcTypeInteger)
631 if ((value == FcTypeLangSet && type == FcTypeString) ||
632 (value == FcTypeString && type == FcTypeLangSet) ||
633 (value == FcTypeInteger && type == FcTypeRange) ||
634 (value == FcTypeDouble && type == FcTypeRange))
636 if (type == FcTypeUnknown)
638 /* It's perfectly fine to use user-define elements in expressions,
639 * so don't warn in that case. */
640 if (value == FcTypeUnknown)
642 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
643 FcTypeName (value), FcTypeName (type));
648 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
650 const FcObjectType *o;
653 /* If parsing the expression failed, some nodes may be NULL */
657 switch (FC_OP_GET_OP (expr->op)) {
660 FcTypecheckValue (parse, FcTypeDouble, type);
663 FcTypecheckValue (parse, FcTypeString, type);
666 FcTypecheckValue (parse, FcTypeMatrix, type);
669 FcTypecheckValue (parse, FcTypeBool, type);
672 FcTypecheckValue (parse, FcTypeCharSet, type);
675 FcTypecheckValue (parse, FcTypeLangSet, type);
678 FcTypecheckValue (parse, FcTypeRange, type);
683 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
685 FcTypecheckValue (parse, o->type, type);
688 c = FcNameGetConstant (expr->u.constant);
691 o = FcNameGetObjectType (c->object);
693 FcTypecheckValue (parse, o->type, type);
696 FcConfigMessage (parse, FcSevereWarning,
697 "invalid constant used : %s",
701 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
702 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
703 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
706 case FcOpAssignReplace:
715 case FcOpNotContains:
717 FcTypecheckValue (parse, FcTypeBool, type);
726 FcTypecheckExpr (parse, expr->u.tree.left, type);
727 FcTypecheckExpr (parse, expr->u.tree.right, type);
730 FcTypecheckValue (parse, FcTypeBool, type);
731 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
737 FcTypecheckValue (parse, FcTypeDouble, type);
738 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
746 FcTestCreate (FcConfigParse *parse,
749 const FcChar8 *field,
750 unsigned int compare,
753 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
757 const FcObjectType *o;
761 test->object = FcObjectFromName ((const char *) field);
764 o = FcNameGetObjectType (FcObjectName (test->object));
766 FcTypecheckExpr (parse, expr, o->type);
772 FcEditCreate (FcConfigParse *parse,
776 FcValueBinding binding)
778 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
782 const FcObjectType *o;
787 e->binding = binding;
788 o = FcNameGetObjectType (FcObjectName (e->object));
790 FcTypecheckExpr (parse, expr, o->type);
796 FcRuleCreate (FcRuleType type,
799 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
809 r->u.test = (FcTest *) p;
812 r->u.edit = (FcEdit *) p;
825 FcVStackCreateAndPush (FcConfigParse *parse)
829 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
830 new = &parse->vstack_static[parse->vstack_static_used++];
833 new = malloc (sizeof (FcVStack));
837 new->tag = FcVStackNone;
840 new->prev = parse->vstack;
841 new->pstack = parse->pstack ? parse->pstack->prev : 0;
848 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
850 FcVStack *vstack = FcVStackCreateAndPush (parse);
853 vstack->u.string = string;
859 FcVStackPushInteger (FcConfigParse *parse, int integer)
861 FcVStack *vstack = FcVStackCreateAndPush (parse);
864 vstack->u.integer = integer;
865 vstack->tag = FcVStackInteger;
870 FcVStackPushDouble (FcConfigParse *parse, double _double)
872 FcVStack *vstack = FcVStackCreateAndPush (parse);
875 vstack->u._double = _double;
876 vstack->tag = FcVStackDouble;
881 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
884 vstack = FcVStackCreateAndPush (parse);
887 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
888 vstack->tag = FcVStackMatrix;
893 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
895 FcVStack *vstack = FcVStackCreateAndPush (parse);
898 vstack->u.range = range;
899 vstack->tag = FcVStackRange;
904 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
906 FcVStack *vstack = FcVStackCreateAndPush (parse);
909 vstack->u.bool_ = bool_;
910 vstack->tag = FcVStackBool;
915 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
920 vstack = FcVStackCreateAndPush (parse);
923 vstack->u.charset = charset;
924 vstack->tag = FcVStackCharSet;
929 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
934 vstack = FcVStackCreateAndPush (parse);
937 vstack->u.langset = langset;
938 vstack->tag = FcVStackLangSet;
943 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
945 FcVStack *vstack = FcVStackCreateAndPush (parse);
948 vstack->u.name.object = object;
949 vstack->u.name.kind = kind;
950 vstack->tag = FcVStackName;
955 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
957 FcVStack *vstack = FcVStackCreateAndPush (parse);
960 vstack->u.test = test;
961 vstack->tag = FcVStackTest;
966 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
968 FcVStack *vstack = FcVStackCreateAndPush (parse);
971 vstack->u.expr = expr;
977 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
979 FcVStack *vstack = FcVStackCreateAndPush (parse);
982 vstack->u.edit = edit;
983 vstack->tag = FcVStackEdit;
988 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
990 FcVStack *vstack = FcVStackCreateAndPush (parse);
993 vstack->u.pattern = pattern;
994 vstack->tag = FcVStackPattern;
999 FcVStackFetch (FcConfigParse *parse, int off)
1003 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
1008 FcVStackPeek (FcConfigParse *parse)
1010 FcVStack *vstack = parse->vstack;
1012 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1016 FcVStackPopAndDestroy (FcConfigParse *parse)
1018 FcVStack *vstack = parse->vstack;
1020 if (!vstack || vstack->pstack != parse->pstack)
1023 parse->vstack = vstack->prev;
1025 switch (vstack->tag) {
1030 case FcVStackFamily:
1032 case FcVStackString:
1033 case FcVStackConstant:
1035 FcStrFree (vstack->u.string);
1037 case FcVStackPattern:
1038 FcPatternDestroy (vstack->u.pattern);
1040 case FcVStackInteger:
1041 case FcVStackDouble:
1043 case FcVStackMatrix:
1044 FcExprMatrixFreeShallow (vstack->u.matrix);
1049 FcRangeDestroy (vstack->u.range);
1051 case FcVStackCharSet:
1052 FcCharSetDestroy (vstack->u.charset);
1054 case FcVStackLangSet:
1055 FcLangSetDestroy (vstack->u.langset);
1058 FcTestDestroy (vstack->u.test);
1061 case FcVStackPrefer:
1062 case FcVStackAccept:
1063 case FcVStackDefault:
1064 FcExprDestroy (vstack->u.expr);
1067 FcEditDestroy (vstack->u.edit);
1071 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1072 parse->vstack_static_used--;
1078 FcVStackClear (FcConfigParse *parse)
1080 while (FcVStackPeek (parse))
1081 FcVStackPopAndDestroy (parse);
1085 FcVStackElements (FcConfigParse *parse)
1088 FcVStack *vstack = parse->vstack;
1089 while (vstack && vstack->pstack == parse->pstack)
1092 vstack = vstack->prev;
1098 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1108 for (i = 0; attr[i]; i++)
1109 slen += strlen ((char *) attr[i]) + 1;
1112 slen += (i + 1) * sizeof (FcChar8 *);
1113 if (slen <= size_bytes)
1117 new = malloc (slen);
1120 FcConfigMessage (0, FcSevereError, "out of memory");
1124 s = (FcChar8 *) (new + (i + 1));
1125 for (i = 0; attr[i]; i++)
1128 strcpy ((char *) s, (char *) attr[i]);
1129 s += strlen ((char *) s) + 1;
1136 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1140 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1141 new = &parse->pstack_static[parse->pstack_static_used++];
1144 new = malloc (sizeof (FcPStack));
1149 new->prev = parse->pstack;
1150 new->element = element;
1151 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1152 FcStrBufInit (&new->str, 0, 0);
1153 parse->pstack = new;
1158 FcPStackPop (FcConfigParse *parse)
1164 FcConfigMessage (parse, FcSevereError, "mismatching element");
1168 if (parse->pstack->attr)
1170 /* Warn about unused attrs. */
1171 FcChar8 **attrs = parse->pstack->attr;
1176 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1182 FcVStackClear (parse);
1183 old = parse->pstack;
1184 parse->pstack = old->prev;
1185 FcStrBufDestroy (&old->str);
1187 if (old->attr && old->attr != old->attr_buf_static)
1190 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1191 parse->pstack_static_used--;
1198 FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1201 parse->pstack_static_used = 0;
1203 parse->vstack_static_used = 0;
1204 parse->error = FcFalse;
1206 parse->config = config;
1207 parse->parser = parser;
1212 FcConfigCleanup (FcConfigParse *parse)
1214 while (parse->pstack)
1215 FcPStackPop (parse);
1218 static const FcChar8 *
1219 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1225 attrs = parse->pstack->attr;
1231 if (!strcmp ((char *) *attrs, attr))
1233 attrs[0][0] = '\0'; /* Mark as used. */
1242 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1244 FcConfigParse *parse = userData;
1247 element = FcElementMap (name);
1248 if (element == FcElementUnknown)
1249 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1251 if (!FcPStackPush (parse, element, attr))
1253 FcConfigMessage (parse, FcSevereError, "out of memory");
1260 FcParseBlank (FcConfigParse *parse)
1262 int n = FcVStackElements (parse);
1264 FcChar32 i, begin, end;
1267 FcConfigMessage (parse, FcSevereWarning, "blank doesn't take any effect anymore. please remove it from your fonts.conf");
1270 FcVStack *v = FcVStackFetch (parse, n);
1271 if (!parse->config->blanks)
1273 parse->config->blanks = FcBlanksCreate ();
1274 if (!parse->config->blanks)
1277 switch ((int) v->tag) {
1278 case FcVStackInteger:
1280 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1286 begin = (FcChar32) v->u.range->begin;
1287 end = (FcChar32) v->u.range->end;
1290 for (i = begin; i <= end; i++)
1292 if (!FcBlanksAdd (parse->config->blanks, i))
1299 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1305 FcConfigMessage (parse, FcSevereError, "out of memory");
1309 FcParseRescan (FcConfigParse *parse)
1311 int n = FcVStackElements (parse);
1314 FcVStack *v = FcVStackFetch (parse, n);
1315 if (v->tag != FcVStackInteger)
1316 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1318 parse->config->rescanInterval = v->u.integer;
1323 FcParseInt (FcConfigParse *parse)
1330 s = FcStrBufDoneStatic (&parse->pstack->str);
1333 FcConfigMessage (parse, FcSevereError, "out of memory");
1337 l = (int) strtol ((char *) s, (char **)&end, 0);
1338 if (end != s + strlen ((char *) s))
1339 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1341 FcVStackPushInteger (parse, l);
1342 FcStrBufDestroy (&parse->pstack->str);
1346 * idea copied from glib g_ascii_strtod with
1347 * permission of the author (Alexander Larsson)
1353 FcStrtod (char *s, char **end)
1356 struct lconv *locale_data;
1358 const char *decimal_point;
1364 * Have to swap the decimal point to match the current locale
1365 * if that locale doesn't use 0x2e
1368 locale_data = localeconv ();
1369 decimal_point = locale_data->decimal_point;
1370 dlen = strlen (decimal_point);
1372 decimal_point = ".";
1376 if ((dot = strchr (s, 0x2e)) &&
1377 (decimal_point[0] != 0x2e ||
1378 decimal_point[1] != 0))
1381 int slen = strlen (s);
1383 if (slen + dlen > (int) sizeof (buf))
1393 strncpy (buf, s, dot - s);
1395 strcpy (buf + (dot - s), decimal_point);
1396 /* rest of number */
1397 strcpy (buf + (dot - s) + dlen, dot + 1);
1399 v = strtod (buf, &buf_end);
1401 buf_end = s + (buf_end - buf);
1403 buf_end -= dlen - 1;
1410 v = strtod (s, end);
1415 FcParseDouble (FcConfigParse *parse)
1422 s = FcStrBufDoneStatic (&parse->pstack->str);
1425 FcConfigMessage (parse, FcSevereError, "out of memory");
1429 d = FcStrtod ((char *) s, (char **)&end);
1430 if (end != s + strlen ((char *) s))
1431 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1433 FcVStackPushDouble (parse, d);
1434 FcStrBufDestroy (&parse->pstack->str);
1438 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1444 s = FcStrBufDone (&parse->pstack->str);
1447 FcConfigMessage (parse, FcSevereError, "out of memory");
1450 if (!FcVStackPushString (parse, tag, s))
1455 FcParseName (FcConfigParse *parse)
1457 const FcChar8 *kind_string;
1462 kind_string = FcConfigGetAttribute (parse, "target");
1464 kind = FcMatchDefault;
1467 if (!strcmp ((char *) kind_string, "pattern"))
1468 kind = FcMatchPattern;
1469 else if (!strcmp ((char *) kind_string, "font"))
1471 else if (!strcmp ((char *) kind_string, "default"))
1472 kind = FcMatchDefault;
1475 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1482 s = FcStrBufDone (&parse->pstack->str);
1485 FcConfigMessage (parse, FcSevereError, "out of memory");
1488 object = FcObjectFromName ((const char *) s);
1490 FcVStackPushName (parse, kind, object);
1496 FcParseMatrix (FcConfigParse *parse)
1500 m.yy = FcPopExpr (parse);
1501 m.yx = FcPopExpr (parse);
1502 m.xy = FcPopExpr (parse);
1503 m.xx = FcPopExpr (parse);
1505 if (FcPopExpr (parse))
1506 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1508 FcVStackPushMatrix (parse, &m);
1512 FcParseRange (FcConfigParse *parse)
1516 FcChar32 n[2] = {0, 0};
1518 double d[2] = {0.0L, 0.0L};
1519 FcBool dflag = FcFalse;
1521 while ((vstack = FcVStackPeek (parse)))
1525 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1528 switch ((int) vstack->tag) {
1529 case FcVStackInteger:
1531 d[count] = (double)vstack->u.integer;
1533 n[count] = vstack->u.integer;
1535 case FcVStackDouble:
1536 if (count == 0 && !dflag)
1537 d[1] = (double)n[1];
1538 d[count] = vstack->u._double;
1542 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1550 FcVStackPopAndDestroy (parse);
1554 FcConfigMessage (parse, FcSevereError, "invalid range");
1561 FcConfigMessage (parse, FcSevereError, "invalid range");
1564 r = FcRangeCreateDouble (d[0], d[1]);
1570 FcConfigMessage (parse, FcSevereError, "invalid range");
1573 r = FcRangeCreateInteger (n[0], n[1]);
1575 FcVStackPushRange (parse, r);
1579 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1581 FcBool result = FcFalse;
1583 if (!FcNameBool (bool_, &result))
1584 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1590 FcParseBool (FcConfigParse *parse)
1596 s = FcStrBufDoneStatic (&parse->pstack->str);
1599 FcConfigMessage (parse, FcSevereError, "out of memory");
1602 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1603 FcStrBufDestroy (&parse->pstack->str);
1607 FcParseCharSet (FcConfigParse *parse)
1610 FcCharSet *charset = FcCharSetCreate ();
1611 FcChar32 i, begin, end;
1614 while ((vstack = FcVStackPeek (parse)))
1616 switch ((int) vstack->tag) {
1617 case FcVStackInteger:
1618 if (!FcCharSetAddChar (charset, vstack->u.integer))
1620 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1626 begin = (FcChar32) vstack->u.range->begin;
1627 end = (FcChar32) vstack->u.range->end;
1631 for (i = begin; i <= end; i++)
1633 if (!FcCharSetAddChar (charset, i))
1635 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1643 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1646 FcVStackPopAndDestroy (parse);
1649 FcVStackPushCharSet (parse, charset);
1651 FcCharSetDestroy (charset);
1655 FcParseLangSet (FcConfigParse *parse)
1658 FcLangSet *langset = FcLangSetCreate ();
1661 while ((vstack = FcVStackPeek (parse)))
1663 switch ((int) vstack->tag) {
1664 case FcVStackString:
1665 if (!FcLangSetAdd (langset, vstack->u.string))
1667 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1673 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1676 FcVStackPopAndDestroy (parse);
1679 FcVStackPushLangSet (parse, langset);
1681 FcLangSetDestroy (langset);
1685 FcConfigLexBinding (FcConfigParse *parse,
1686 const FcChar8 *binding_string,
1687 FcValueBinding *binding_ret)
1689 FcValueBinding binding;
1691 if (!binding_string)
1692 binding = FcValueBindingWeak;
1695 if (!strcmp ((char *) binding_string, "weak"))
1696 binding = FcValueBindingWeak;
1697 else if (!strcmp ((char *) binding_string, "strong"))
1698 binding = FcValueBindingStrong;
1699 else if (!strcmp ((char *) binding_string, "same"))
1700 binding = FcValueBindingSame;
1703 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1707 *binding_ret = binding;
1712 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1715 FcExpr *left, *expr = 0, *new;
1717 while ((vstack = FcVStackPeek (parse)))
1719 if (vstack->tag != FcVStackFamily)
1721 FcConfigMessage (parse, FcSevereWarning, "non-family");
1722 FcVStackPopAndDestroy (parse);
1725 left = vstack->u.expr;
1726 vstack->tag = FcVStackNone;
1727 FcVStackPopAndDestroy (parse);
1730 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1733 FcConfigMessage (parse, FcSevereError, "out of memory");
1734 FcExprDestroy (left);
1735 FcExprDestroy (expr);
1745 if (!FcVStackPushExpr (parse, tag, expr))
1747 FcConfigMessage (parse, FcSevereError, "out of memory");
1748 FcExprDestroy (expr);
1754 FcParseFamily (FcConfigParse *parse)
1761 s = FcStrBufDoneStatic (&parse->pstack->str);
1764 FcConfigMessage (parse, FcSevereError, "out of memory");
1767 expr = FcExprCreateString (parse->config, s);
1768 FcStrBufDestroy (&parse->pstack->str);
1770 FcVStackPushExpr (parse, FcVStackFamily, expr);
1774 FcParseAlias (FcConfigParse *parse)
1776 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1779 FcRule *rule = NULL, *r;
1780 FcValueBinding binding;
1782 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1784 while ((vstack = FcVStackPeek (parse)))
1786 switch ((int) vstack->tag) {
1787 case FcVStackFamily:
1790 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1791 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1793 FcConfigMessage (parse, FcSevereError, "out of memory");
1798 new = vstack->u.expr;
1802 vstack->tag = FcVStackNone;
1805 case FcVStackPrefer:
1807 FcExprDestroy (prefer);
1808 prefer = vstack->u.expr;
1809 vstack->tag = FcVStackNone;
1811 case FcVStackAccept:
1813 FcExprDestroy (accept);
1814 accept = vstack->u.expr;
1815 vstack->tag = FcVStackNone;
1817 case FcVStackDefault:
1819 FcExprDestroy (def);
1820 def = vstack->u.expr;
1821 vstack->tag = FcVStackNone;
1826 r = FcRuleCreate (FcRuleTest, vstack->u.test);
1831 rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1832 vstack->tag = FcVStackNone;
1835 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1838 FcVStackPopAndDestroy (parse);
1842 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1844 FcExprDestroy (prefer);
1846 FcExprDestroy (accept);
1848 FcExprDestroy (def);
1850 FcRuleDestroy (rule);
1857 FcExprDestroy (family);
1862 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1864 (FcChar8 *) FC_FAMILY,
1865 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1869 for (r = rule; r->next; r = r->next);
1870 r->next = FcRuleCreate (FcRuleTest, t);
1875 r = rule = FcRuleCreate (FcRuleTest, t);
1880 edit = FcEditCreate (parse,
1886 FcExprDestroy (prefer);
1889 r->next = FcRuleCreate (FcRuleEdit, edit);
1895 edit = FcEditCreate (parse,
1901 FcExprDestroy (accept);
1904 r->next = FcRuleCreate (FcRuleEdit, edit);
1910 edit = FcEditCreate (parse,
1916 FcExprDestroy (def);
1919 r->next = FcRuleCreate (FcRuleEdit, edit);
1923 if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
1924 FcRuleDestroy (rule);
1928 FcPopExpr (FcConfigParse *parse)
1930 FcVStack *vstack = FcVStackPeek (parse);
1934 switch ((int) vstack->tag) {
1937 case FcVStackString:
1938 case FcVStackFamily:
1939 expr = FcExprCreateString (parse->config, vstack->u.string);
1942 expr = FcExprCreateName (parse->config, vstack->u.name);
1944 case FcVStackConstant:
1945 expr = FcExprCreateConst (parse->config, vstack->u.string);
1948 /* XXX: What's the correct action here? (CDW) */
1950 case FcVStackPrefer:
1951 case FcVStackAccept:
1952 case FcVStackDefault:
1953 expr = vstack->u.expr;
1954 vstack->tag = FcVStackNone;
1956 case FcVStackInteger:
1957 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1959 case FcVStackDouble:
1960 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1962 case FcVStackMatrix:
1963 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1966 expr = FcExprCreateRange (parse->config, vstack->u.range);
1969 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1971 case FcVStackCharSet:
1972 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1974 case FcVStackLangSet:
1975 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1980 expr = vstack->u.expr;
1981 vstack->tag = FcVStackNone;
1988 FcVStackPopAndDestroy (parse);
1993 * This builds a tree of binary operations. Note
1994 * that every operator is defined so that if only
1995 * a single operand is contained, the value of the
1996 * whole expression is the value of the operand.
1998 * This code reduces in that case to returning that
2002 FcPopBinary (FcConfigParse *parse, FcOp op)
2004 FcExpr *left, *expr = 0, *new;
2006 while ((left = FcPopExpr (parse)))
2010 new = FcExprCreateOp (parse->config, left, op, expr);
2013 FcConfigMessage (parse, FcSevereError, "out of memory");
2014 FcExprDestroy (left);
2015 FcExprDestroy (expr);
2027 FcParseBinary (FcConfigParse *parse, FcOp op)
2029 FcExpr *expr = FcPopBinary (parse, op);
2031 FcVStackPushExpr (parse, FcVStackExpr, expr);
2035 * This builds a a unary operator, it consumes only
2040 FcPopUnary (FcConfigParse *parse, FcOp op)
2042 FcExpr *operand, *new = 0;
2044 if ((operand = FcPopExpr (parse)))
2046 new = FcExprCreateOp (parse->config, operand, op, 0);
2049 FcExprDestroy (operand);
2050 FcConfigMessage (parse, FcSevereError, "out of memory");
2057 FcParseUnary (FcConfigParse *parse, FcOp op)
2059 FcExpr *expr = FcPopUnary (parse, op);
2061 FcVStackPushExpr (parse, FcVStackExpr, expr);
2065 FcParseDir (FcConfigParse *parse)
2067 const FcChar8 *attr, *data;
2068 FcChar8 *prefix = NULL, *p;
2070 FcChar8 buffer[1000];
2073 attr = FcConfigGetAttribute (parse, "prefix");
2074 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2076 prefix = FcConfigXdgDataHome ();
2077 /* home directory might be disabled.
2078 * simply ignore this element.
2083 data = FcStrBufDoneStatic (&parse->pstack->str);
2086 FcConfigMessage (parse, FcSevereError, "out of memory");
2092 size_t plen = strlen ((const char *)prefix);
2093 size_t dlen = strlen ((const char *)data);
2095 p = realloc (prefix, plen + 1 + dlen + 1);
2098 FcConfigMessage (parse, FcSevereError, "out of memory");
2102 prefix[plen] = FC_DIR_SEPARATOR;
2103 memcpy (&prefix[plen + 1], data, dlen);
2104 prefix[plen + 1 + dlen] = 0;
2108 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2112 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2114 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2118 * Must use the multi-byte aware function to search
2119 * for backslash because East Asian double-byte code
2120 * pages have characters with backslash as the second
2123 p = _mbsrchr (data, '\\');
2125 strcat ((char *) data, "\\fonts");
2127 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2131 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2133 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2136 p = _mbsrchr (data, '\\');
2138 strcat ((char *) data, "\\..\\share\\fonts");
2140 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2144 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2145 if (rc == 0 || rc > sizeof (buffer) - 20)
2147 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2150 if (data [strlen ((const char *) data) - 1] != '\\')
2151 strcat ((char *) data, "\\");
2152 strcat ((char *) data, "fonts");
2155 if (strlen ((char *) data) == 0)
2156 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2157 else if (!FcStrUsesHome (data) || FcConfigHome ())
2159 if (!FcConfigAddDir (parse->config, data))
2160 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2162 FcStrBufDestroy (&parse->pstack->str);
2170 FcParseCacheDir (FcConfigParse *parse)
2172 const FcChar8 *attr;
2173 FcChar8 *prefix = NULL, *p, *data = NULL;
2175 attr = FcConfigGetAttribute (parse, "prefix");
2176 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2178 prefix = FcConfigXdgCacheHome ();
2179 /* home directory might be disabled.
2180 * simply ignore this element.
2185 data = FcStrBufDone (&parse->pstack->str);
2188 FcConfigMessage (parse, FcSevereError, "out of memory");
2193 size_t plen = strlen ((const char *)prefix);
2194 size_t dlen = strlen ((const char *)data);
2196 p = realloc (prefix, plen + 1 + dlen + 1);
2199 FcConfigMessage (parse, FcSevereError, "out of memory");
2204 prefix[plen] = FC_DIR_SEPARATOR;
2205 memcpy (&prefix[plen + 1], data, dlen);
2206 prefix[plen + 1 + dlen] = 0;
2211 else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2213 size_t plen = strlen ((const char *)fontconfig_instprefix);
2214 size_t dlen = strlen ((const char *)data);
2216 prefix = malloc (plen + 1 + dlen + 1);
2219 FcConfigMessage (parse, FcSevereError, "out of memory");
2222 strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2223 prefix[plen] = FC_DIR_SEPARATOR;
2224 memcpy (&prefix[plen + 1], data, dlen);
2225 prefix[plen + 1 + dlen] = 0;
2229 else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2233 data = malloc (1000);
2236 FcConfigMessage (parse, FcSevereError, "out of memory");
2239 rc = GetTempPath (800, (LPSTR) data);
2240 if (rc == 0 || rc > 800)
2242 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2245 if (data [strlen ((const char *) data) - 1] != '\\')
2246 strcat ((char *) data, "\\");
2247 strcat ((char *) data, "fontconfig\\cache");
2249 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2251 char szFPath[MAX_PATH + 1];
2254 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2256 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2259 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2260 len = strlen(szFPath) + 1;
2265 FcConfigMessage (parse, FcSevereError, "out of memory");
2268 strncpy((char *) data, szFPath, len);
2271 if (strlen ((char *) data) == 0)
2272 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2273 else if (!FcStrUsesHome (data) || FcConfigHome ())
2275 if (!FcConfigAddCacheDir (parse->config, data))
2276 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2278 FcStrBufDestroy (&parse->pstack->str);
2286 FcConfigPathFini (void)
2291 s = fc_atomic_ptr_get (&__fc_userdir);
2292 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2297 s = fc_atomic_ptr_get (&__fc_userconf);
2298 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2304 FcParseInclude (FcConfigParse *parse)
2307 const FcChar8 *attr;
2308 FcBool ignore_missing = FcFalse;
2310 FcBool deprecated = FcFalse;
2312 FcChar8 *prefix = NULL, *p;
2313 FcChar8 *userdir = NULL, *userconf = NULL;
2315 s = FcStrBufDoneStatic (&parse->pstack->str);
2318 FcConfigMessage (parse, FcSevereError, "out of memory");
2321 attr = FcConfigGetAttribute (parse, "ignore_missing");
2322 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2323 ignore_missing = FcTrue;
2324 attr = FcConfigGetAttribute (parse, "deprecated");
2326 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2327 deprecated = FcTrue;
2329 attr = FcConfigGetAttribute (parse, "prefix");
2330 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2332 prefix = FcConfigXdgConfigHome ();
2333 /* home directory might be disabled.
2334 * simply ignore this element.
2341 size_t plen = strlen ((const char *)prefix);
2342 size_t dlen = strlen ((const char *)s);
2345 p = realloc (prefix, plen + 1 + dlen + 1);
2348 FcConfigMessage (parse, FcSevereError, "out of memory");
2352 prefix[plen] = FC_DIR_SEPARATOR;
2353 memcpy (&prefix[plen + 1], s, dlen);
2354 prefix[plen + 1 + dlen] = 0;
2356 if (FcFileIsDir (s))
2359 userdir = fc_atomic_ptr_get (&__fc_userdir);
2363 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2371 else if (FcFileIsFile (s))
2374 userconf = fc_atomic_ptr_get (&__fc_userconf);
2378 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2388 /* No config dir nor file on the XDG directory spec compliant place
2389 * so need to guess what it is supposed to be.
2391 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2397 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2398 parse->error = FcTrue;
2403 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2405 filename = FcConfigFilename(s);
2406 if (deprecated == FcTrue &&
2409 !FcFileIsLink (filename))
2411 if (FcFileIsDir (filename))
2413 FcChar8 *parent = FcStrDirname (userdir);
2415 if (!FcFileIsDir (parent))
2416 FcMakeDirectory (parent);
2418 if (FcFileIsDir (userdir) ||
2419 rename ((const char *)filename, (const char *)userdir) != 0 ||
2420 symlink ((const char *)userdir, (const char *)filename) != 0)
2424 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2425 warn_confd = FcTrue;
2431 FcChar8 *parent = FcStrDirname (userconf);
2433 if (!FcFileIsDir (parent))
2434 FcMakeDirectory (parent);
2436 if (FcFileIsFile (userconf) ||
2437 rename ((const char *)filename, (const char *)userconf) != 0 ||
2438 symlink ((const char *)userconf, (const char *)filename) != 0)
2442 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2449 FcStrFree(filename);
2452 FcStrBufDestroy (&parse->pstack->str);
2459 typedef struct _FcOpMap {
2465 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2469 for (i = 0; i < nmap; i++)
2470 if (!strcmp ((char *) op, map[i].name))
2475 static const FcOpMap fcCompareOps[] = {
2476 { "eq", FcOpEqual },
2477 { "not_eq", FcOpNotEqual },
2478 { "less", FcOpLess },
2479 { "less_eq", FcOpLessEqual },
2480 { "more", FcOpMore },
2481 { "more_eq", FcOpMoreEqual },
2482 { "contains", FcOpContains },
2483 { "not_contains", FcOpNotContains }
2486 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2489 FcConfigLexCompare (const FcChar8 *compare)
2491 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2495 FcParseTest (FcConfigParse *parse)
2497 const FcChar8 *kind_string;
2499 const FcChar8 *qual_string;
2501 const FcChar8 *name;
2502 const FcChar8 *compare_string;
2506 const FcChar8 *iblanks_string;
2509 kind_string = FcConfigGetAttribute (parse, "target");
2511 kind = FcMatchDefault;
2514 if (!strcmp ((char *) kind_string, "pattern"))
2515 kind = FcMatchPattern;
2516 else if (!strcmp ((char *) kind_string, "font"))
2518 else if (!strcmp ((char *) kind_string, "scan"))
2520 else if (!strcmp ((char *) kind_string, "default"))
2521 kind = FcMatchDefault;
2524 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2528 qual_string = FcConfigGetAttribute (parse, "qual");
2533 if (!strcmp ((char *) qual_string, "any"))
2535 else if (!strcmp ((char *) qual_string, "all"))
2537 else if (!strcmp ((char *) qual_string, "first"))
2539 else if (!strcmp ((char *) qual_string, "not_first"))
2540 qual = FcQualNotFirst;
2543 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2547 name = FcConfigGetAttribute (parse, "name");
2550 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2553 compare_string = FcConfigGetAttribute (parse, "compare");
2554 if (!compare_string)
2555 compare = FcOpEqual;
2558 compare = FcConfigLexCompare (compare_string);
2559 if (compare == FcOpInvalid)
2561 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2565 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2570 if (!FcNameBool (iblanks_string, &f))
2572 FcConfigMessage (parse,
2574 "invalid test ignore-blanks \"%s\"", iblanks_string);
2577 flags |= FcOpFlagIgnoreBlanks;
2579 expr = FcPopBinary (parse, FcOpComma);
2582 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2585 if (expr->op == FcOpComma)
2587 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2589 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2592 FcConfigMessage (parse, FcSevereError, "out of memory");
2595 FcVStackPushTest (parse, test);
2598 static const FcOpMap fcModeOps[] = {
2599 { "assign", FcOpAssign },
2600 { "assign_replace", FcOpAssignReplace },
2601 { "prepend", FcOpPrepend },
2602 { "prepend_first", FcOpPrependFirst },
2603 { "append", FcOpAppend },
2604 { "append_last", FcOpAppendLast },
2605 { "delete", FcOpDelete },
2606 { "delete_all", FcOpDeleteAll },
2609 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2612 FcConfigLexMode (const FcChar8 *mode)
2614 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2618 FcParseEdit (FcConfigParse *parse)
2620 const FcChar8 *name;
2621 const FcChar8 *mode_string;
2623 FcValueBinding binding;
2627 name = FcConfigGetAttribute (parse, "name");
2630 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2633 mode_string = FcConfigGetAttribute (parse, "mode");
2638 mode = FcConfigLexMode (mode_string);
2639 if (mode == FcOpInvalid)
2641 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2645 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2648 expr = FcPopBinary (parse, FcOpComma);
2649 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2652 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2653 FcExprDestroy (expr);
2656 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2657 mode, expr, binding);
2660 FcConfigMessage (parse, FcSevereError, "out of memory");
2661 FcExprDestroy (expr);
2664 if (!FcVStackPushEdit (parse, edit))
2665 FcEditDestroy (edit);
2669 FcParseMatch (FcConfigParse *parse)
2671 const FcChar8 *kind_name;
2674 FcRule *rule = NULL, *r;
2676 kind_name = FcConfigGetAttribute (parse, "target");
2678 kind = FcMatchPattern;
2681 if (!strcmp ((char *) kind_name, "pattern"))
2682 kind = FcMatchPattern;
2683 else if (!strcmp ((char *) kind_name, "font"))
2685 else if (!strcmp ((char *) kind_name, "scan"))
2689 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2693 while ((vstack = FcVStackPeek (parse)))
2695 switch ((int) vstack->tag) {
2697 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2701 vstack->tag = FcVStackNone;
2704 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2706 FcConfigMessage (parse, FcSevereError,
2707 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2708 FcObjectName(vstack->u.edit->object));
2710 FcRuleDestroy (rule);
2713 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2717 vstack->tag = FcVStackNone;
2720 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2723 FcVStackPopAndDestroy (parse);
2727 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2730 if (!FcConfigAddRule (parse->config, rule, kind))
2731 FcConfigMessage (parse, FcSevereError, "out of memory");
2735 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2739 while ((vstack = FcVStackPeek (parse)))
2741 switch ((int) vstack->tag) {
2743 if (!FcConfigGlobAdd (parse->config,
2745 element == FcElementAcceptfont))
2747 FcConfigMessage (parse, FcSevereError, "out of memory");
2750 case FcVStackPattern:
2751 if (!FcConfigPatternsAdd (parse->config,
2753 element == FcElementAcceptfont))
2755 FcConfigMessage (parse, FcSevereError, "out of memory");
2758 vstack->tag = FcVStackNone;
2761 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2764 FcVStackPopAndDestroy (parse);
2770 FcPopValue (FcConfigParse *parse)
2772 FcVStack *vstack = FcVStackPeek (parse);
2775 value.type = FcTypeVoid;
2780 switch ((int) vstack->tag) {
2781 case FcVStackString:
2782 value.u.s = FcStrdup (vstack->u.string);
2784 value.type = FcTypeString;
2786 case FcVStackConstant:
2787 if (FcNameConstant (vstack->u.string, &value.u.i))
2788 value.type = FcTypeInteger;
2790 case FcVStackInteger:
2791 value.u.i = vstack->u.integer;
2792 value.type = FcTypeInteger;
2794 case FcVStackDouble:
2795 value.u.d = vstack->u._double;
2796 value.type = FcTypeDouble;
2799 value.u.b = vstack->u.bool_;
2800 value.type = FcTypeBool;
2802 case FcVStackCharSet:
2803 value.u.c = FcCharSetCopy (vstack->u.charset);
2805 value.type = FcTypeCharSet;
2807 case FcVStackLangSet:
2808 value.u.l = FcLangSetCopy (vstack->u.langset);
2810 value.type = FcTypeLangSet;
2813 value.u.r = FcRangeCopy (vstack->u.range);
2815 value.type = FcTypeRange;
2818 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2822 FcVStackPopAndDestroy (parse);
2828 FcParsePatelt (FcConfigParse *parse)
2831 FcPattern *pattern = FcPatternCreate ();
2836 FcConfigMessage (parse, FcSevereError, "out of memory");
2840 name = (char *) FcConfigGetAttribute (parse, "name");
2843 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2844 FcPatternDestroy (pattern);
2850 value = FcPopValue (parse);
2851 if (value.type == FcTypeVoid)
2853 if (!FcPatternAdd (pattern, name, value, FcTrue))
2855 FcConfigMessage (parse, FcSevereError, "out of memory");
2856 FcValueDestroy(value);
2859 FcValueDestroy(value);
2862 FcVStackPushPattern (parse, pattern);
2866 FcParsePattern (FcConfigParse *parse)
2869 FcPattern *pattern = FcPatternCreate ();
2873 FcConfigMessage (parse, FcSevereError, "out of memory");
2877 while ((vstack = FcVStackPeek (parse)))
2879 switch ((int) vstack->tag) {
2880 case FcVStackPattern:
2881 if (!FcPatternAppend (pattern, vstack->u.pattern))
2883 FcConfigMessage (parse, FcSevereError, "out of memory");
2884 FcPatternDestroy (pattern);
2889 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2892 FcVStackPopAndDestroy (parse);
2895 FcVStackPushPattern (parse, pattern);
2899 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2901 FcConfigParse *parse = userData;
2906 switch (parse->pstack->element) {
2909 case FcElementFontconfig:
2914 case FcElementCacheDir:
2915 FcParseCacheDir (parse);
2917 case FcElementCache:
2918 data = FcStrBufDoneStatic (&parse->pstack->str);
2921 FcConfigMessage (parse, FcSevereError, "out of memory");
2924 /* discard this data; no longer used */
2925 FcStrBufDestroy (&parse->pstack->str);
2927 case FcElementInclude:
2928 FcParseInclude (parse);
2930 case FcElementConfig:
2932 case FcElementMatch:
2933 FcParseMatch (parse);
2935 case FcElementAlias:
2936 FcParseAlias (parse);
2939 case FcElementBlank:
2940 FcParseBlank (parse);
2942 case FcElementRescan:
2943 FcParseRescan (parse);
2946 case FcElementPrefer:
2947 FcParseFamilies (parse, FcVStackPrefer);
2949 case FcElementAccept:
2950 FcParseFamilies (parse, FcVStackAccept);
2952 case FcElementDefault:
2953 FcParseFamilies (parse, FcVStackDefault);
2955 case FcElementFamily:
2956 FcParseFamily (parse);
2960 FcParseTest (parse);
2963 FcParseEdit (parse);
2969 case FcElementDouble:
2970 FcParseDouble (parse);
2972 case FcElementString:
2973 FcParseString (parse, FcVStackString);
2975 case FcElementMatrix:
2976 FcParseMatrix (parse);
2978 case FcElementRange:
2979 FcParseRange (parse);
2982 FcParseBool (parse);
2984 case FcElementCharSet:
2985 FcParseCharSet (parse);
2987 case FcElementLangSet:
2988 FcParseLangSet (parse);
2990 case FcElementSelectfont:
2992 case FcElementAcceptfont:
2993 case FcElementRejectfont:
2994 FcParseAcceptRejectFont (parse, parse->pstack->element);
2997 FcParseString (parse, FcVStackGlob);
2999 case FcElementPattern:
3000 FcParsePattern (parse);
3002 case FcElementPatelt:
3003 FcParsePatelt (parse);
3006 FcParseName (parse);
3008 case FcElementConst:
3009 FcParseString (parse, FcVStackConstant);
3012 FcParseBinary (parse, FcOpOr);
3015 FcParseBinary (parse, FcOpAnd);
3018 FcParseBinary (parse, FcOpEqual);
3020 case FcElementNotEq:
3021 FcParseBinary (parse, FcOpNotEqual);
3024 FcParseBinary (parse, FcOpLess);
3026 case FcElementLessEq:
3027 FcParseBinary (parse, FcOpLessEqual);
3030 FcParseBinary (parse, FcOpMore);
3032 case FcElementMoreEq:
3033 FcParseBinary (parse, FcOpMoreEqual);
3035 case FcElementContains:
3036 FcParseBinary (parse, FcOpContains);
3038 case FcElementNotContains:
3039 FcParseBinary (parse, FcOpNotContains);
3042 FcParseBinary (parse, FcOpPlus);
3044 case FcElementMinus:
3045 FcParseBinary (parse, FcOpMinus);
3047 case FcElementTimes:
3048 FcParseBinary (parse, FcOpTimes);
3050 case FcElementDivide:
3051 FcParseBinary (parse, FcOpDivide);
3054 FcParseUnary (parse, FcOpNot);
3057 FcParseBinary (parse, FcOpQuest);
3059 case FcElementFloor:
3060 FcParseUnary (parse, FcOpFloor);
3063 FcParseUnary (parse, FcOpCeil);
3065 case FcElementRound:
3066 FcParseUnary (parse, FcOpRound);
3068 case FcElementTrunc:
3069 FcParseUnary (parse, FcOpTrunc);
3071 case FcElementUnknown:
3074 (void) FcPStackPop (parse);
3078 FcCharacterData (void *userData, const XML_Char *s, int len)
3080 FcConfigParse *parse = userData;
3084 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
3085 FcConfigMessage (parse, FcSevereError, "out of memory");
3089 FcStartDoctypeDecl (void *userData,
3090 const XML_Char *doctypeName,
3091 const XML_Char *sysid FC_UNUSED,
3092 const XML_Char *pubid FC_UNUSED,
3093 int has_internal_subset FC_UNUSED)
3095 FcConfigParse *parse = userData;
3097 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
3098 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3101 #ifdef ENABLE_LIBXML2
3104 FcInternalSubsetDecl (void *userData,
3105 const XML_Char *doctypeName,
3106 const XML_Char *sysid,
3107 const XML_Char *pubid)
3109 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3113 FcExternalSubsetDecl (void *userData,
3114 const XML_Char *doctypeName,
3115 const XML_Char *sysid,
3116 const XML_Char *pubid)
3118 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3121 #else /* ENABLE_LIBXML2 */
3124 FcEndDoctypeDecl (void *userData FC_UNUSED)
3128 #endif /* ENABLE_LIBXML2 */
3131 FcSortCmpStr (const void *a, const void *b)
3133 const FcChar8 *as = *((FcChar8 **) a);
3134 const FcChar8 *bs = *((FcChar8 **) b);
3135 return FcStrCmp (as, bs);
3139 FcConfigParseAndLoadDir (FcConfig *config,
3140 const FcChar8 *name,
3146 FcBool ret = FcTrue;
3151 d = opendir ((char *) dir);
3155 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3161 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3168 strcpy ((char *) file, (char *) dir);
3169 strcat ((char *) file, "/");
3170 base = file + strlen ((char *) file);
3172 files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3179 if (FcDebug () & FC_DBG_CONFIG)
3180 printf ("\tScanning config dir %s\n", dir);
3182 while (ret && (e = readdir (d)))
3185 #define TAIL ".conf"
3188 * Add all files of the form [0-9]*.conf
3190 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3191 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3193 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3195 strcpy ((char *) base, (char *) e->d_name);
3196 if (!FcStrSetAdd (files, file))
3206 qsort (files->strs, files->num, sizeof (FcChar8 *),
3207 (int (*)(const void *, const void *)) FcSortCmpStr);
3208 for (i = 0; ret && i < files->num; i++)
3209 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
3212 FcStrSetDestroy (files);
3218 return ret || !complain;
3222 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3223 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3227 FcConfigParseAndLoad (FcConfig *config,
3228 const FcChar8 *name,
3233 FcChar8 *filename, *f;
3236 FcConfigParse parse;
3237 FcBool error = FcTrue;
3238 const FcChar8 *sysroot = FcConfigGetSysRoot (config);
3240 #ifdef ENABLE_LIBXML2
3248 if (!pGetSystemWindowsDirectory)
3250 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3251 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3252 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3254 if (!pSHGetFolderPathA)
3256 HMODULE hSh = LoadLibraryA("shfolder.dll");
3257 /* the check is done later, because there is no provided fallback */
3259 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3263 f = FcConfigFilename (name);
3267 filename = FcStrBuildFilename (sysroot, f, NULL);
3269 filename = FcStrdup (f);
3272 if (FcStrSetMember (config->configFiles, filename))
3274 FcStrFree (filename);
3278 if (!FcStrSetAdd (config->configFiles, filename))
3280 FcStrFree (filename);
3284 if (FcFileIsDir (filename))
3286 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
3287 FcStrFree (filename);
3291 if (FcDebug () & FC_DBG_CONFIG)
3292 printf ("\tLoading config file %s\n", filename);
3294 fd = FcOpen ((char *) filename, O_RDONLY);
3296 FcStrFree (filename);
3300 #ifdef ENABLE_LIBXML2
3301 memset(&sax, 0, sizeof(sax));
3303 sax.internalSubset = FcInternalSubsetDecl;
3304 sax.externalSubset = FcExternalSubsetDecl;
3305 sax.startElement = FcStartElement;
3306 sax.endElement = FcEndElement;
3307 sax.characters = FcCharacterData;
3309 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3311 p = XML_ParserCreate ("UTF-8");
3313 FcStrFree (filename);
3318 if (!FcConfigParseInit (&parse, name, config, p))
3321 #ifndef ENABLE_LIBXML2
3323 XML_SetUserData (p, &parse);
3325 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3326 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3327 XML_SetCharacterDataHandler (p, FcCharacterData);
3329 #endif /* ENABLE_LIBXML2 */
3332 #ifndef ENABLE_LIBXML2
3333 buf = XML_GetBuffer (p, BUFSIZ);
3336 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3340 len = read (fd, buf, BUFSIZ);
3343 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3347 #ifdef ENABLE_LIBXML2
3348 if (xmlParseChunk (p, buf, len, len == 0))
3350 if (!XML_ParseBuffer (p, len, len == 0))
3353 FcConfigMessage (&parse, FcSevereError, "%s",
3354 XML_ErrorString (XML_GetErrorCode (p)));
3358 error = parse.error;
3360 FcConfigCleanup (&parse);
3367 if (error && complain)
3370 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3372 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3378 #include "fcaliastail.h"