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 */
60 FcExprDestroy (FcExpr *e);
63 FcTestDestroy (FcTest *test)
65 FcExprDestroy (test->expr);
70 FcRuleDestroy (FcRule *rule)
72 FcRule *n = rule->next;
76 FcTestDestroy (rule->u.test);
79 FcEditDestroy (rule->u.edit);
90 FcExprCreateInteger (FcConfig *config, int i)
92 FcExpr *e = FcConfigAllocExpr (config);
102 FcExprCreateDouble (FcConfig *config, double d)
104 FcExpr *e = FcConfigAllocExpr (config);
114 FcExprCreateString (FcConfig *config, const FcChar8 *s)
116 FcExpr *e = FcConfigAllocExpr (config);
120 e->u.sval = FcStrdup (s);
125 static FcExprMatrix *
126 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
128 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
137 FcExprMatrixFreeShallow (FcExprMatrix *m)
146 FcExprMatrixFree (FcExprMatrix *m)
151 FcExprDestroy (m->xx);
152 FcExprDestroy (m->xy);
153 FcExprDestroy (m->yx);
154 FcExprDestroy (m->yy);
160 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
162 FcExpr *e = FcConfigAllocExpr (config);
166 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
172 FcExprCreateRange (FcConfig *config, FcRange *range)
174 FcExpr *e = FcConfigAllocExpr (config);
178 e->u.rval = FcRangeCopy (range);
184 FcExprCreateBool (FcConfig *config, FcBool b)
186 FcExpr *e = FcConfigAllocExpr (config);
196 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
198 FcExpr *e = FcConfigAllocExpr (config);
202 e->u.cval = FcCharSetCopy (charset);
208 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
210 FcExpr *e = FcConfigAllocExpr (config);
214 e->u.lval = FcLangSetCopy (langset);
220 FcExprCreateName (FcConfig *config, FcExprName name)
222 FcExpr *e = FcConfigAllocExpr (config);
232 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
234 FcExpr *e = FcConfigAllocExpr (config);
238 e->u.constant = FcStrdup (constant);
244 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
246 FcExpr *e = FcConfigAllocExpr (config);
250 e->u.tree.left = left;
251 e->u.tree.right = right;
257 FcExprDestroy (FcExpr *e)
261 switch (FC_OP_GET_OP (e->op)) {
270 FcExprMatrixFree (e->u.mexpr);
273 FcRangeDestroy (e->u.rval);
276 FcCharSetDestroy (e->u.cval);
279 FcLangSetDestroy (e->u.lval);
286 FcFree (e->u.constant);
289 case FcOpAssignReplace:
291 case FcOpPrependFirst:
307 case FcOpNotContains:
314 FcExprDestroy (e->u.tree.right);
321 FcExprDestroy (e->u.tree.left);
332 FcEditDestroy (FcEdit *e)
335 FcExprDestroy (e->expr);
339 typedef enum _FcElement {
386 FcElementNotContains,
400 static const struct {
404 { "fontconfig", FcElementFontconfig },
405 { "dir", FcElementDir },
406 { "cachedir", FcElementCacheDir },
407 { "cache", FcElementCache },
408 { "include", FcElementInclude },
409 { "config", FcElementConfig },
410 { "match", FcElementMatch },
411 { "alias", FcElementAlias },
413 { "blank", FcElementBlank },
414 { "rescan", FcElementRescan },
416 { "prefer", FcElementPrefer },
417 { "accept", FcElementAccept },
418 { "default", FcElementDefault },
419 { "family", FcElementFamily },
421 { "selectfont", FcElementSelectfont },
422 { "acceptfont", FcElementAcceptfont },
423 { "rejectfont", FcElementRejectfont },
424 { "glob", FcElementGlob },
425 { "pattern", FcElementPattern },
426 { "patelt", FcElementPatelt },
428 { "test", FcElementTest },
429 { "edit", FcElementEdit },
430 { "int", FcElementInt },
431 { "double", FcElementDouble },
432 { "string", FcElementString },
433 { "matrix", FcElementMatrix },
434 { "range", FcElementRange },
435 { "bool", FcElementBool },
436 { "charset", FcElementCharSet },
437 { "langset", FcElementLangSet },
438 { "name", FcElementName },
439 { "const", FcElementConst },
440 { "or", FcElementOr },
441 { "and", FcElementAnd },
442 { "eq", FcElementEq },
443 { "not_eq", FcElementNotEq },
444 { "less", FcElementLess },
445 { "less_eq", FcElementLessEq },
446 { "more", FcElementMore },
447 { "more_eq", FcElementMoreEq },
448 { "contains", FcElementContains },
449 { "not_contains", FcElementNotContains },
450 { "plus", FcElementPlus },
451 { "minus", FcElementMinus },
452 { "times", FcElementTimes },
453 { "divide", FcElementDivide },
454 { "not", FcElementNot },
455 { "if", FcElementIf },
456 { "floor", FcElementFloor },
457 { "ceil", FcElementCeil },
458 { "round", FcElementRound },
459 { "trunc", FcElementTrunc },
461 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
464 FcElementMap (const XML_Char *name)
468 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
469 if (!strcmp ((char *) name, fcElementMap[i].name))
470 return fcElementMap[i].element;
471 return FcElementUnknown;
474 typedef struct _FcPStack {
475 struct _FcPStack *prev;
479 FcChar8 *attr_buf_static[16];
482 typedef enum _FcVStackTag {
509 typedef struct _FcVStack {
510 struct _FcVStack *prev;
511 FcPStack *pstack; /* related parse element */
518 FcExprMatrix *matrix;
535 typedef struct _FcConfigParse {
542 unsigned int pstack_static_used;
543 FcPStack pstack_static[8];
544 unsigned int vstack_static_used;
545 FcVStack vstack_static[64];
548 typedef enum _FcConfigSeverity {
549 FcSevereInfo, FcSevereWarning, FcSevereError
553 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
555 const char *s = "unknown";
558 va_start (args, fmt);
561 case FcSevereInfo: s = "info"; break;
562 case FcSevereWarning: s = "warning"; break;
563 case FcSevereError: s = "error"; break;
568 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
569 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
571 fprintf (stderr, "Fontconfig %s: line %d: ", s,
572 (int)XML_GetCurrentLineNumber (parse->parser));
573 if (severe >= FcSevereError)
574 parse->error = FcTrue;
577 fprintf (stderr, "Fontconfig %s: ", s);
578 vfprintf (stderr, fmt, args);
579 fprintf (stderr, "\n");
585 FcPopExpr (FcConfigParse *parse);
589 FcTypeName (FcType type)
617 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
619 if (value == FcTypeInteger)
620 value = FcTypeDouble;
621 if (type == FcTypeInteger)
625 if ((value == FcTypeLangSet && type == FcTypeString) ||
626 (value == FcTypeString && type == FcTypeLangSet) ||
627 (value == FcTypeInteger && type == FcTypeRange) ||
628 (value == FcTypeDouble && type == FcTypeRange))
630 if (type == FcTypeUnknown)
632 /* It's perfectly fine to use user-define elements in expressions,
633 * so don't warn in that case. */
634 if (value == FcTypeUnknown)
636 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
637 FcTypeName (value), FcTypeName (type));
642 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
644 const FcObjectType *o;
647 /* If parsing the expression failed, some nodes may be NULL */
651 switch (FC_OP_GET_OP (expr->op)) {
654 FcTypecheckValue (parse, FcTypeDouble, type);
657 FcTypecheckValue (parse, FcTypeString, type);
660 FcTypecheckValue (parse, FcTypeMatrix, type);
663 FcTypecheckValue (parse, FcTypeBool, type);
666 FcTypecheckValue (parse, FcTypeCharSet, type);
669 FcTypecheckValue (parse, FcTypeLangSet, type);
672 FcTypecheckValue (parse, FcTypeRange, type);
677 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
679 FcTypecheckValue (parse, o->type, type);
682 c = FcNameGetConstant (expr->u.constant);
685 o = FcNameGetObjectType (c->object);
687 FcTypecheckValue (parse, o->type, type);
690 FcConfigMessage (parse, FcSevereWarning,
691 "invalid constant used : %s",
695 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
696 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
697 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
700 case FcOpAssignReplace:
709 case FcOpNotContains:
711 FcTypecheckValue (parse, FcTypeBool, type);
720 FcTypecheckExpr (parse, expr->u.tree.left, type);
721 FcTypecheckExpr (parse, expr->u.tree.right, type);
724 FcTypecheckValue (parse, FcTypeBool, type);
725 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
731 FcTypecheckValue (parse, FcTypeDouble, type);
732 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
740 FcTestCreate (FcConfigParse *parse,
743 const FcChar8 *field,
744 unsigned int compare,
747 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
751 const FcObjectType *o;
755 test->object = FcObjectFromName ((const char *) field);
758 o = FcNameGetObjectType (FcObjectName (test->object));
760 FcTypecheckExpr (parse, expr, o->type);
766 FcEditCreate (FcConfigParse *parse,
770 FcValueBinding binding)
772 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
776 const FcObjectType *o;
781 e->binding = binding;
782 o = FcNameGetObjectType (FcObjectName (e->object));
784 FcTypecheckExpr (parse, expr, o->type);
790 FcRuleCreate (FcRuleType type,
793 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
803 r->u.test = (FcTest *) p;
806 r->u.edit = (FcEdit *) p;
818 FcVStackCreateAndPush (FcConfigParse *parse)
822 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
823 new = &parse->vstack_static[parse->vstack_static_used++];
826 new = malloc (sizeof (FcVStack));
830 new->tag = FcVStackNone;
833 new->prev = parse->vstack;
834 new->pstack = parse->pstack ? parse->pstack->prev : 0;
841 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
843 FcVStack *vstack = FcVStackCreateAndPush (parse);
846 vstack->u.string = string;
852 FcVStackPushInteger (FcConfigParse *parse, int integer)
854 FcVStack *vstack = FcVStackCreateAndPush (parse);
857 vstack->u.integer = integer;
858 vstack->tag = FcVStackInteger;
863 FcVStackPushDouble (FcConfigParse *parse, double _double)
865 FcVStack *vstack = FcVStackCreateAndPush (parse);
868 vstack->u._double = _double;
869 vstack->tag = FcVStackDouble;
874 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
877 vstack = FcVStackCreateAndPush (parse);
880 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
881 vstack->tag = FcVStackMatrix;
886 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
888 FcVStack *vstack = FcVStackCreateAndPush (parse);
891 vstack->u.range = range;
892 vstack->tag = FcVStackRange;
897 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
899 FcVStack *vstack = FcVStackCreateAndPush (parse);
902 vstack->u.bool_ = bool_;
903 vstack->tag = FcVStackBool;
908 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
913 vstack = FcVStackCreateAndPush (parse);
916 vstack->u.charset = charset;
917 vstack->tag = FcVStackCharSet;
922 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
927 vstack = FcVStackCreateAndPush (parse);
930 vstack->u.langset = langset;
931 vstack->tag = FcVStackLangSet;
936 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
938 FcVStack *vstack = FcVStackCreateAndPush (parse);
941 vstack->u.name.object = object;
942 vstack->u.name.kind = kind;
943 vstack->tag = FcVStackName;
948 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
950 FcVStack *vstack = FcVStackCreateAndPush (parse);
953 vstack->u.test = test;
954 vstack->tag = FcVStackTest;
959 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
961 FcVStack *vstack = FcVStackCreateAndPush (parse);
964 vstack->u.expr = expr;
970 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
972 FcVStack *vstack = FcVStackCreateAndPush (parse);
975 vstack->u.edit = edit;
976 vstack->tag = FcVStackEdit;
981 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
983 FcVStack *vstack = FcVStackCreateAndPush (parse);
986 vstack->u.pattern = pattern;
987 vstack->tag = FcVStackPattern;
992 FcVStackFetch (FcConfigParse *parse, int off)
996 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
1001 FcVStackPeek (FcConfigParse *parse)
1003 FcVStack *vstack = parse->vstack;
1005 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1009 FcVStackPopAndDestroy (FcConfigParse *parse)
1011 FcVStack *vstack = parse->vstack;
1013 if (!vstack || vstack->pstack != parse->pstack)
1016 parse->vstack = vstack->prev;
1018 switch (vstack->tag) {
1023 case FcVStackFamily:
1025 case FcVStackString:
1026 case FcVStackConstant:
1028 FcStrFree (vstack->u.string);
1030 case FcVStackPattern:
1031 FcPatternDestroy (vstack->u.pattern);
1033 case FcVStackInteger:
1034 case FcVStackDouble:
1036 case FcVStackMatrix:
1037 FcExprMatrixFreeShallow (vstack->u.matrix);
1042 FcRangeDestroy (vstack->u.range);
1044 case FcVStackCharSet:
1045 FcCharSetDestroy (vstack->u.charset);
1047 case FcVStackLangSet:
1048 FcLangSetDestroy (vstack->u.langset);
1051 FcTestDestroy (vstack->u.test);
1054 case FcVStackPrefer:
1055 case FcVStackAccept:
1056 case FcVStackDefault:
1057 FcExprDestroy (vstack->u.expr);
1060 FcEditDestroy (vstack->u.edit);
1064 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1065 parse->vstack_static_used--;
1071 FcVStackClear (FcConfigParse *parse)
1073 while (FcVStackPeek (parse))
1074 FcVStackPopAndDestroy (parse);
1078 FcVStackElements (FcConfigParse *parse)
1081 FcVStack *vstack = parse->vstack;
1082 while (vstack && vstack->pstack == parse->pstack)
1085 vstack = vstack->prev;
1091 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1101 for (i = 0; attr[i]; i++)
1102 slen += strlen ((char *) attr[i]) + 1;
1105 slen += (i + 1) * sizeof (FcChar8 *);
1106 if (slen <= size_bytes)
1110 new = malloc (slen);
1113 FcConfigMessage (0, FcSevereError, "out of memory");
1117 s = (FcChar8 *) (new + (i + 1));
1118 for (i = 0; attr[i]; i++)
1121 strcpy ((char *) s, (char *) attr[i]);
1122 s += strlen ((char *) s) + 1;
1129 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1133 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1134 new = &parse->pstack_static[parse->pstack_static_used++];
1137 new = malloc (sizeof (FcPStack));
1142 new->prev = parse->pstack;
1143 new->element = element;
1144 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1145 FcStrBufInit (&new->str, 0, 0);
1146 parse->pstack = new;
1151 FcPStackPop (FcConfigParse *parse)
1157 FcConfigMessage (parse, FcSevereError, "mismatching element");
1161 if (parse->pstack->attr)
1163 /* Warn about unused attrs. */
1164 FcChar8 **attrs = parse->pstack->attr;
1169 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1175 FcVStackClear (parse);
1176 old = parse->pstack;
1177 parse->pstack = old->prev;
1178 FcStrBufDestroy (&old->str);
1180 if (old->attr && old->attr != old->attr_buf_static)
1183 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1184 parse->pstack_static_used--;
1191 FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1194 parse->pstack_static_used = 0;
1196 parse->vstack_static_used = 0;
1197 parse->error = FcFalse;
1199 parse->config = config;
1200 parse->parser = parser;
1205 FcConfigCleanup (FcConfigParse *parse)
1207 while (parse->pstack)
1208 FcPStackPop (parse);
1211 static const FcChar8 *
1212 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1218 attrs = parse->pstack->attr;
1224 if (!strcmp ((char *) *attrs, attr))
1226 attrs[0][0] = '\0'; /* Mark as used. */
1235 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1237 FcConfigParse *parse = userData;
1240 element = FcElementMap (name);
1241 if (element == FcElementUnknown)
1242 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1244 if (!FcPStackPush (parse, element, attr))
1246 FcConfigMessage (parse, FcSevereError, "out of memory");
1253 FcParseBlank (FcConfigParse *parse)
1255 int n = FcVStackElements (parse);
1256 FcChar32 i, begin, end;
1261 FcVStack *v = FcVStackFetch (parse, n);
1262 if (!parse->config->blanks)
1264 parse->config->blanks = FcBlanksCreate ();
1265 if (!parse->config->blanks)
1268 switch ((int) v->tag) {
1269 case FcVStackInteger:
1270 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1274 r = FcRangeCanonicalize (v->u.range);
1275 begin = (FcChar32)r.u.d.begin;
1276 end = (FcChar32)r.u.d.end;
1279 for (i = begin; i <= end; i++)
1281 if (!FcBlanksAdd (parse->config->blanks, i))
1287 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1293 FcConfigMessage (parse, FcSevereError, "out of memory");
1297 FcParseRescan (FcConfigParse *parse)
1299 int n = FcVStackElements (parse);
1302 FcVStack *v = FcVStackFetch (parse, n);
1303 if (v->tag != FcVStackInteger)
1304 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1306 parse->config->rescanInterval = v->u.integer;
1311 FcParseInt (FcConfigParse *parse)
1318 s = FcStrBufDoneStatic (&parse->pstack->str);
1321 FcConfigMessage (parse, FcSevereError, "out of memory");
1325 l = (int) strtol ((char *) s, (char **)&end, 0);
1326 if (end != s + strlen ((char *) s))
1327 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1329 FcVStackPushInteger (parse, l);
1330 FcStrBufDestroy (&parse->pstack->str);
1334 * idea copied from glib g_ascii_strtod with
1335 * permission of the author (Alexander Larsson)
1341 FcStrtod (char *s, char **end)
1343 struct lconv *locale_data;
1348 * Have to swap the decimal point to match the current locale
1349 * if that locale doesn't use 0x2e
1351 if ((dot = strchr (s, 0x2e)) &&
1352 (locale_data = localeconv ()) &&
1353 (locale_data->decimal_point[0] != 0x2e ||
1354 locale_data->decimal_point[1] != 0))
1357 int slen = strlen (s);
1358 int dlen = strlen (locale_data->decimal_point);
1360 if (slen + dlen > (int) sizeof (buf))
1370 strncpy (buf, s, dot - s);
1372 strcpy (buf + (dot - s), locale_data->decimal_point);
1373 /* rest of number */
1374 strcpy (buf + (dot - s) + dlen, dot + 1);
1376 v = strtod (buf, &buf_end);
1378 buf_end = s + (buf_end - buf);
1380 buf_end -= dlen - 1;
1387 v = strtod (s, end);
1392 FcParseDouble (FcConfigParse *parse)
1399 s = FcStrBufDoneStatic (&parse->pstack->str);
1402 FcConfigMessage (parse, FcSevereError, "out of memory");
1406 d = FcStrtod ((char *) s, (char **)&end);
1407 if (end != s + strlen ((char *) s))
1408 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1410 FcVStackPushDouble (parse, d);
1411 FcStrBufDestroy (&parse->pstack->str);
1415 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1421 s = FcStrBufDone (&parse->pstack->str);
1424 FcConfigMessage (parse, FcSevereError, "out of memory");
1427 if (!FcVStackPushString (parse, tag, s))
1432 FcParseName (FcConfigParse *parse)
1434 const FcChar8 *kind_string;
1439 kind_string = FcConfigGetAttribute (parse, "target");
1441 kind = FcMatchDefault;
1444 if (!strcmp ((char *) kind_string, "pattern"))
1445 kind = FcMatchPattern;
1446 else if (!strcmp ((char *) kind_string, "font"))
1448 else if (!strcmp ((char *) kind_string, "default"))
1449 kind = FcMatchDefault;
1452 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1459 s = FcStrBufDone (&parse->pstack->str);
1462 FcConfigMessage (parse, FcSevereError, "out of memory");
1465 object = FcObjectFromName ((const char *) s);
1467 FcVStackPushName (parse, kind, object);
1473 FcParseMatrix (FcConfigParse *parse)
1477 m.yy = FcPopExpr (parse);
1478 m.yx = FcPopExpr (parse);
1479 m.xy = FcPopExpr (parse);
1480 m.xx = FcPopExpr (parse);
1482 if (FcPopExpr (parse))
1483 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1485 FcVStackPushMatrix (parse, &m);
1489 FcParseRange (FcConfigParse *parse)
1493 FcChar32 n[2] = {0, 0};
1495 double d[2] = {0.0L, 0.0L};
1496 FcBool dflag = FcFalse;
1498 while ((vstack = FcVStackPeek (parse)))
1502 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1505 switch ((int) vstack->tag) {
1506 case FcVStackInteger:
1508 d[count] = (double)vstack->u.integer;
1510 n[count] = vstack->u.integer;
1512 case FcVStackDouble:
1513 if (count == 0 && !dflag)
1514 d[1] = (double)n[1];
1515 d[count] = vstack->u._double;
1519 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1527 FcVStackPopAndDestroy (parse);
1531 FcConfigMessage (parse, FcSevereError, "invalid range");
1538 FcConfigMessage (parse, FcSevereError, "invalid range");
1541 r = FcRangeCreateDouble (d[0], d[1]);
1547 FcConfigMessage (parse, FcSevereError, "invalid range");
1550 r = FcRangeCreateInteger (n[0], n[1]);
1552 FcVStackPushRange (parse, r);
1556 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1558 FcBool result = FcFalse;
1560 if (!FcNameBool (bool_, &result))
1561 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1567 FcParseBool (FcConfigParse *parse)
1573 s = FcStrBufDoneStatic (&parse->pstack->str);
1576 FcConfigMessage (parse, FcSevereError, "out of memory");
1579 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1580 FcStrBufDestroy (&parse->pstack->str);
1584 FcParseCharSet (FcConfigParse *parse)
1587 FcCharSet *charset = FcCharSetCreate ();
1588 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 r = FcRangeCanonicalize (vstack->u.range);
1605 begin = (FcChar32)r.u.d.begin;
1606 end = (FcChar32)r.u.d.end;
1610 for (i = begin; i <= end; i++)
1612 if (!FcCharSetAddChar (charset, i))
1614 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1622 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1625 FcVStackPopAndDestroy (parse);
1628 FcVStackPushCharSet (parse, charset);
1630 FcCharSetDestroy (charset);
1634 FcParseLangSet (FcConfigParse *parse)
1637 FcLangSet *langset = FcLangSetCreate ();
1640 while ((vstack = FcVStackPeek (parse)))
1642 switch ((int) vstack->tag) {
1643 case FcVStackString:
1644 if (!FcLangSetAdd (langset, vstack->u.string))
1646 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1652 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1655 FcVStackPopAndDestroy (parse);
1658 FcVStackPushLangSet (parse, langset);
1660 FcLangSetDestroy (langset);
1664 FcConfigLexBinding (FcConfigParse *parse,
1665 const FcChar8 *binding_string,
1666 FcValueBinding *binding_ret)
1668 FcValueBinding binding;
1670 if (!binding_string)
1671 binding = FcValueBindingWeak;
1674 if (!strcmp ((char *) binding_string, "weak"))
1675 binding = FcValueBindingWeak;
1676 else if (!strcmp ((char *) binding_string, "strong"))
1677 binding = FcValueBindingStrong;
1678 else if (!strcmp ((char *) binding_string, "same"))
1679 binding = FcValueBindingSame;
1682 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1686 *binding_ret = binding;
1691 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1694 FcExpr *left, *expr = 0, *new;
1696 while ((vstack = FcVStackPeek (parse)))
1698 if (vstack->tag != FcVStackFamily)
1700 FcConfigMessage (parse, FcSevereWarning, "non-family");
1701 FcVStackPopAndDestroy (parse);
1704 left = vstack->u.expr;
1705 vstack->tag = FcVStackNone;
1706 FcVStackPopAndDestroy (parse);
1709 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1712 FcConfigMessage (parse, FcSevereError, "out of memory");
1713 FcExprDestroy (left);
1714 FcExprDestroy (expr);
1724 if (!FcVStackPushExpr (parse, tag, expr))
1726 FcConfigMessage (parse, FcSevereError, "out of memory");
1727 FcExprDestroy (expr);
1733 FcParseFamily (FcConfigParse *parse)
1740 s = FcStrBufDoneStatic (&parse->pstack->str);
1743 FcConfigMessage (parse, FcSevereError, "out of memory");
1746 expr = FcExprCreateString (parse->config, s);
1747 FcStrBufDestroy (&parse->pstack->str);
1749 FcVStackPushExpr (parse, FcVStackFamily, expr);
1753 FcParseAlias (FcConfigParse *parse)
1755 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1758 FcRule *rule = NULL, *r;
1759 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);
1841 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1843 (FcChar8 *) FC_FAMILY,
1844 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1848 for (r = rule; r->next; r = r->next);
1849 r->next = FcRuleCreate (FcRuleTest, t);
1854 r = rule = FcRuleCreate (FcRuleTest, t);
1859 edit = FcEditCreate (parse,
1865 FcExprDestroy (prefer);
1868 r->next = FcRuleCreate (FcRuleEdit, edit);
1874 edit = FcEditCreate (parse,
1880 FcExprDestroy (accept);
1883 r->next = FcRuleCreate (FcRuleEdit, edit);
1889 edit = FcEditCreate (parse,
1895 FcExprDestroy (def);
1898 r->next = FcRuleCreate (FcRuleEdit, edit);
1902 if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
1903 FcRuleDestroy (rule);
1907 FcPopExpr (FcConfigParse *parse)
1909 FcVStack *vstack = FcVStackPeek (parse);
1913 switch ((int) vstack->tag) {
1916 case FcVStackString:
1917 case FcVStackFamily:
1918 expr = FcExprCreateString (parse->config, vstack->u.string);
1921 expr = FcExprCreateName (parse->config, vstack->u.name);
1923 case FcVStackConstant:
1924 expr = FcExprCreateConst (parse->config, vstack->u.string);
1927 /* XXX: What's the correct action here? (CDW) */
1929 case FcVStackPrefer:
1930 case FcVStackAccept:
1931 case FcVStackDefault:
1932 expr = vstack->u.expr;
1933 vstack->tag = FcVStackNone;
1935 case FcVStackInteger:
1936 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1938 case FcVStackDouble:
1939 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1941 case FcVStackMatrix:
1942 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1945 expr = FcExprCreateRange (parse->config, vstack->u.range);
1948 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1950 case FcVStackCharSet:
1951 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1953 case FcVStackLangSet:
1954 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1959 expr = vstack->u.expr;
1960 vstack->tag = FcVStackNone;
1967 FcVStackPopAndDestroy (parse);
1972 * This builds a tree of binary operations. Note
1973 * that every operator is defined so that if only
1974 * a single operand is contained, the value of the
1975 * whole expression is the value of the operand.
1977 * This code reduces in that case to returning that
1981 FcPopBinary (FcConfigParse *parse, FcOp op)
1983 FcExpr *left, *expr = 0, *new;
1985 while ((left = FcPopExpr (parse)))
1989 new = FcExprCreateOp (parse->config, left, op, expr);
1992 FcConfigMessage (parse, FcSevereError, "out of memory");
1993 FcExprDestroy (left);
1994 FcExprDestroy (expr);
2006 FcParseBinary (FcConfigParse *parse, FcOp op)
2008 FcExpr *expr = FcPopBinary (parse, op);
2010 FcVStackPushExpr (parse, FcVStackExpr, expr);
2014 * This builds a a unary operator, it consumes only
2019 FcPopUnary (FcConfigParse *parse, FcOp op)
2021 FcExpr *operand, *new = 0;
2023 if ((operand = FcPopExpr (parse)))
2025 new = FcExprCreateOp (parse->config, operand, op, 0);
2028 FcExprDestroy (operand);
2029 FcConfigMessage (parse, FcSevereError, "out of memory");
2036 FcParseUnary (FcConfigParse *parse, FcOp op)
2038 FcExpr *expr = FcPopUnary (parse, op);
2040 FcVStackPushExpr (parse, FcVStackExpr, expr);
2044 FcParseDir (FcConfigParse *parse)
2046 const FcChar8 *attr, *data;
2047 FcChar8 *prefix = NULL, *p;
2049 FcChar8 buffer[1000];
2052 attr = FcConfigGetAttribute (parse, "prefix");
2053 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2055 prefix = FcConfigXdgDataHome ();
2056 /* home directory might be disabled.
2057 * simply ignore this element.
2062 data = FcStrBufDoneStatic (&parse->pstack->str);
2065 FcConfigMessage (parse, FcSevereError, "out of memory");
2071 size_t plen = strlen ((const char *)prefix);
2072 size_t dlen = strlen ((const char *)data);
2074 p = realloc (prefix, plen + 1 + dlen + 1);
2077 FcConfigMessage (parse, FcSevereError, "out of memory");
2081 prefix[plen] = FC_DIR_SEPARATOR;
2082 memcpy (&prefix[plen + 1], data, dlen);
2083 prefix[plen + 1 + dlen] = 0;
2087 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2091 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2093 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2097 * Must use the multi-byte aware function to search
2098 * for backslash because East Asian double-byte code
2099 * pages have characters with backslash as the second
2102 p = _mbsrchr (data, '\\');
2104 strcat ((char *) data, "\\fonts");
2106 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2110 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2112 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2115 p = _mbsrchr (data, '\\');
2117 strcat ((char *) data, "\\..\\share\\fonts");
2119 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2123 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2124 if (rc == 0 || rc > sizeof (buffer) - 20)
2126 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2129 if (data [strlen ((const char *) data) - 1] != '\\')
2130 strcat ((char *) data, "\\");
2131 strcat ((char *) data, "fonts");
2134 if (strlen ((char *) data) == 0)
2135 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2136 else if (!FcStrUsesHome (data) || FcConfigHome ())
2138 if (!FcConfigAddDir (parse->config, data))
2139 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2141 FcStrBufDestroy (&parse->pstack->str);
2149 FcParseCacheDir (FcConfigParse *parse)
2151 const FcChar8 *attr;
2152 FcChar8 *prefix = NULL, *p, *data = NULL;
2154 attr = FcConfigGetAttribute (parse, "prefix");
2155 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2157 prefix = FcConfigXdgCacheHome ();
2158 /* home directory might be disabled.
2159 * simply ignore this element.
2164 data = FcStrBufDone (&parse->pstack->str);
2167 FcConfigMessage (parse, FcSevereError, "out of memory");
2172 size_t plen = strlen ((const char *)prefix);
2173 size_t dlen = strlen ((const char *)data);
2175 p = realloc (prefix, plen + 1 + dlen + 1);
2178 FcConfigMessage (parse, FcSevereError, "out of memory");
2183 prefix[plen] = FC_DIR_SEPARATOR;
2184 memcpy (&prefix[plen + 1], data, dlen);
2185 prefix[plen + 1 + dlen] = 0;
2190 if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2194 data = malloc (1000);
2197 FcConfigMessage (parse, FcSevereError, "out of memory");
2200 rc = GetTempPath (800, (LPSTR) data);
2201 if (rc == 0 || rc > 800)
2203 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2206 if (data [strlen ((const char *) data) - 1] != '\\')
2207 strcat ((char *) data, "\\");
2208 strcat ((char *) data, "fontconfig\\cache");
2210 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2212 char szFPath[MAX_PATH + 1];
2215 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2217 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2220 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2221 len = strlen(szFPath) + 1;
2226 FcConfigMessage (parse, FcSevereError, "out of memory");
2229 strncpy((char *) data, szFPath, len);
2232 if (strlen ((char *) data) == 0)
2233 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2234 else if (!FcStrUsesHome (data) || FcConfigHome ())
2236 if (!FcConfigAddCacheDir (parse->config, data))
2237 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2239 FcStrBufDestroy (&parse->pstack->str);
2247 FcParseInclude (FcConfigParse *parse)
2250 const FcChar8 *attr;
2251 FcBool ignore_missing = FcFalse;
2253 FcBool deprecated = FcFalse;
2255 FcChar8 *prefix = NULL, *p;
2256 static FcChar8 *userdir = NULL;
2257 static FcChar8 *userconf = NULL;
2259 s = FcStrBufDoneStatic (&parse->pstack->str);
2262 FcConfigMessage (parse, FcSevereError, "out of memory");
2265 attr = FcConfigGetAttribute (parse, "ignore_missing");
2266 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2267 ignore_missing = FcTrue;
2269 attr = FcConfigGetAttribute (parse, "deprecated");
2270 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2271 deprecated = FcTrue;
2273 attr = FcConfigGetAttribute (parse, "prefix");
2274 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2276 prefix = FcConfigXdgConfigHome ();
2277 /* home directory might be disabled.
2278 * simply ignore this element.
2285 size_t plen = strlen ((const char *)prefix);
2286 size_t dlen = strlen ((const char *)s);
2288 p = realloc (prefix, plen + 1 + dlen + 1);
2291 FcConfigMessage (parse, FcSevereError, "out of memory");
2295 prefix[plen] = FC_DIR_SEPARATOR;
2296 memcpy (&prefix[plen + 1], s, dlen);
2297 prefix[plen + 1 + dlen] = 0;
2299 if (FcFileIsDir (s))
2303 userdir = FcStrdup (s);
2305 else if (FcFileIsFile (s))
2309 userconf = FcStrdup (s);
2313 /* No config dir nor file on the XDG directory spec compliant place
2314 * so need to guess what it is supposed to be.
2316 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2322 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2323 parse->error = FcTrue;
2328 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2330 filename = FcConfigFilename(s);
2331 if (deprecated == FcTrue &&
2333 !FcFileIsLink (filename))
2335 if (FcFileIsDir (filename))
2337 FcChar8 *parent = FcStrDirname (userdir);
2339 if (!FcFileIsDir (parent))
2340 FcMakeDirectory (parent);
2342 if (FcFileIsDir (userdir) ||
2343 rename ((const char *)filename, (const char *)userdir) != 0 ||
2344 symlink ((const char *)userdir, (const char *)filename) != 0)
2348 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2349 warn_confd = FcTrue;
2355 FcChar8 *parent = FcStrDirname (userconf);
2357 if (!FcFileIsDir (parent))
2358 FcMakeDirectory (parent);
2360 if (FcFileIsFile (userconf) ||
2361 rename ((const char *)filename, (const char *)userconf) != 0 ||
2362 symlink ((const char *)userconf, (const char *)filename) != 0)
2366 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2373 FcStrFree(filename);
2376 FcStrBufDestroy (&parse->pstack->str);
2383 typedef struct _FcOpMap {
2389 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2393 for (i = 0; i < nmap; i++)
2394 if (!strcmp ((char *) op, map[i].name))
2399 static const FcOpMap fcCompareOps[] = {
2400 { "eq", FcOpEqual },
2401 { "not_eq", FcOpNotEqual },
2402 { "less", FcOpLess },
2403 { "less_eq", FcOpLessEqual },
2404 { "more", FcOpMore },
2405 { "more_eq", FcOpMoreEqual },
2406 { "contains", FcOpContains },
2407 { "not_contains", FcOpNotContains }
2410 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2413 FcConfigLexCompare (const FcChar8 *compare)
2415 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2419 FcParseTest (FcConfigParse *parse)
2421 const FcChar8 *kind_string;
2423 const FcChar8 *qual_string;
2425 const FcChar8 *name;
2426 const FcChar8 *compare_string;
2430 const FcChar8 *iblanks_string;
2433 kind_string = FcConfigGetAttribute (parse, "target");
2435 kind = FcMatchDefault;
2438 if (!strcmp ((char *) kind_string, "pattern"))
2439 kind = FcMatchPattern;
2440 else if (!strcmp ((char *) kind_string, "font"))
2442 else if (!strcmp ((char *) kind_string, "scan"))
2444 else if (!strcmp ((char *) kind_string, "default"))
2445 kind = FcMatchDefault;
2448 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2452 qual_string = FcConfigGetAttribute (parse, "qual");
2457 if (!strcmp ((char *) qual_string, "any"))
2459 else if (!strcmp ((char *) qual_string, "all"))
2461 else if (!strcmp ((char *) qual_string, "first"))
2463 else if (!strcmp ((char *) qual_string, "not_first"))
2464 qual = FcQualNotFirst;
2467 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2471 name = FcConfigGetAttribute (parse, "name");
2474 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2477 compare_string = FcConfigGetAttribute (parse, "compare");
2478 if (!compare_string)
2479 compare = FcOpEqual;
2482 compare = FcConfigLexCompare (compare_string);
2483 if (compare == FcOpInvalid)
2485 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2489 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2494 if (!FcNameBool (iblanks_string, &f))
2496 FcConfigMessage (parse,
2498 "invalid test ignore-blanks \"%s\"", iblanks_string);
2501 flags |= FcOpFlagIgnoreBlanks;
2503 expr = FcPopBinary (parse, FcOpComma);
2506 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2509 if (expr->op == FcOpComma)
2511 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2513 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2516 FcConfigMessage (parse, FcSevereError, "out of memory");
2519 FcVStackPushTest (parse, test);
2522 static const FcOpMap fcModeOps[] = {
2523 { "assign", FcOpAssign },
2524 { "assign_replace", FcOpAssignReplace },
2525 { "prepend", FcOpPrepend },
2526 { "prepend_first", FcOpPrependFirst },
2527 { "append", FcOpAppend },
2528 { "append_last", FcOpAppendLast },
2529 { "delete", FcOpDelete },
2530 { "delete_all", FcOpDeleteAll },
2533 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2536 FcConfigLexMode (const FcChar8 *mode)
2538 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2542 FcParseEdit (FcConfigParse *parse)
2544 const FcChar8 *name;
2545 const FcChar8 *mode_string;
2547 FcValueBinding binding;
2551 name = FcConfigGetAttribute (parse, "name");
2554 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2557 mode_string = FcConfigGetAttribute (parse, "mode");
2562 mode = FcConfigLexMode (mode_string);
2563 if (mode == FcOpInvalid)
2565 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2569 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2572 expr = FcPopBinary (parse, FcOpComma);
2573 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2576 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2577 FcExprDestroy (expr);
2580 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2581 mode, expr, binding);
2584 FcConfigMessage (parse, FcSevereError, "out of memory");
2585 FcExprDestroy (expr);
2588 if (!FcVStackPushEdit (parse, edit))
2589 FcEditDestroy (edit);
2593 FcParseMatch (FcConfigParse *parse)
2595 const FcChar8 *kind_name;
2598 FcRule *rule = NULL, *r;
2600 kind_name = FcConfigGetAttribute (parse, "target");
2602 kind = FcMatchPattern;
2605 if (!strcmp ((char *) kind_name, "pattern"))
2606 kind = FcMatchPattern;
2607 else if (!strcmp ((char *) kind_name, "font"))
2609 else if (!strcmp ((char *) kind_name, "scan"))
2613 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2617 while ((vstack = FcVStackPeek (parse)))
2619 switch ((int) vstack->tag) {
2621 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2625 vstack->tag = FcVStackNone;
2628 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2630 FcConfigMessage (parse, FcSevereError,
2631 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2632 FcObjectName(vstack->u.edit->object));
2634 FcRuleDestroy (rule);
2637 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2641 vstack->tag = FcVStackNone;
2644 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2647 FcVStackPopAndDestroy (parse);
2651 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2654 if (!FcConfigAddRule (parse->config, rule, kind))
2655 FcConfigMessage (parse, FcSevereError, "out of memory");
2659 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2663 while ((vstack = FcVStackPeek (parse)))
2665 switch ((int) vstack->tag) {
2667 if (!FcConfigGlobAdd (parse->config,
2669 element == FcElementAcceptfont))
2671 FcConfigMessage (parse, FcSevereError, "out of memory");
2674 case FcVStackPattern:
2675 if (!FcConfigPatternsAdd (parse->config,
2677 element == FcElementAcceptfont))
2679 FcConfigMessage (parse, FcSevereError, "out of memory");
2682 vstack->tag = FcVStackNone;
2685 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2688 FcVStackPopAndDestroy (parse);
2694 FcPopValue (FcConfigParse *parse)
2696 FcVStack *vstack = FcVStackPeek (parse);
2699 value.type = FcTypeVoid;
2704 switch ((int) vstack->tag) {
2705 case FcVStackString:
2706 value.u.s = FcStrdup (vstack->u.string);
2708 value.type = FcTypeString;
2710 case FcVStackConstant:
2711 if (FcNameConstant (vstack->u.string, &value.u.i))
2712 value.type = FcTypeInteger;
2714 case FcVStackInteger:
2715 value.u.i = vstack->u.integer;
2716 value.type = FcTypeInteger;
2718 case FcVStackDouble:
2719 value.u.d = vstack->u._double;
2720 value.type = FcTypeDouble;
2723 value.u.b = vstack->u.bool_;
2724 value.type = FcTypeBool;
2726 case FcVStackCharSet:
2727 value.u.c = FcCharSetCopy (vstack->u.charset);
2729 value.type = FcTypeCharSet;
2731 case FcVStackLangSet:
2732 value.u.l = FcLangSetCopy (vstack->u.langset);
2734 value.type = FcTypeLangSet;
2737 value.u.r = FcRangeCopy (vstack->u.range);
2739 value.type = FcTypeRange;
2742 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2746 FcVStackPopAndDestroy (parse);
2752 FcParsePatelt (FcConfigParse *parse)
2755 FcPattern *pattern = FcPatternCreate ();
2760 FcConfigMessage (parse, FcSevereError, "out of memory");
2764 name = (char *) FcConfigGetAttribute (parse, "name");
2767 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2768 FcPatternDestroy (pattern);
2774 value = FcPopValue (parse);
2775 if (value.type == FcTypeVoid)
2777 if (!FcPatternAdd (pattern, name, value, FcTrue))
2779 FcConfigMessage (parse, FcSevereError, "out of memory");
2780 FcValueDestroy(value);
2783 FcValueDestroy(value);
2786 FcVStackPushPattern (parse, pattern);
2790 FcParsePattern (FcConfigParse *parse)
2793 FcPattern *pattern = FcPatternCreate ();
2797 FcConfigMessage (parse, FcSevereError, "out of memory");
2801 while ((vstack = FcVStackPeek (parse)))
2803 switch ((int) vstack->tag) {
2804 case FcVStackPattern:
2805 if (!FcPatternAppend (pattern, vstack->u.pattern))
2807 FcConfigMessage (parse, FcSevereError, "out of memory");
2808 FcPatternDestroy (pattern);
2813 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2816 FcVStackPopAndDestroy (parse);
2819 FcVStackPushPattern (parse, pattern);
2823 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2825 FcConfigParse *parse = userData;
2830 switch (parse->pstack->element) {
2833 case FcElementFontconfig:
2838 case FcElementCacheDir:
2839 FcParseCacheDir (parse);
2841 case FcElementCache:
2842 data = FcStrBufDoneStatic (&parse->pstack->str);
2845 FcConfigMessage (parse, FcSevereError, "out of memory");
2848 /* discard this data; no longer used */
2849 FcStrBufDestroy (&parse->pstack->str);
2851 case FcElementInclude:
2852 FcParseInclude (parse);
2854 case FcElementConfig:
2856 case FcElementMatch:
2857 FcParseMatch (parse);
2859 case FcElementAlias:
2860 FcParseAlias (parse);
2863 case FcElementBlank:
2864 FcParseBlank (parse);
2866 case FcElementRescan:
2867 FcParseRescan (parse);
2870 case FcElementPrefer:
2871 FcParseFamilies (parse, FcVStackPrefer);
2873 case FcElementAccept:
2874 FcParseFamilies (parse, FcVStackAccept);
2876 case FcElementDefault:
2877 FcParseFamilies (parse, FcVStackDefault);
2879 case FcElementFamily:
2880 FcParseFamily (parse);
2884 FcParseTest (parse);
2887 FcParseEdit (parse);
2893 case FcElementDouble:
2894 FcParseDouble (parse);
2896 case FcElementString:
2897 FcParseString (parse, FcVStackString);
2899 case FcElementMatrix:
2900 FcParseMatrix (parse);
2902 case FcElementRange:
2903 FcParseRange (parse);
2906 FcParseBool (parse);
2908 case FcElementCharSet:
2909 FcParseCharSet (parse);
2911 case FcElementLangSet:
2912 FcParseLangSet (parse);
2914 case FcElementSelectfont:
2916 case FcElementAcceptfont:
2917 case FcElementRejectfont:
2918 FcParseAcceptRejectFont (parse, parse->pstack->element);
2921 FcParseString (parse, FcVStackGlob);
2923 case FcElementPattern:
2924 FcParsePattern (parse);
2926 case FcElementPatelt:
2927 FcParsePatelt (parse);
2930 FcParseName (parse);
2932 case FcElementConst:
2933 FcParseString (parse, FcVStackConstant);
2936 FcParseBinary (parse, FcOpOr);
2939 FcParseBinary (parse, FcOpAnd);
2942 FcParseBinary (parse, FcOpEqual);
2944 case FcElementNotEq:
2945 FcParseBinary (parse, FcOpNotEqual);
2948 FcParseBinary (parse, FcOpLess);
2950 case FcElementLessEq:
2951 FcParseBinary (parse, FcOpLessEqual);
2954 FcParseBinary (parse, FcOpMore);
2956 case FcElementMoreEq:
2957 FcParseBinary (parse, FcOpMoreEqual);
2959 case FcElementContains:
2960 FcParseBinary (parse, FcOpContains);
2962 case FcElementNotContains:
2963 FcParseBinary (parse, FcOpNotContains);
2966 FcParseBinary (parse, FcOpPlus);
2968 case FcElementMinus:
2969 FcParseBinary (parse, FcOpMinus);
2971 case FcElementTimes:
2972 FcParseBinary (parse, FcOpTimes);
2974 case FcElementDivide:
2975 FcParseBinary (parse, FcOpDivide);
2978 FcParseUnary (parse, FcOpNot);
2981 FcParseBinary (parse, FcOpQuest);
2983 case FcElementFloor:
2984 FcParseUnary (parse, FcOpFloor);
2987 FcParseUnary (parse, FcOpCeil);
2989 case FcElementRound:
2990 FcParseUnary (parse, FcOpRound);
2992 case FcElementTrunc:
2993 FcParseUnary (parse, FcOpTrunc);
2995 case FcElementUnknown:
2998 (void) FcPStackPop (parse);
3002 FcCharacterData (void *userData, const XML_Char *s, int len)
3004 FcConfigParse *parse = userData;
3008 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
3009 FcConfigMessage (parse, FcSevereError, "out of memory");
3013 FcStartDoctypeDecl (void *userData,
3014 const XML_Char *doctypeName,
3015 const XML_Char *sysid FC_UNUSED,
3016 const XML_Char *pubid FC_UNUSED,
3017 int has_internal_subset FC_UNUSED)
3019 FcConfigParse *parse = userData;
3021 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
3022 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3025 #ifdef ENABLE_LIBXML2
3028 FcInternalSubsetDecl (void *userData,
3029 const XML_Char *doctypeName,
3030 const XML_Char *sysid,
3031 const XML_Char *pubid)
3033 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3037 FcExternalSubsetDecl (void *userData,
3038 const XML_Char *doctypeName,
3039 const XML_Char *sysid,
3040 const XML_Char *pubid)
3042 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3045 #else /* ENABLE_LIBXML2 */
3048 FcEndDoctypeDecl (void *userData FC_UNUSED)
3052 #endif /* ENABLE_LIBXML2 */
3055 FcSortCmpStr (const void *a, const void *b)
3057 const FcChar8 *as = *((FcChar8 **) a);
3058 const FcChar8 *bs = *((FcChar8 **) b);
3059 return FcStrCmp (as, bs);
3063 FcConfigParseAndLoadDir (FcConfig *config,
3064 const FcChar8 *name,
3070 FcBool ret = FcTrue;
3075 d = opendir ((char *) dir);
3079 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3085 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3092 strcpy ((char *) file, (char *) dir);
3093 strcat ((char *) file, "/");
3094 base = file + strlen ((char *) file);
3096 files = FcStrSetCreate ();
3103 if (FcDebug () & FC_DBG_CONFIG)
3104 printf ("\tScanning config dir %s\n", dir);
3106 while (ret && (e = readdir (d)))
3109 #define TAIL ".conf"
3112 * Add all files of the form [0-9]*.conf
3114 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3115 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3117 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3119 strcpy ((char *) base, (char *) e->d_name);
3120 if (!FcStrSetAdd (files, file))
3130 qsort (files->strs, files->num, sizeof (FcChar8 *),
3131 (int (*)(const void *, const void *)) FcSortCmpStr);
3132 for (i = 0; ret && i < files->num; i++)
3133 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
3136 FcStrSetDestroy (files);
3142 return ret || !complain;
3146 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3147 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3151 FcConfigParseAndLoad (FcConfig *config,
3152 const FcChar8 *name,
3157 FcChar8 *filename, *f;
3160 FcConfigParse parse;
3161 FcBool error = FcTrue;
3162 const FcChar8 *sysroot = FcConfigGetSysRoot (config);
3164 #ifdef ENABLE_LIBXML2
3172 if (!pGetSystemWindowsDirectory)
3174 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3175 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3176 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3178 if (!pSHGetFolderPathA)
3180 HMODULE hSh = LoadLibraryA("shfolder.dll");
3181 /* the check is done later, because there is no provided fallback */
3183 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3187 f = FcConfigFilename (name);
3191 filename = FcStrBuildFilename (sysroot, f, NULL);
3193 filename = FcStrdup (f);
3196 if (FcStrSetMember (config->configFiles, filename))
3198 FcStrFree (filename);
3202 if (!FcStrSetAdd (config->configFiles, filename))
3204 FcStrFree (filename);
3208 if (FcFileIsDir (filename))
3210 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
3211 FcStrFree (filename);
3215 if (FcDebug () & FC_DBG_CONFIG)
3216 printf ("\tLoading config file %s\n", filename);
3218 fd = FcOpen ((char *) filename, O_RDONLY);
3220 FcStrFree (filename);
3224 #ifdef ENABLE_LIBXML2
3225 memset(&sax, 0, sizeof(sax));
3227 sax.internalSubset = FcInternalSubsetDecl;
3228 sax.externalSubset = FcExternalSubsetDecl;
3229 sax.startElement = FcStartElement;
3230 sax.endElement = FcEndElement;
3231 sax.characters = FcCharacterData;
3233 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3235 p = XML_ParserCreate ("UTF-8");
3237 FcStrFree (filename);
3242 if (!FcConfigParseInit (&parse, name, config, p))
3245 #ifndef ENABLE_LIBXML2
3247 XML_SetUserData (p, &parse);
3249 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3250 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3251 XML_SetCharacterDataHandler (p, FcCharacterData);
3253 #endif /* ENABLE_LIBXML2 */
3256 #ifndef ENABLE_LIBXML2
3257 buf = XML_GetBuffer (p, BUFSIZ);
3260 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3264 len = read (fd, buf, BUFSIZ);
3267 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3271 #ifdef ENABLE_LIBXML2
3272 if (xmlParseChunk (p, buf, len, len == 0))
3274 if (!XML_ParseBuffer (p, len, len == 0))
3277 FcConfigMessage (&parse, FcSevereError, "%s",
3278 XML_ErrorString (XML_GetErrorCode (p)));
3282 error = parse.error;
3284 FcConfigCleanup (&parse);
3291 if (error && complain)
3294 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3296 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3302 #include "fcaliastail.h"