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)
66 FcTestDestroy (test->next);
67 FcExprDestroy (test->expr);
72 FcExprCreateInteger (FcConfig *config, int i)
74 FcExpr *e = FcConfigAllocExpr (config);
84 FcExprCreateDouble (FcConfig *config, double d)
86 FcExpr *e = FcConfigAllocExpr (config);
96 FcExprCreateString (FcConfig *config, const FcChar8 *s)
98 FcExpr *e = FcConfigAllocExpr (config);
102 e->u.sval = FcStrdup (s);
107 static FcExprMatrix *
108 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
110 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
119 FcExprMatrixFreeShallow (FcExprMatrix *m)
128 FcExprMatrixFree (FcExprMatrix *m)
133 FcExprDestroy (m->xx);
134 FcExprDestroy (m->xy);
135 FcExprDestroy (m->yx);
136 FcExprDestroy (m->yy);
142 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
144 FcExpr *e = FcConfigAllocExpr (config);
148 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
154 FcExprCreateBool (FcConfig *config, FcBool b)
156 FcExpr *e = FcConfigAllocExpr (config);
166 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
168 FcExpr *e = FcConfigAllocExpr (config);
172 e->u.cval = FcCharSetCopy (charset);
178 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
180 FcExpr *e = FcConfigAllocExpr (config);
184 e->u.lval = FcLangSetCopy (langset);
190 FcExprCreateName (FcConfig *config, FcExprName name)
192 FcExpr *e = FcConfigAllocExpr (config);
202 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
204 FcExpr *e = FcConfigAllocExpr (config);
208 e->u.constant = FcStrdup (constant);
214 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
216 FcExpr *e = FcConfigAllocExpr (config);
220 e->u.tree.left = left;
221 e->u.tree.right = right;
227 FcExprDestroy (FcExpr *e)
231 switch (FC_OP_GET_OP (e->op)) {
240 FcExprMatrixFree (e->u.mexpr);
245 FcCharSetDestroy (e->u.cval);
248 FcLangSetDestroy (e->u.lval);
255 FcFree (e->u.constant);
258 case FcOpAssignReplace:
260 case FcOpPrependFirst:
274 case FcOpNotContains:
281 FcExprDestroy (e->u.tree.right);
288 FcExprDestroy (e->u.tree.left);
299 FcEditDestroy (FcEdit *e)
302 FcEditDestroy (e->next);
304 FcExprDestroy (e->expr);
308 typedef enum _FcElement {
355 FcElementNotContains,
369 static const struct {
373 { "fontconfig", FcElementFontconfig },
374 { "dir", FcElementDir },
375 { "cachedir", FcElementCacheDir },
376 { "cache", FcElementCache },
377 { "include", FcElementInclude },
378 { "config", FcElementConfig },
379 { "match", FcElementMatch },
380 { "alias", FcElementAlias },
382 { "blank", FcElementBlank },
383 { "rescan", FcElementRescan },
385 { "prefer", FcElementPrefer },
386 { "accept", FcElementAccept },
387 { "default", FcElementDefault },
388 { "family", FcElementFamily },
390 { "selectfont", FcElementSelectfont },
391 { "acceptfont", FcElementAcceptfont },
392 { "rejectfont", FcElementRejectfont },
393 { "glob", FcElementGlob },
394 { "pattern", FcElementPattern },
395 { "patelt", FcElementPatelt },
397 { "test", FcElementTest },
398 { "edit", FcElementEdit },
399 { "int", FcElementInt },
400 { "double", FcElementDouble },
401 { "string", FcElementString },
402 { "matrix", FcElementMatrix },
403 { "range", FcElementRange },
404 { "bool", FcElementBool },
405 { "charset", FcElementCharSet },
406 { "langset", FcElementLangSet },
407 { "name", FcElementName },
408 { "const", FcElementConst },
409 { "or", FcElementOr },
410 { "and", FcElementAnd },
411 { "eq", FcElementEq },
412 { "not_eq", FcElementNotEq },
413 { "less", FcElementLess },
414 { "less_eq", FcElementLessEq },
415 { "more", FcElementMore },
416 { "more_eq", FcElementMoreEq },
417 { "contains", FcElementContains },
418 { "not_contains", FcElementNotContains },
419 { "plus", FcElementPlus },
420 { "minus", FcElementMinus },
421 { "times", FcElementTimes },
422 { "divide", FcElementDivide },
423 { "not", FcElementNot },
424 { "if", FcElementIf },
425 { "floor", FcElementFloor },
426 { "ceil", FcElementCeil },
427 { "round", FcElementRound },
428 { "trunc", FcElementTrunc },
430 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
433 FcElementMap (const XML_Char *name)
437 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
438 if (!strcmp ((char *) name, fcElementMap[i].name))
439 return fcElementMap[i].element;
440 return FcElementUnknown;
443 typedef struct _FcPStack {
444 struct _FcPStack *prev;
448 FcChar8 *attr_buf_static[16];
451 typedef enum _FcVStackTag {
478 typedef struct _FcVStack {
479 struct _FcVStack *prev;
480 FcPStack *pstack; /* related parse element */
487 FcExprMatrix *matrix;
504 typedef struct _FcConfigParse {
511 unsigned int pstack_static_used;
512 FcPStack pstack_static[8];
513 unsigned int vstack_static_used;
514 FcVStack vstack_static[64];
517 typedef enum _FcConfigSeverity {
518 FcSevereInfo, FcSevereWarning, FcSevereError
522 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
524 const char *s = "unknown";
527 va_start (args, fmt);
530 case FcSevereInfo: s = "info"; break;
531 case FcSevereWarning: s = "warning"; break;
532 case FcSevereError: s = "error"; break;
537 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
538 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
540 fprintf (stderr, "Fontconfig %s: line %d: ", s,
541 (int)XML_GetCurrentLineNumber (parse->parser));
542 if (severe >= FcSevereError)
543 parse->error = FcTrue;
546 fprintf (stderr, "Fontconfig %s: ", s);
547 vfprintf (stderr, fmt, args);
548 fprintf (stderr, "\n");
554 FcPopExpr (FcConfigParse *parse);
558 FcTypeName (FcType type)
584 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
586 if (value == FcTypeInteger)
587 value = FcTypeDouble;
588 if (type == FcTypeInteger)
592 if ((value == FcTypeLangSet && type == FcTypeString) ||
593 (value == FcTypeString && type == FcTypeLangSet))
595 if (type == (FcType) -1)
597 /* It's perfectly fine to use user-define elements in expressions,
598 * so don't warn in that case. */
599 if (value == (FcType) -1)
601 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
602 FcTypeName (value), FcTypeName (type));
607 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
609 const FcObjectType *o;
612 /* If parsing the expression failed, some nodes may be NULL */
616 switch (FC_OP_GET_OP (expr->op)) {
619 FcTypecheckValue (parse, FcTypeDouble, type);
622 FcTypecheckValue (parse, FcTypeString, type);
625 FcTypecheckValue (parse, FcTypeMatrix, type);
628 FcTypecheckValue (parse, FcTypeBool, type);
631 FcTypecheckValue (parse, FcTypeCharSet, type);
634 FcTypecheckValue (parse, FcTypeLangSet, type);
639 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
641 FcTypecheckValue (parse, o->type, type);
644 c = FcNameGetConstant (expr->u.constant);
647 o = FcNameGetObjectType (c->object);
649 FcTypecheckValue (parse, o->type, type);
652 FcConfigMessage (parse, FcSevereWarning,
653 "invalid constant used : %s",
657 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
658 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
659 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
662 case FcOpAssignReplace:
671 case FcOpNotContains:
673 FcTypecheckValue (parse, FcTypeBool, type);
682 FcTypecheckExpr (parse, expr->u.tree.left, type);
683 FcTypecheckExpr (parse, expr->u.tree.right, type);
686 FcTypecheckValue (parse, FcTypeBool, type);
687 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
693 FcTypecheckValue (parse, FcTypeDouble, type);
694 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
702 FcTestCreate (FcConfigParse *parse,
705 const FcChar8 *field,
709 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
713 const FcObjectType *o;
718 test->object = FcObjectFromName ((const char *) field);
721 o = FcNameGetObjectType (FcObjectName (test->object));
723 FcTypecheckExpr (parse, expr, o->type);
729 FcEditCreate (FcConfigParse *parse,
733 FcValueBinding binding)
735 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
739 const FcObjectType *o;
745 e->binding = binding;
746 o = FcNameGetObjectType (FcObjectName (e->object));
748 FcTypecheckExpr (parse, expr, o->type);
754 FcVStackCreateAndPush (FcConfigParse *parse)
758 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
759 new = &parse->vstack_static[parse->vstack_static_used++];
762 new = malloc (sizeof (FcVStack));
766 new->tag = FcVStackNone;
769 new->prev = parse->vstack;
770 new->pstack = parse->pstack ? parse->pstack->prev : 0;
777 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
779 FcVStack *vstack = FcVStackCreateAndPush (parse);
782 vstack->u.string = string;
788 FcVStackPushInteger (FcConfigParse *parse, int integer)
790 FcVStack *vstack = FcVStackCreateAndPush (parse);
793 vstack->u.integer = integer;
794 vstack->tag = FcVStackInteger;
799 FcVStackPushDouble (FcConfigParse *parse, double _double)
801 FcVStack *vstack = FcVStackCreateAndPush (parse);
804 vstack->u._double = _double;
805 vstack->tag = FcVStackDouble;
810 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
813 vstack = FcVStackCreateAndPush (parse);
816 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
817 vstack->tag = FcVStackMatrix;
822 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
824 FcVStack *vstack = FcVStackCreateAndPush (parse);
827 vstack->u.range.begin = range->begin;
828 vstack->u.range.end = range->end;
829 vstack->tag = FcVStackRange;
834 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
836 FcVStack *vstack = FcVStackCreateAndPush (parse);
839 vstack->u.bool_ = bool_;
840 vstack->tag = FcVStackBool;
845 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
850 vstack = FcVStackCreateAndPush (parse);
853 vstack->u.charset = charset;
854 vstack->tag = FcVStackCharSet;
859 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
864 vstack = FcVStackCreateAndPush (parse);
867 vstack->u.langset = langset;
868 vstack->tag = FcVStackLangSet;
873 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
875 FcVStack *vstack = FcVStackCreateAndPush (parse);
878 vstack->u.name.object = object;
879 vstack->u.name.kind = kind;
880 vstack->tag = FcVStackName;
885 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
887 FcVStack *vstack = FcVStackCreateAndPush (parse);
890 vstack->u.test = test;
891 vstack->tag = FcVStackTest;
896 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
898 FcVStack *vstack = FcVStackCreateAndPush (parse);
901 vstack->u.expr = expr;
907 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
909 FcVStack *vstack = FcVStackCreateAndPush (parse);
912 vstack->u.edit = edit;
913 vstack->tag = FcVStackEdit;
918 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
920 FcVStack *vstack = FcVStackCreateAndPush (parse);
923 vstack->u.pattern = pattern;
924 vstack->tag = FcVStackPattern;
929 FcVStackFetch (FcConfigParse *parse, int off)
933 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
938 FcVStackPeek (FcConfigParse *parse)
940 FcVStack *vstack = parse->vstack;
942 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
946 FcVStackPopAndDestroy (FcConfigParse *parse)
948 FcVStack *vstack = parse->vstack;
950 if (!vstack || vstack->pstack != parse->pstack)
953 parse->vstack = vstack->prev;
955 switch (vstack->tag) {
963 case FcVStackConstant:
965 FcStrFree (vstack->u.string);
967 case FcVStackPattern:
968 FcPatternDestroy (vstack->u.pattern);
970 case FcVStackInteger:
974 FcExprMatrixFreeShallow (vstack->u.matrix);
979 case FcVStackCharSet:
980 FcCharSetDestroy (vstack->u.charset);
982 case FcVStackLangSet:
983 FcLangSetDestroy (vstack->u.langset);
986 FcTestDestroy (vstack->u.test);
991 case FcVStackDefault:
992 FcExprDestroy (vstack->u.expr);
995 FcEditDestroy (vstack->u.edit);
999 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1000 parse->vstack_static_used--;
1006 FcVStackClear (FcConfigParse *parse)
1008 while (FcVStackPeek (parse))
1009 FcVStackPopAndDestroy (parse);
1013 FcVStackElements (FcConfigParse *parse)
1016 FcVStack *vstack = parse->vstack;
1017 while (vstack && vstack->pstack == parse->pstack)
1020 vstack = vstack->prev;
1026 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1036 for (i = 0; attr[i]; i++)
1037 slen += strlen ((char *) attr[i]) + 1;
1040 slen += (i + 1) * sizeof (FcChar8 *);
1041 if (slen <= size_bytes)
1045 new = malloc (slen);
1048 FcConfigMessage (0, FcSevereError, "out of memory");
1052 s = (FcChar8 *) (new + (i + 1));
1053 for (i = 0; attr[i]; i++)
1056 strcpy ((char *) s, (char *) attr[i]);
1057 s += strlen ((char *) s) + 1;
1064 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1068 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1069 new = &parse->pstack_static[parse->pstack_static_used++];
1072 new = malloc (sizeof (FcPStack));
1077 new->prev = parse->pstack;
1078 new->element = element;
1079 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1080 FcStrBufInit (&new->str, 0, 0);
1081 parse->pstack = new;
1086 FcPStackPop (FcConfigParse *parse)
1092 FcConfigMessage (parse, FcSevereError, "mismatching element");
1096 if (parse->pstack->attr)
1098 /* Warn about unused attrs. */
1099 FcChar8 **attrs = parse->pstack->attr;
1104 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1110 FcVStackClear (parse);
1111 old = parse->pstack;
1112 parse->pstack = old->prev;
1113 FcStrBufDestroy (&old->str);
1115 if (old->attr && old->attr != old->attr_buf_static)
1118 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1119 parse->pstack_static_used--;
1126 FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1129 parse->pstack_static_used = 0;
1131 parse->vstack_static_used = 0;
1132 parse->error = FcFalse;
1134 parse->config = config;
1135 parse->parser = parser;
1140 FcConfigCleanup (FcConfigParse *parse)
1142 while (parse->pstack)
1143 FcPStackPop (parse);
1146 static const FcChar8 *
1147 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1153 attrs = parse->pstack->attr;
1159 if (!strcmp ((char *) *attrs, attr))
1161 attrs[0][0] = '\0'; /* Mark as used. */
1170 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1172 FcConfigParse *parse = userData;
1175 element = FcElementMap (name);
1176 if (element == FcElementUnknown)
1177 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1179 if (!FcPStackPush (parse, element, attr))
1181 FcConfigMessage (parse, FcSevereError, "out of memory");
1188 FcParseBlank (FcConfigParse *parse)
1190 int n = FcVStackElements (parse);
1194 FcVStack *v = FcVStackFetch (parse, n);
1195 if (!parse->config->blanks)
1197 parse->config->blanks = FcBlanksCreate ();
1198 if (!parse->config->blanks)
1201 switch ((int) v->tag) {
1202 case FcVStackInteger:
1203 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1207 if (v->u.range.begin <= v->u.range.end)
1209 for (i = v->u.range.begin; i <= v->u.range.end; i++)
1211 if (!FcBlanksAdd (parse->config->blanks, i))
1217 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1223 FcConfigMessage (parse, FcSevereError, "out of memory");
1227 FcParseRescan (FcConfigParse *parse)
1229 int n = FcVStackElements (parse);
1232 FcVStack *v = FcVStackFetch (parse, n);
1233 if (v->tag != FcVStackInteger)
1234 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1236 parse->config->rescanInterval = v->u.integer;
1241 FcParseInt (FcConfigParse *parse)
1248 s = FcStrBufDoneStatic (&parse->pstack->str);
1251 FcConfigMessage (parse, FcSevereError, "out of memory");
1255 l = (int) strtol ((char *) s, (char **)&end, 0);
1256 if (end != s + strlen ((char *) s))
1257 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1259 FcVStackPushInteger (parse, l);
1260 FcStrBufDestroy (&parse->pstack->str);
1264 * idea copied from glib g_ascii_strtod with
1265 * permission of the author (Alexander Larsson)
1271 FcStrtod (char *s, char **end)
1273 struct lconv *locale_data;
1278 * Have to swap the decimal point to match the current locale
1279 * if that locale doesn't use 0x2e
1281 if ((dot = strchr (s, 0x2e)) &&
1282 (locale_data = localeconv ()) &&
1283 (locale_data->decimal_point[0] != 0x2e ||
1284 locale_data->decimal_point[1] != 0))
1287 int slen = strlen (s);
1288 int dlen = strlen (locale_data->decimal_point);
1290 if (slen + dlen > (int) sizeof (buf))
1300 strncpy (buf, s, dot - s);
1302 strcpy (buf + (dot - s), locale_data->decimal_point);
1303 /* rest of number */
1304 strcpy (buf + (dot - s) + dlen, dot + 1);
1306 v = strtod (buf, &buf_end);
1308 buf_end = s + (buf_end - buf);
1310 buf_end -= dlen - 1;
1317 v = strtod (s, end);
1322 FcParseDouble (FcConfigParse *parse)
1329 s = FcStrBufDoneStatic (&parse->pstack->str);
1332 FcConfigMessage (parse, FcSevereError, "out of memory");
1336 d = FcStrtod ((char *) s, (char **)&end);
1337 if (end != s + strlen ((char *) s))
1338 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1340 FcVStackPushDouble (parse, d);
1341 FcStrBufDestroy (&parse->pstack->str);
1345 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1351 s = FcStrBufDone (&parse->pstack->str);
1354 FcConfigMessage (parse, FcSevereError, "out of memory");
1357 if (!FcVStackPushString (parse, tag, s))
1362 FcParseName (FcConfigParse *parse)
1364 const FcChar8 *kind_string;
1369 kind_string = FcConfigGetAttribute (parse, "target");
1371 kind = FcMatchDefault;
1374 if (!strcmp ((char *) kind_string, "pattern"))
1375 kind = FcMatchPattern;
1376 else if (!strcmp ((char *) kind_string, "font"))
1378 else if (!strcmp ((char *) kind_string, "default"))
1379 kind = FcMatchDefault;
1382 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1389 s = FcStrBufDone (&parse->pstack->str);
1392 FcConfigMessage (parse, FcSevereError, "out of memory");
1395 object = FcObjectFromName ((const char *) s);
1397 FcVStackPushName (parse, kind, object);
1403 FcParseMatrix (FcConfigParse *parse)
1407 m.yy = FcPopExpr (parse);
1408 m.yx = FcPopExpr (parse);
1409 m.xy = FcPopExpr (parse);
1410 m.xx = FcPopExpr (parse);
1412 if (FcPopExpr (parse))
1413 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1415 FcVStackPushMatrix (parse, &m);
1419 FcParseRange (FcConfigParse *parse)
1426 while ((vstack = FcVStackPeek (parse)))
1430 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1433 switch ((int) vstack->tag) {
1434 case FcVStackInteger:
1435 n = vstack->u.integer;
1438 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1447 FcVStackPopAndDestroy (parse);
1451 if (r.begin > r.end)
1453 FcConfigMessage (parse, FcSevereError, "invalid range");
1456 FcVStackPushRange (parse, &r);
1459 FcConfigMessage (parse, FcSevereError, "invalid range");
1463 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1465 FcBool result = FcFalse;
1467 if (!FcNameBool (bool_, &result))
1468 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1474 FcParseBool (FcConfigParse *parse)
1480 s = FcStrBufDoneStatic (&parse->pstack->str);
1483 FcConfigMessage (parse, FcSevereError, "out of memory");
1486 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1487 FcStrBufDestroy (&parse->pstack->str);
1491 FcParseCharSet (FcConfigParse *parse)
1494 FcCharSet *charset = FcCharSetCreate ();
1498 while ((vstack = FcVStackPeek (parse)))
1500 switch ((int) vstack->tag) {
1501 case FcVStackInteger:
1502 if (!FcCharSetAddChar (charset, vstack->u.integer))
1504 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1510 if (vstack->u.range.begin <= vstack->u.range.end)
1512 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1514 if (!FcCharSetAddChar (charset, i))
1516 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1524 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1527 FcVStackPopAndDestroy (parse);
1530 FcVStackPushCharSet (parse, charset);
1532 FcCharSetDestroy (charset);
1536 FcParseLangSet (FcConfigParse *parse)
1539 FcLangSet *langset = FcLangSetCreate ();
1542 while ((vstack = FcVStackPeek (parse)))
1544 switch ((int) vstack->tag) {
1545 case FcVStackString:
1546 if (!FcLangSetAdd (langset, vstack->u.string))
1548 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1554 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1557 FcVStackPopAndDestroy (parse);
1560 FcVStackPushLangSet (parse, langset);
1562 FcLangSetDestroy (langset);
1566 FcConfigLexBinding (FcConfigParse *parse,
1567 const FcChar8 *binding_string,
1568 FcValueBinding *binding_ret)
1570 FcValueBinding binding;
1572 if (!binding_string)
1573 binding = FcValueBindingWeak;
1576 if (!strcmp ((char *) binding_string, "weak"))
1577 binding = FcValueBindingWeak;
1578 else if (!strcmp ((char *) binding_string, "strong"))
1579 binding = FcValueBindingStrong;
1580 else if (!strcmp ((char *) binding_string, "same"))
1581 binding = FcValueBindingSame;
1584 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1588 *binding_ret = binding;
1593 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1596 FcExpr *left, *expr = 0, *new;
1598 while ((vstack = FcVStackPeek (parse)))
1600 if (vstack->tag != FcVStackFamily)
1602 FcConfigMessage (parse, FcSevereWarning, "non-family");
1603 FcVStackPopAndDestroy (parse);
1606 left = vstack->u.expr;
1607 vstack->tag = FcVStackNone;
1608 FcVStackPopAndDestroy (parse);
1611 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1614 FcConfigMessage (parse, FcSevereError, "out of memory");
1615 FcExprDestroy (left);
1616 FcExprDestroy (expr);
1626 if (!FcVStackPushExpr (parse, tag, expr))
1628 FcConfigMessage (parse, FcSevereError, "out of memory");
1629 FcExprDestroy (expr);
1635 FcParseFamily (FcConfigParse *parse)
1642 s = FcStrBufDoneStatic (&parse->pstack->str);
1645 FcConfigMessage (parse, FcSevereError, "out of memory");
1648 expr = FcExprCreateString (parse->config, s);
1649 FcStrBufDestroy (&parse->pstack->str);
1651 FcVStackPushExpr (parse, FcVStackFamily, expr);
1655 FcParseAlias (FcConfigParse *parse)
1657 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1658 FcEdit *edit = 0, *next;
1660 FcTest *test = NULL;
1661 FcValueBinding binding;
1663 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1665 while ((vstack = FcVStackPeek (parse)))
1667 switch ((int) vstack->tag) {
1668 case FcVStackFamily:
1671 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1672 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1674 FcConfigMessage (parse, FcSevereError, "out of memory");
1679 new = vstack->u.expr;
1683 vstack->tag = FcVStackNone;
1686 case FcVStackPrefer:
1688 FcExprDestroy (prefer);
1689 prefer = vstack->u.expr;
1690 vstack->tag = FcVStackNone;
1692 case FcVStackAccept:
1694 FcExprDestroy (accept);
1695 accept = vstack->u.expr;
1696 vstack->tag = FcVStackNone;
1698 case FcVStackDefault:
1700 FcExprDestroy (def);
1701 def = vstack->u.expr;
1702 vstack->tag = FcVStackNone;
1705 vstack->u.test->next = test;
1706 test = vstack->u.test;
1707 vstack->tag = FcVStackNone;
1710 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1713 FcVStackPopAndDestroy (parse);
1717 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1719 FcExprDestroy (prefer);
1721 FcExprDestroy (accept);
1723 FcExprDestroy (def);
1728 edit = FcEditCreate (parse,
1736 FcExprDestroy (prefer);
1741 edit = FcEditCreate (parse,
1749 FcExprDestroy (accept);
1754 edit = FcEditCreate (parse,
1762 FcExprDestroy (def);
1766 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1768 (FcChar8 *) FC_FAMILY,
1769 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1782 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1783 FcTestDestroy (test);
1786 FcExprDestroy (family);
1790 FcPopExpr (FcConfigParse *parse)
1792 FcVStack *vstack = FcVStackPeek (parse);
1796 switch ((int) vstack->tag) {
1799 case FcVStackString:
1800 case FcVStackFamily:
1801 expr = FcExprCreateString (parse->config, vstack->u.string);
1804 expr = FcExprCreateName (parse->config, vstack->u.name);
1806 case FcVStackConstant:
1807 expr = FcExprCreateConst (parse->config, vstack->u.string);
1810 /* XXX: What's the correct action here? (CDW) */
1812 case FcVStackPrefer:
1813 case FcVStackAccept:
1814 case FcVStackDefault:
1815 expr = vstack->u.expr;
1816 vstack->tag = FcVStackNone;
1818 case FcVStackInteger:
1819 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1821 case FcVStackDouble:
1822 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1824 case FcVStackMatrix:
1825 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1830 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1832 case FcVStackCharSet:
1833 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1835 case FcVStackLangSet:
1836 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1841 expr = vstack->u.expr;
1842 vstack->tag = FcVStackNone;
1849 FcVStackPopAndDestroy (parse);
1854 * This builds a tree of binary operations. Note
1855 * that every operator is defined so that if only
1856 * a single operand is contained, the value of the
1857 * whole expression is the value of the operand.
1859 * This code reduces in that case to returning that
1863 FcPopBinary (FcConfigParse *parse, FcOp op)
1865 FcExpr *left, *expr = 0, *new;
1867 while ((left = FcPopExpr (parse)))
1871 new = FcExprCreateOp (parse->config, left, op, expr);
1874 FcConfigMessage (parse, FcSevereError, "out of memory");
1875 FcExprDestroy (left);
1876 FcExprDestroy (expr);
1888 FcParseBinary (FcConfigParse *parse, FcOp op)
1890 FcExpr *expr = FcPopBinary (parse, op);
1892 FcVStackPushExpr (parse, FcVStackExpr, expr);
1896 * This builds a a unary operator, it consumes only
1901 FcPopUnary (FcConfigParse *parse, FcOp op)
1903 FcExpr *operand, *new = 0;
1905 if ((operand = FcPopExpr (parse)))
1907 new = FcExprCreateOp (parse->config, operand, op, 0);
1910 FcExprDestroy (operand);
1911 FcConfigMessage (parse, FcSevereError, "out of memory");
1918 FcParseUnary (FcConfigParse *parse, FcOp op)
1920 FcExpr *expr = FcPopUnary (parse, op);
1922 FcVStackPushExpr (parse, FcVStackExpr, expr);
1926 FcParseDir (FcConfigParse *parse)
1928 const FcChar8 *attr, *data;
1929 FcChar8 *prefix = NULL, *p;
1931 FcChar8 buffer[1000];
1934 attr = FcConfigGetAttribute (parse, "prefix");
1935 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1936 prefix = FcConfigXdgDataHome ();
1937 data = FcStrBufDoneStatic (&parse->pstack->str);
1940 FcConfigMessage (parse, FcSevereError, "out of memory");
1946 size_t plen = strlen ((const char *)prefix);
1947 size_t dlen = strlen ((const char *)data);
1949 p = realloc (prefix, plen + 1 + dlen + 1);
1952 FcConfigMessage (parse, FcSevereError, "out of memory");
1956 prefix[plen] = FC_DIR_SEPARATOR;
1957 memcpy (&prefix[plen + 1], data, dlen);
1958 prefix[plen + 1 + dlen] = 0;
1962 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
1966 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1968 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1972 * Must use the multi-byte aware function to search
1973 * for backslash because East Asian double-byte code
1974 * pages have characters with backslash as the second
1977 p = _mbsrchr (data, '\\');
1979 strcat (data, "\\fonts");
1981 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
1985 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1987 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1990 p = _mbsrchr (data, '\\');
1992 strcat (data, "\\..\\share\\fonts");
1994 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
1998 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1999 if (rc == 0 || rc > sizeof (buffer) - 20)
2001 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2004 if (data [strlen ((const char *) data) - 1] != '\\')
2005 strcat (data, "\\");
2006 strcat (data, "fonts");
2009 if (strlen ((char *) data) == 0)
2010 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2011 else if (!FcStrUsesHome (data) || FcConfigHome ())
2013 if (!FcConfigAddDir (parse->config, data))
2014 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2016 FcStrBufDestroy (&parse->pstack->str);
2024 FcParseCacheDir (FcConfigParse *parse)
2026 const FcChar8 *attr;
2027 FcChar8 *prefix = NULL, *p, *data;
2029 attr = FcConfigGetAttribute (parse, "prefix");
2030 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2031 prefix = FcConfigXdgCacheHome ();
2032 data = FcStrBufDone (&parse->pstack->str);
2035 FcConfigMessage (parse, FcSevereError, "out of memory");
2040 size_t plen = strlen ((const char *)prefix);
2041 size_t dlen = strlen ((const char *)data);
2043 p = realloc (prefix, plen + 1 + dlen + 1);
2046 FcConfigMessage (parse, FcSevereError, "out of memory");
2051 prefix[plen] = FC_DIR_SEPARATOR;
2052 memcpy (&prefix[plen + 1], data, dlen);
2053 prefix[plen + 1 + dlen] = 0;
2058 if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2062 data = malloc (1000);
2065 FcConfigMessage (parse, FcSevereError, "out of memory");
2068 rc = GetTempPath (800, (LPSTR) data);
2069 if (rc == 0 || rc > 800)
2071 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2074 if (data [strlen ((const char *) data) - 1] != '\\')
2075 strcat (data, "\\");
2076 strcat (data, "fontconfig\\cache");
2078 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2080 char szFPath[MAX_PATH + 1];
2083 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2085 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2088 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2089 len = strlen(szFPath) + 1;
2094 FcConfigMessage (parse, FcSevereError, "out of memory");
2097 strncpy((char *) data, szFPath, len);
2100 if (strlen ((char *) data) == 0)
2101 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2102 else if (!FcStrUsesHome (data) || FcConfigHome ())
2104 if (!FcConfigAddCacheDir (parse->config, data))
2105 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2107 FcStrBufDestroy (&parse->pstack->str);
2115 FcParseInclude (FcConfigParse *parse)
2118 const FcChar8 *attr;
2119 FcBool ignore_missing = FcFalse;
2120 FcBool deprecated = FcFalse;
2121 FcChar8 *prefix = NULL, *p;
2123 s = FcStrBufDoneStatic (&parse->pstack->str);
2126 FcConfigMessage (parse, FcSevereError, "out of memory");
2129 attr = FcConfigGetAttribute (parse, "ignore_missing");
2130 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2131 ignore_missing = FcTrue;
2132 attr = FcConfigGetAttribute (parse, "deprecated");
2133 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2134 deprecated = FcTrue;
2135 attr = FcConfigGetAttribute (parse, "prefix");
2136 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2137 prefix = FcConfigXdgConfigHome ();
2140 size_t plen = strlen ((const char *)prefix);
2141 size_t dlen = strlen ((const char *)s);
2143 p = realloc (prefix, plen + 1 + dlen + 1);
2146 FcConfigMessage (parse, FcSevereError, "out of memory");
2150 prefix[plen] = FC_DIR_SEPARATOR;
2151 memcpy (&prefix[plen + 1], s, dlen);
2152 prefix[plen + 1 + dlen] = 0;
2155 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2156 parse->error = FcTrue;
2161 filename = FcConfigFilename(s);
2162 if (deprecated == FcTrue &&
2164 !FcFileIsLink (filename))
2166 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
2169 FcStrFree(filename);
2171 FcStrBufDestroy (&parse->pstack->str);
2178 typedef struct _FcOpMap {
2184 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2188 for (i = 0; i < nmap; i++)
2189 if (!strcmp ((char *) op, map[i].name))
2194 static const FcOpMap fcCompareOps[] = {
2195 { "eq", FcOpEqual },
2196 { "not_eq", FcOpNotEqual },
2197 { "less", FcOpLess },
2198 { "less_eq", FcOpLessEqual },
2199 { "more", FcOpMore },
2200 { "more_eq", FcOpMoreEqual },
2201 { "contains", FcOpContains },
2202 { "not_contains", FcOpNotContains }
2205 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2208 FcConfigLexCompare (const FcChar8 *compare)
2210 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2214 FcParseTest (FcConfigParse *parse)
2216 const FcChar8 *kind_string;
2218 const FcChar8 *qual_string;
2220 const FcChar8 *name;
2221 const FcChar8 *compare_string;
2225 const FcChar8 *iblanks_string;
2228 kind_string = FcConfigGetAttribute (parse, "target");
2230 kind = FcMatchDefault;
2233 if (!strcmp ((char *) kind_string, "pattern"))
2234 kind = FcMatchPattern;
2235 else if (!strcmp ((char *) kind_string, "font"))
2237 else if (!strcmp ((char *) kind_string, "scan"))
2239 else if (!strcmp ((char *) kind_string, "default"))
2240 kind = FcMatchDefault;
2243 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2247 qual_string = FcConfigGetAttribute (parse, "qual");
2252 if (!strcmp ((char *) qual_string, "any"))
2254 else if (!strcmp ((char *) qual_string, "all"))
2256 else if (!strcmp ((char *) qual_string, "first"))
2258 else if (!strcmp ((char *) qual_string, "not_first"))
2259 qual = FcQualNotFirst;
2262 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2266 name = FcConfigGetAttribute (parse, "name");
2269 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2272 compare_string = FcConfigGetAttribute (parse, "compare");
2273 if (!compare_string)
2274 compare = FcOpEqual;
2277 compare = FcConfigLexCompare (compare_string);
2278 if (compare == FcOpInvalid)
2280 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2284 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2289 if (!FcNameBool (iblanks_string, &f))
2291 FcConfigMessage (parse,
2293 "invalid test ignore-blanks \"%s\"", iblanks_string);
2296 flags |= FcOpFlagIgnoreBlanks;
2298 expr = FcPopBinary (parse, FcOpComma);
2301 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2304 if (expr->op == FcOpComma)
2306 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2308 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2311 FcConfigMessage (parse, FcSevereError, "out of memory");
2314 FcVStackPushTest (parse, test);
2317 static const FcOpMap fcModeOps[] = {
2318 { "assign", FcOpAssign },
2319 { "assign_replace", FcOpAssignReplace },
2320 { "prepend", FcOpPrepend },
2321 { "prepend_first", FcOpPrependFirst },
2322 { "append", FcOpAppend },
2323 { "append_last", FcOpAppendLast },
2326 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2329 FcConfigLexMode (const FcChar8 *mode)
2331 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2335 FcParseEdit (FcConfigParse *parse)
2337 const FcChar8 *name;
2338 const FcChar8 *mode_string;
2340 FcValueBinding binding;
2344 name = FcConfigGetAttribute (parse, "name");
2347 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2350 mode_string = FcConfigGetAttribute (parse, "mode");
2355 mode = FcConfigLexMode (mode_string);
2356 if (mode == FcOpInvalid)
2358 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2362 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2365 expr = FcPopBinary (parse, FcOpComma);
2366 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2367 mode, expr, binding);
2370 FcConfigMessage (parse, FcSevereError, "out of memory");
2371 FcExprDestroy (expr);
2374 if (!FcVStackPushEdit (parse, edit))
2375 FcEditDestroy (edit);
2379 FcParseMatch (FcConfigParse *parse)
2381 const FcChar8 *kind_name;
2387 kind_name = FcConfigGetAttribute (parse, "target");
2389 kind = FcMatchPattern;
2392 if (!strcmp ((char *) kind_name, "pattern"))
2393 kind = FcMatchPattern;
2394 else if (!strcmp ((char *) kind_name, "font"))
2396 else if (!strcmp ((char *) kind_name, "scan"))
2400 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2404 while ((vstack = FcVStackPeek (parse)))
2406 switch ((int) vstack->tag) {
2408 vstack->u.test->next = test;
2409 test = vstack->u.test;
2410 vstack->tag = FcVStackNone;
2413 vstack->u.edit->next = edit;
2414 edit = vstack->u.edit;
2415 vstack->tag = FcVStackNone;
2416 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
2418 FcConfigMessage (parse, FcSevereError,
2419 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2420 FcObjectName(edit->object));
2424 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2427 FcVStackPopAndDestroy (parse);
2429 if (!FcConfigAddEdit (parse->config, test, edit, kind))
2430 FcConfigMessage (parse, FcSevereError, "out of memory");
2434 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2438 while ((vstack = FcVStackPeek (parse)))
2440 switch ((int) vstack->tag) {
2442 if (!FcConfigGlobAdd (parse->config,
2444 element == FcElementAcceptfont))
2446 FcConfigMessage (parse, FcSevereError, "out of memory");
2449 case FcVStackPattern:
2450 if (!FcConfigPatternsAdd (parse->config,
2452 element == FcElementAcceptfont))
2454 FcConfigMessage (parse, FcSevereError, "out of memory");
2457 vstack->tag = FcVStackNone;
2460 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2463 FcVStackPopAndDestroy (parse);
2469 FcPopValue (FcConfigParse *parse)
2471 FcVStack *vstack = FcVStackPeek (parse);
2474 value.type = FcTypeVoid;
2479 switch ((int) vstack->tag) {
2480 case FcVStackString:
2481 value.u.s = FcStrdup (vstack->u.string);
2483 value.type = FcTypeString;
2485 case FcVStackConstant:
2486 if (FcNameConstant (vstack->u.string, &value.u.i))
2487 value.type = FcTypeInteger;
2489 case FcVStackInteger:
2490 value.u.i = vstack->u.integer;
2491 value.type = FcTypeInteger;
2493 case FcVStackDouble:
2494 value.u.d = vstack->u._double;
2495 value.type = FcTypeDouble;
2498 value.u.b = vstack->u.bool_;
2499 value.type = FcTypeBool;
2501 case FcVStackCharSet:
2502 value.u.c = FcCharSetCopy (vstack->u.charset);
2504 value.type = FcTypeCharSet;
2506 case FcVStackLangSet:
2507 value.u.l = FcLangSetCopy (vstack->u.langset);
2509 value.type = FcTypeLangSet;
2512 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2516 FcVStackPopAndDestroy (parse);
2522 FcParsePatelt (FcConfigParse *parse)
2525 FcPattern *pattern = FcPatternCreate ();
2530 FcConfigMessage (parse, FcSevereError, "out of memory");
2534 name = (char *) FcConfigGetAttribute (parse, "name");
2537 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2538 FcPatternDestroy (pattern);
2544 value = FcPopValue (parse);
2545 if (value.type == FcTypeVoid)
2547 if (!FcPatternAdd (pattern, name, value, FcTrue))
2549 FcConfigMessage (parse, FcSevereError, "out of memory");
2550 FcValueDestroy(value);
2553 FcValueDestroy(value);
2556 FcVStackPushPattern (parse, pattern);
2560 FcParsePattern (FcConfigParse *parse)
2563 FcPattern *pattern = FcPatternCreate ();
2567 FcConfigMessage (parse, FcSevereError, "out of memory");
2571 while ((vstack = FcVStackPeek (parse)))
2573 switch ((int) vstack->tag) {
2574 case FcVStackPattern:
2575 if (!FcPatternAppend (pattern, vstack->u.pattern))
2577 FcConfigMessage (parse, FcSevereError, "out of memory");
2578 FcPatternDestroy (pattern);
2583 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2586 FcVStackPopAndDestroy (parse);
2589 FcVStackPushPattern (parse, pattern);
2593 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2595 FcConfigParse *parse = userData;
2600 switch (parse->pstack->element) {
2603 case FcElementFontconfig:
2608 case FcElementCacheDir:
2609 FcParseCacheDir (parse);
2611 case FcElementCache:
2612 data = FcStrBufDoneStatic (&parse->pstack->str);
2615 FcConfigMessage (parse, FcSevereError, "out of memory");
2618 /* discard this data; no longer used */
2619 FcStrBufDestroy (&parse->pstack->str);
2621 case FcElementInclude:
2622 FcParseInclude (parse);
2624 case FcElementConfig:
2626 case FcElementMatch:
2627 FcParseMatch (parse);
2629 case FcElementAlias:
2630 FcParseAlias (parse);
2633 case FcElementBlank:
2634 FcParseBlank (parse);
2636 case FcElementRescan:
2637 FcParseRescan (parse);
2640 case FcElementPrefer:
2641 FcParseFamilies (parse, FcVStackPrefer);
2643 case FcElementAccept:
2644 FcParseFamilies (parse, FcVStackAccept);
2646 case FcElementDefault:
2647 FcParseFamilies (parse, FcVStackDefault);
2649 case FcElementFamily:
2650 FcParseFamily (parse);
2654 FcParseTest (parse);
2657 FcParseEdit (parse);
2663 case FcElementDouble:
2664 FcParseDouble (parse);
2666 case FcElementString:
2667 FcParseString (parse, FcVStackString);
2669 case FcElementMatrix:
2670 FcParseMatrix (parse);
2672 case FcElementRange:
2673 FcParseRange (parse);
2676 FcParseBool (parse);
2678 case FcElementCharSet:
2679 FcParseCharSet (parse);
2681 case FcElementLangSet:
2682 FcParseLangSet (parse);
2684 case FcElementSelectfont:
2686 case FcElementAcceptfont:
2687 case FcElementRejectfont:
2688 FcParseAcceptRejectFont (parse, parse->pstack->element);
2691 FcParseString (parse, FcVStackGlob);
2693 case FcElementPattern:
2694 FcParsePattern (parse);
2696 case FcElementPatelt:
2697 FcParsePatelt (parse);
2700 FcParseName (parse);
2702 case FcElementConst:
2703 FcParseString (parse, FcVStackConstant);
2706 FcParseBinary (parse, FcOpOr);
2709 FcParseBinary (parse, FcOpAnd);
2712 FcParseBinary (parse, FcOpEqual);
2714 case FcElementNotEq:
2715 FcParseBinary (parse, FcOpNotEqual);
2718 FcParseBinary (parse, FcOpLess);
2720 case FcElementLessEq:
2721 FcParseBinary (parse, FcOpLessEqual);
2724 FcParseBinary (parse, FcOpMore);
2726 case FcElementMoreEq:
2727 FcParseBinary (parse, FcOpMoreEqual);
2729 case FcElementContains:
2730 FcParseBinary (parse, FcOpContains);
2732 case FcElementNotContains:
2733 FcParseBinary (parse, FcOpNotContains);
2736 FcParseBinary (parse, FcOpPlus);
2738 case FcElementMinus:
2739 FcParseBinary (parse, FcOpMinus);
2741 case FcElementTimes:
2742 FcParseBinary (parse, FcOpTimes);
2744 case FcElementDivide:
2745 FcParseBinary (parse, FcOpDivide);
2748 FcParseUnary (parse, FcOpNot);
2751 FcParseBinary (parse, FcOpQuest);
2753 case FcElementFloor:
2754 FcParseUnary (parse, FcOpFloor);
2757 FcParseUnary (parse, FcOpCeil);
2759 case FcElementRound:
2760 FcParseUnary (parse, FcOpRound);
2762 case FcElementTrunc:
2763 FcParseUnary (parse, FcOpTrunc);
2765 case FcElementUnknown:
2768 (void) FcPStackPop (parse);
2772 FcCharacterData (void *userData, const XML_Char *s, int len)
2774 FcConfigParse *parse = userData;
2778 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2779 FcConfigMessage (parse, FcSevereError, "out of memory");
2783 FcStartDoctypeDecl (void *userData,
2784 const XML_Char *doctypeName,
2785 const XML_Char *sysid FC_UNUSED,
2786 const XML_Char *pubid FC_UNUSED,
2787 int has_internal_subset FC_UNUSED)
2789 FcConfigParse *parse = userData;
2791 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2792 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2795 #ifdef ENABLE_LIBXML2
2798 FcInternalSubsetDecl (void *userData,
2799 const XML_Char *doctypeName,
2800 const XML_Char *sysid,
2801 const XML_Char *pubid)
2803 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2807 FcExternalSubsetDecl (void *userData,
2808 const XML_Char *doctypeName,
2809 const XML_Char *sysid,
2810 const XML_Char *pubid)
2812 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2815 #else /* ENABLE_LIBXML2 */
2818 FcEndDoctypeDecl (void *userData FC_UNUSED)
2822 #endif /* ENABLE_LIBXML2 */
2825 FcSortCmpStr (const void *a, const void *b)
2827 const FcChar8 *as = *((FcChar8 **) a);
2828 const FcChar8 *bs = *((FcChar8 **) b);
2829 return FcStrCmp (as, bs);
2833 FcConfigParseAndLoadDir (FcConfig *config,
2834 const FcChar8 *name,
2840 FcBool ret = FcTrue;
2845 d = opendir ((char *) dir);
2849 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2855 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2862 strcpy ((char *) file, (char *) dir);
2863 strcat ((char *) file, "/");
2864 base = file + strlen ((char *) file);
2866 files = FcStrSetCreate ();
2873 if (FcDebug () & FC_DBG_CONFIG)
2874 printf ("\tScanning config dir %s\n", dir);
2876 while (ret && (e = readdir (d)))
2879 #define TAIL ".conf"
2882 * Add all files of the form [0-9]*.conf
2884 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2885 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2887 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2889 strcpy ((char *) base, (char *) e->d_name);
2890 if (!FcStrSetAdd (files, file))
2900 qsort (files->strs, files->num, sizeof (FcChar8 *),
2901 (int (*)(const void *, const void *)) FcSortCmpStr);
2902 for (i = 0; ret && i < files->num; i++)
2903 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2906 FcStrSetDestroy (files);
2912 return ret || !complain;
2916 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
2917 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
2921 FcConfigParseAndLoad (FcConfig *config,
2922 const FcChar8 *name,
2930 FcConfigParse parse;
2931 FcBool error = FcTrue;
2933 #ifdef ENABLE_LIBXML2
2941 if (!pGetSystemWindowsDirectory)
2943 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
2944 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
2945 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
2947 if (!pSHGetFolderPathA)
2949 HMODULE hSh = LoadLibraryA("shfolder.dll");
2950 /* the check is done later, because there is no provided fallback */
2952 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
2956 filename = FcConfigFilename (name);
2960 if (FcStrSetMember (config->configFiles, filename))
2962 FcStrFree (filename);
2966 if (!FcStrSetAdd (config->configFiles, filename))
2968 FcStrFree (filename);
2972 if (FcFileIsDir (filename))
2974 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2975 FcStrFree (filename);
2979 if (FcDebug () & FC_DBG_CONFIG)
2980 printf ("\tLoading config file %s\n", filename);
2982 fd = open ((char *) filename, O_RDONLY);
2984 FcStrFree (filename);
2988 #ifdef ENABLE_LIBXML2
2989 memset(&sax, 0, sizeof(sax));
2991 sax.internalSubset = FcInternalSubsetDecl;
2992 sax.externalSubset = FcExternalSubsetDecl;
2993 sax.startElement = FcStartElement;
2994 sax.endElement = FcEndElement;
2995 sax.characters = FcCharacterData;
2997 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2999 p = XML_ParserCreate ("UTF-8");
3001 FcStrFree (filename);
3006 if (!FcConfigParseInit (&parse, name, config, p))
3009 #ifndef ENABLE_LIBXML2
3011 XML_SetUserData (p, &parse);
3013 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3014 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3015 XML_SetCharacterDataHandler (p, FcCharacterData);
3017 #endif /* ENABLE_LIBXML2 */
3020 #ifndef ENABLE_LIBXML2
3021 buf = XML_GetBuffer (p, BUFSIZ);
3024 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3028 len = read (fd, buf, BUFSIZ);
3031 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3035 #ifdef ENABLE_LIBXML2
3036 if (xmlParseChunk (p, buf, len, len == 0))
3038 if (!XML_ParseBuffer (p, len, len == 0))
3041 FcConfigMessage (&parse, FcSevereError, "%s",
3042 XML_ErrorString (XML_GetErrorCode (p)));
3046 error = parse.error;
3048 FcConfigCleanup (&parse);
3055 if (error && complain)
3058 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3060 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3066 #include "fcaliastail.h"