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 = FcSharedStr (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 FcExprCreateField (FcConfig *config, const char *field)
192 FcExpr *e = FcConfigAllocExpr (config);
196 e->u.object = FcObjectFromName (field);
202 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
204 FcExpr *e = FcConfigAllocExpr (config);
208 e->u.constant = FcSharedStr (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)) {
237 FcSharedStrFree (e->u.sval);
240 FcExprMatrixFree (e->u.mexpr);
245 FcCharSetDestroy (e->u.cval);
248 FcLangSetDestroy (e->u.lval);
255 FcSharedStrFree (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;
503 typedef struct _FcConfigParse {
510 unsigned int pstack_static_used;
511 FcPStack pstack_static[8];
512 unsigned int vstack_static_used;
513 FcVStack vstack_static[64];
516 typedef enum _FcConfigSeverity {
517 FcSevereInfo, FcSevereWarning, FcSevereError
521 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
523 const char *s = "unknown";
526 va_start (args, fmt);
529 case FcSevereInfo: s = "info"; break;
530 case FcSevereWarning: s = "warning"; break;
531 case FcSevereError: s = "error"; break;
536 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
537 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
539 fprintf (stderr, "Fontconfig %s: line %d: ", s,
540 (int)XML_GetCurrentLineNumber (parse->parser));
541 if (severe >= FcSevereError)
542 parse->error = FcTrue;
545 fprintf (stderr, "Fontconfig %s: ", s);
546 vfprintf (stderr, fmt, args);
547 fprintf (stderr, "\n");
553 FcPopExpr (FcConfigParse *parse);
557 FcTypeName (FcType type)
583 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
585 if (value == FcTypeInteger)
586 value = FcTypeDouble;
587 if (type == FcTypeInteger)
591 if ((value == FcTypeLangSet && type == FcTypeString) ||
592 (value == FcTypeString && type == FcTypeLangSet))
594 if (type == (FcType) -1)
596 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
597 FcTypeName (value), FcTypeName (type));
602 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
604 const FcObjectType *o;
607 /* If parsing the expression failed, some nodes may be NULL */
611 switch (FC_OP_GET_OP (expr->op)) {
614 FcTypecheckValue (parse, FcTypeDouble, type);
617 FcTypecheckValue (parse, FcTypeString, type);
620 FcTypecheckValue (parse, FcTypeMatrix, type);
623 FcTypecheckValue (parse, FcTypeBool, type);
626 FcTypecheckValue (parse, FcTypeCharSet, type);
629 FcTypecheckValue (parse, FcTypeLangSet, type);
634 o = FcNameGetObjectType (FcObjectName (expr->u.object));
636 FcTypecheckValue (parse, o->type, type);
639 c = FcNameGetConstant (expr->u.constant);
642 o = FcNameGetObjectType (c->object);
644 FcTypecheckValue (parse, o->type, type);
647 FcConfigMessage (parse, FcSevereWarning,
648 "invalid constant used : %s",
652 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
653 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
654 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
657 case FcOpAssignReplace:
666 case FcOpNotContains:
668 FcTypecheckValue (parse, FcTypeBool, type);
677 FcTypecheckExpr (parse, expr->u.tree.left, type);
678 FcTypecheckExpr (parse, expr->u.tree.right, type);
681 FcTypecheckValue (parse, FcTypeBool, type);
682 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
688 FcTypecheckValue (parse, FcTypeDouble, type);
689 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
697 FcTestCreate (FcConfigParse *parse,
700 const FcChar8 *field,
704 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
708 const FcObjectType *o;
713 test->object = FcObjectFromName ((const char *) field);
716 o = FcNameGetObjectType (FcObjectName (test->object));
718 FcTypecheckExpr (parse, expr, o->type);
724 FcEditCreate (FcConfigParse *parse,
728 FcValueBinding binding)
730 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
734 const FcObjectType *o;
740 e->binding = binding;
741 o = FcNameGetObjectType (FcObjectName (e->object));
743 FcTypecheckExpr (parse, expr, o->type);
749 FcVStackCreateAndPush (FcConfigParse *parse)
753 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
754 new = &parse->vstack_static[parse->vstack_static_used++];
757 new = malloc (sizeof (FcVStack));
761 new->tag = FcVStackNone;
764 new->prev = parse->vstack;
765 new->pstack = parse->pstack ? parse->pstack->prev : 0;
772 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
774 FcVStack *vstack = FcVStackCreateAndPush (parse);
777 vstack->u.string = string;
783 FcVStackPushInteger (FcConfigParse *parse, int integer)
785 FcVStack *vstack = FcVStackCreateAndPush (parse);
788 vstack->u.integer = integer;
789 vstack->tag = FcVStackInteger;
794 FcVStackPushDouble (FcConfigParse *parse, double _double)
796 FcVStack *vstack = FcVStackCreateAndPush (parse);
799 vstack->u._double = _double;
800 vstack->tag = FcVStackDouble;
805 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
808 vstack = FcVStackCreateAndPush (parse);
811 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
812 vstack->tag = FcVStackMatrix;
817 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
819 FcVStack *vstack = FcVStackCreateAndPush (parse);
822 vstack->u.range.begin = range->begin;
823 vstack->u.range.end = range->end;
824 vstack->tag = FcVStackRange;
829 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
831 FcVStack *vstack = FcVStackCreateAndPush (parse);
834 vstack->u.bool_ = bool_;
835 vstack->tag = FcVStackBool;
840 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
845 vstack = FcVStackCreateAndPush (parse);
848 vstack->u.charset = charset;
849 vstack->tag = FcVStackCharSet;
854 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
859 vstack = FcVStackCreateAndPush (parse);
862 vstack->u.langset = langset;
863 vstack->tag = FcVStackLangSet;
868 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
870 FcVStack *vstack = FcVStackCreateAndPush (parse);
873 vstack->u.test = test;
874 vstack->tag = FcVStackTest;
879 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
881 FcVStack *vstack = FcVStackCreateAndPush (parse);
884 vstack->u.expr = expr;
890 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
892 FcVStack *vstack = FcVStackCreateAndPush (parse);
895 vstack->u.edit = edit;
896 vstack->tag = FcVStackEdit;
901 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
903 FcVStack *vstack = FcVStackCreateAndPush (parse);
906 vstack->u.pattern = pattern;
907 vstack->tag = FcVStackPattern;
912 FcVStackFetch (FcConfigParse *parse, int off)
916 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
921 FcVStackPeek (FcConfigParse *parse)
923 FcVStack *vstack = parse->vstack;
925 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
929 FcVStackPopAndDestroy (FcConfigParse *parse)
931 FcVStack *vstack = parse->vstack;
933 if (!vstack || vstack->pstack != parse->pstack)
936 parse->vstack = vstack->prev;
938 switch (vstack->tag) {
945 case FcVStackConstant:
947 FcStrFree (vstack->u.string);
949 case FcVStackPattern:
950 FcPatternDestroy (vstack->u.pattern);
952 case FcVStackInteger:
956 FcExprMatrixFreeShallow (vstack->u.matrix);
961 case FcVStackCharSet:
962 FcCharSetDestroy (vstack->u.charset);
964 case FcVStackLangSet:
965 FcLangSetDestroy (vstack->u.langset);
968 FcTestDestroy (vstack->u.test);
973 case FcVStackDefault:
974 FcExprDestroy (vstack->u.expr);
977 FcEditDestroy (vstack->u.edit);
981 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
982 parse->vstack_static_used--;
988 FcVStackClear (FcConfigParse *parse)
990 while (FcVStackPeek (parse))
991 FcVStackPopAndDestroy (parse);
995 FcVStackElements (FcConfigParse *parse)
998 FcVStack *vstack = parse->vstack;
999 while (vstack && vstack->pstack == parse->pstack)
1002 vstack = vstack->prev;
1008 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1018 for (i = 0; attr[i]; i++)
1019 slen += strlen ((char *) attr[i]) + 1;
1022 slen += (i + 1) * sizeof (FcChar8 *);
1023 if (slen <= size_bytes)
1027 new = malloc (slen);
1030 FcConfigMessage (0, FcSevereError, "out of memory");
1034 s = (FcChar8 *) (new + (i + 1));
1035 for (i = 0; attr[i]; i++)
1038 strcpy ((char *) s, (char *) attr[i]);
1039 s += strlen ((char *) s) + 1;
1046 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1050 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1051 new = &parse->pstack_static[parse->pstack_static_used++];
1054 new = malloc (sizeof (FcPStack));
1059 new->prev = parse->pstack;
1060 new->element = element;
1061 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1062 FcStrBufInit (&new->str, 0, 0);
1063 parse->pstack = new;
1068 FcPStackPop (FcConfigParse *parse)
1074 FcConfigMessage (parse, FcSevereError, "mismatching element");
1077 FcVStackClear (parse);
1078 old = parse->pstack;
1079 parse->pstack = old->prev;
1080 FcStrBufDestroy (&old->str);
1081 if (old->attr && old->attr != old->attr_buf_static)
1084 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1085 parse->pstack_static_used--;
1092 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1095 parse->pstack_static_used = 0;
1097 parse->vstack_static_used = 0;
1098 parse->error = FcFalse;
1100 parse->config = config;
1101 parse->parser = parser;
1106 FcConfigCleanup (FcConfigParse *parse)
1108 while (parse->pstack)
1109 FcPStackPop (parse);
1112 static const FcChar8 *
1113 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1119 attrs = parse->pstack->attr;
1125 if (!strcmp ((char *) *attrs, attr))
1133 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1135 FcConfigParse *parse = userData;
1138 element = FcElementMap (name);
1139 if (element == FcElementUnknown)
1140 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1142 if (!FcPStackPush (parse, element, attr))
1144 FcConfigMessage (parse, FcSevereError, "out of memory");
1151 FcParseBlank (FcConfigParse *parse)
1153 int n = FcVStackElements (parse);
1157 FcVStack *v = FcVStackFetch (parse, n);
1158 if (!parse->config->blanks)
1160 parse->config->blanks = FcBlanksCreate ();
1161 if (!parse->config->blanks)
1164 switch ((int) v->tag) {
1165 case FcVStackInteger:
1166 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1170 if (v->u.range.begin <= v->u.range.end)
1172 for (i = v->u.range.begin; i <= v->u.range.end; i++)
1174 if (!FcBlanksAdd (parse->config->blanks, i))
1180 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1186 FcConfigMessage (parse, FcSevereError, "out of memory");
1190 FcParseRescan (FcConfigParse *parse)
1192 int n = FcVStackElements (parse);
1195 FcVStack *v = FcVStackFetch (parse, n);
1196 if (v->tag != FcVStackInteger)
1197 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1199 parse->config->rescanInterval = v->u.integer;
1204 FcParseInt (FcConfigParse *parse)
1211 s = FcStrBufDoneStatic (&parse->pstack->str);
1214 FcConfigMessage (parse, FcSevereError, "out of memory");
1218 l = (int) strtol ((char *) s, (char **)&end, 0);
1219 if (end != s + strlen ((char *) s))
1220 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1222 FcVStackPushInteger (parse, l);
1223 FcStrBufDestroy (&parse->pstack->str);
1227 * idea copied from glib g_ascii_strtod with
1228 * permission of the author (Alexander Larsson)
1234 FcStrtod (char *s, char **end)
1236 struct lconv *locale_data;
1241 * Have to swap the decimal point to match the current locale
1242 * if that locale doesn't use 0x2e
1244 if ((dot = strchr (s, 0x2e)) &&
1245 (locale_data = localeconv ()) &&
1246 (locale_data->decimal_point[0] != 0x2e ||
1247 locale_data->decimal_point[1] != 0))
1250 int slen = strlen (s);
1251 int dlen = strlen (locale_data->decimal_point);
1253 if (slen + dlen > (int) sizeof (buf))
1263 strncpy (buf, s, dot - s);
1265 strcpy (buf + (dot - s), locale_data->decimal_point);
1266 /* rest of number */
1267 strcpy (buf + (dot - s) + dlen, dot + 1);
1269 v = strtod (buf, &buf_end);
1271 buf_end = s + (buf_end - buf);
1273 buf_end -= dlen - 1;
1280 v = strtod (s, end);
1285 FcParseDouble (FcConfigParse *parse)
1292 s = FcStrBufDoneStatic (&parse->pstack->str);
1295 FcConfigMessage (parse, FcSevereError, "out of memory");
1299 d = FcStrtod ((char *) s, (char **)&end);
1300 if (end != s + strlen ((char *) s))
1301 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1303 FcVStackPushDouble (parse, d);
1304 FcStrBufDestroy (&parse->pstack->str);
1308 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1314 s = FcStrBufDone (&parse->pstack->str);
1317 FcConfigMessage (parse, FcSevereError, "out of memory");
1320 if (!FcVStackPushString (parse, tag, s))
1325 FcParseMatrix (FcConfigParse *parse)
1329 m.yy = FcPopExpr (parse);
1330 m.yx = FcPopExpr (parse);
1331 m.xy = FcPopExpr (parse);
1332 m.xx = FcPopExpr (parse);
1334 if (FcPopExpr (parse))
1335 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1337 FcVStackPushMatrix (parse, &m);
1341 FcParseRange (FcConfigParse *parse)
1348 while ((vstack = FcVStackPeek (parse)))
1352 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1355 switch ((int) vstack->tag) {
1356 case FcVStackInteger:
1357 n = vstack->u.integer;
1360 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1369 FcVStackPopAndDestroy (parse);
1373 if (r.begin > r.end)
1375 FcConfigMessage (parse, FcSevereError, "invalid range");
1378 FcVStackPushRange (parse, &r);
1381 FcConfigMessage (parse, FcSevereError, "invalid range");
1385 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1387 FcBool result = FcFalse;
1389 if (!FcNameBool (bool_, &result))
1390 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1396 FcParseBool (FcConfigParse *parse)
1402 s = FcStrBufDoneStatic (&parse->pstack->str);
1405 FcConfigMessage (parse, FcSevereError, "out of memory");
1408 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1409 FcStrBufDestroy (&parse->pstack->str);
1413 FcParseCharSet (FcConfigParse *parse)
1416 FcCharSet *charset = FcCharSetCreate ();
1420 while ((vstack = FcVStackPeek (parse)))
1422 switch ((int) vstack->tag) {
1423 case FcVStackInteger:
1424 if (!FcCharSetAddChar (charset, vstack->u.integer))
1426 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1432 if (vstack->u.range.begin <= vstack->u.range.end)
1434 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1436 if (!FcCharSetAddChar (charset, i))
1438 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1446 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1449 FcVStackPopAndDestroy (parse);
1452 FcVStackPushCharSet (parse, charset);
1454 FcCharSetDestroy (charset);
1458 FcParseLangSet (FcConfigParse *parse)
1461 FcLangSet *langset = FcLangSetCreate ();
1464 while ((vstack = FcVStackPeek (parse)))
1466 switch ((int) vstack->tag) {
1467 case FcVStackString:
1468 if (!FcLangSetAdd (langset, vstack->u.string))
1470 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1476 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1479 FcVStackPopAndDestroy (parse);
1482 FcVStackPushLangSet (parse, langset);
1484 FcLangSetDestroy (langset);
1488 FcConfigLexBinding (FcConfigParse *parse,
1489 const FcChar8 *binding_string,
1490 FcValueBinding *binding_ret)
1492 FcValueBinding binding;
1494 if (!binding_string)
1495 binding = FcValueBindingWeak;
1498 if (!strcmp ((char *) binding_string, "weak"))
1499 binding = FcValueBindingWeak;
1500 else if (!strcmp ((char *) binding_string, "strong"))
1501 binding = FcValueBindingStrong;
1502 else if (!strcmp ((char *) binding_string, "same"))
1503 binding = FcValueBindingSame;
1506 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1510 *binding_ret = binding;
1515 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1518 FcExpr *left, *expr = 0, *new;
1520 while ((vstack = FcVStackPeek (parse)))
1522 if (vstack->tag != FcVStackFamily)
1524 FcConfigMessage (parse, FcSevereWarning, "non-family");
1525 FcVStackPopAndDestroy (parse);
1528 left = vstack->u.expr;
1529 vstack->tag = FcVStackNone;
1530 FcVStackPopAndDestroy (parse);
1533 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1536 FcConfigMessage (parse, FcSevereError, "out of memory");
1537 FcExprDestroy (left);
1538 FcExprDestroy (expr);
1548 if (!FcVStackPushExpr (parse, tag, expr))
1550 FcConfigMessage (parse, FcSevereError, "out of memory");
1551 FcExprDestroy (expr);
1557 FcParseFamily (FcConfigParse *parse)
1564 s = FcStrBufDoneStatic (&parse->pstack->str);
1567 FcConfigMessage (parse, FcSevereError, "out of memory");
1570 expr = FcExprCreateString (parse->config, s);
1571 FcStrBufDestroy (&parse->pstack->str);
1573 FcVStackPushExpr (parse, FcVStackFamily, expr);
1577 FcParseAlias (FcConfigParse *parse)
1579 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1580 FcEdit *edit = 0, *next;
1582 FcTest *test = NULL;
1583 FcValueBinding binding;
1585 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1587 while ((vstack = FcVStackPeek (parse)))
1589 switch ((int) vstack->tag) {
1590 case FcVStackFamily:
1593 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1594 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1596 FcConfigMessage (parse, FcSevereError, "out of memory");
1601 new = vstack->u.expr;
1605 vstack->tag = FcVStackNone;
1608 case FcVStackPrefer:
1610 FcExprDestroy (prefer);
1611 prefer = vstack->u.expr;
1612 vstack->tag = FcVStackNone;
1614 case FcVStackAccept:
1616 FcExprDestroy (accept);
1617 accept = vstack->u.expr;
1618 vstack->tag = FcVStackNone;
1620 case FcVStackDefault:
1622 FcExprDestroy (def);
1623 def = vstack->u.expr;
1624 vstack->tag = FcVStackNone;
1627 vstack->u.test->next = test;
1628 test = vstack->u.test;
1629 vstack->tag = FcVStackNone;
1632 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1635 FcVStackPopAndDestroy (parse);
1639 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1641 FcExprDestroy (prefer);
1643 FcExprDestroy (accept);
1645 FcExprDestroy (def);
1650 edit = FcEditCreate (parse,
1658 FcExprDestroy (prefer);
1663 edit = FcEditCreate (parse,
1671 FcExprDestroy (accept);
1676 edit = FcEditCreate (parse,
1684 FcExprDestroy (def);
1688 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1690 (FcChar8 *) FC_FAMILY,
1691 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1704 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1705 FcTestDestroy (test);
1708 FcExprDestroy (family);
1712 FcPopExpr (FcConfigParse *parse)
1714 FcVStack *vstack = FcVStackPeek (parse);
1718 switch ((int) vstack->tag) {
1721 case FcVStackString:
1722 case FcVStackFamily:
1723 expr = FcExprCreateString (parse->config, vstack->u.string);
1726 expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
1728 case FcVStackConstant:
1729 expr = FcExprCreateConst (parse->config, vstack->u.string);
1732 /* XXX: What's the correct action here? (CDW) */
1734 case FcVStackPrefer:
1735 case FcVStackAccept:
1736 case FcVStackDefault:
1737 expr = vstack->u.expr;
1738 vstack->tag = FcVStackNone;
1740 case FcVStackInteger:
1741 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1743 case FcVStackDouble:
1744 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1746 case FcVStackMatrix:
1747 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1752 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1754 case FcVStackCharSet:
1755 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1757 case FcVStackLangSet:
1758 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1763 expr = vstack->u.expr;
1764 vstack->tag = FcVStackNone;
1771 FcVStackPopAndDestroy (parse);
1776 * This builds a tree of binary operations. Note
1777 * that every operator is defined so that if only
1778 * a single operand is contained, the value of the
1779 * whole expression is the value of the operand.
1781 * This code reduces in that case to returning that
1785 FcPopBinary (FcConfigParse *parse, FcOp op)
1787 FcExpr *left, *expr = 0, *new;
1789 while ((left = FcPopExpr (parse)))
1793 new = FcExprCreateOp (parse->config, left, op, expr);
1796 FcConfigMessage (parse, FcSevereError, "out of memory");
1797 FcExprDestroy (left);
1798 FcExprDestroy (expr);
1810 FcParseBinary (FcConfigParse *parse, FcOp op)
1812 FcExpr *expr = FcPopBinary (parse, op);
1814 FcVStackPushExpr (parse, FcVStackExpr, expr);
1818 * This builds a a unary operator, it consumes only
1823 FcPopUnary (FcConfigParse *parse, FcOp op)
1825 FcExpr *operand, *new = 0;
1827 if ((operand = FcPopExpr (parse)))
1829 new = FcExprCreateOp (parse->config, operand, op, 0);
1832 FcExprDestroy (operand);
1833 FcConfigMessage (parse, FcSevereError, "out of memory");
1840 FcParseUnary (FcConfigParse *parse, FcOp op)
1842 FcExpr *expr = FcPopUnary (parse, op);
1844 FcVStackPushExpr (parse, FcVStackExpr, expr);
1848 FcParseDir (FcConfigParse *parse)
1850 const FcChar8 *attr, *data;
1851 FcChar8 *prefix = NULL, *p;
1853 FcChar8 buffer[1000];
1856 attr = FcConfigGetAttribute (parse, "prefix");
1857 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1858 prefix = FcConfigXdgDataHome ();
1859 data = FcStrBufDoneStatic (&parse->pstack->str);
1862 FcConfigMessage (parse, FcSevereError, "out of memory");
1868 size_t plen = strlen ((const char *)prefix);
1869 size_t dlen = strlen ((const char *)data);
1871 p = realloc (prefix, plen + 1 + dlen + 1);
1874 FcConfigMessage (parse, FcSevereError, "out of memory");
1878 prefix[plen] = FC_DIR_SEPARATOR;
1879 memcpy (&prefix[plen + 1], data, dlen);
1880 prefix[plen + 1 + dlen] = 0;
1884 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
1888 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1890 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1894 * Must use the multi-byte aware function to search
1895 * for backslash because East Asian double-byte code
1896 * pages have characters with backslash as the second
1899 p = _mbsrchr (data, '\\');
1901 strcat (data, "\\fonts");
1903 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
1907 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1909 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1912 p = _mbsrchr (data, '\\');
1914 strcat (data, "\\..\\share\\fonts");
1916 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
1920 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1921 if (rc == 0 || rc > sizeof (buffer) - 20)
1923 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1926 if (data [strlen ((const char *) data) - 1] != '\\')
1927 strcat (data, "\\");
1928 strcat (data, "fonts");
1931 if (strlen ((char *) data) == 0)
1932 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
1933 else if (!FcStrUsesHome (data) || FcConfigHome ())
1935 if (!FcConfigAddDir (parse->config, data))
1936 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
1938 FcStrBufDestroy (&parse->pstack->str);
1946 FcParseCacheDir (FcConfigParse *parse)
1948 const FcChar8 *attr;
1949 FcChar8 *prefix = NULL, *p, *data;
1951 attr = FcConfigGetAttribute (parse, "prefix");
1952 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1953 prefix = FcConfigXdgCacheHome ();
1954 data = FcStrBufDone (&parse->pstack->str);
1957 FcConfigMessage (parse, FcSevereError, "out of memory");
1962 size_t plen = strlen ((const char *)prefix);
1963 size_t dlen = strlen ((const char *)data);
1965 p = realloc (prefix, plen + 1 + dlen + 1);
1968 FcConfigMessage (parse, FcSevereError, "out of memory");
1973 prefix[plen] = FC_DIR_SEPARATOR;
1974 memcpy (&prefix[plen + 1], data, dlen);
1975 prefix[plen + 1 + dlen] = 0;
1980 if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
1984 data = malloc (1000);
1987 FcConfigMessage (parse, FcSevereError, "out of memory");
1990 rc = GetTempPath (800, (LPSTR) data);
1991 if (rc == 0 || rc > 800)
1993 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
1996 if (data [strlen ((const char *) data) - 1] != '\\')
1997 strcat (data, "\\");
1998 strcat (data, "fontconfig\\cache");
2000 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2002 char szFPath[MAX_PATH + 1];
2005 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2007 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2010 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2011 len = strlen(szFPath) + 1;
2016 FcConfigMessage (parse, FcSevereError, "out of memory");
2019 strncpy((char *) data, szFPath, len);
2022 if (strlen ((char *) data) == 0)
2023 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2024 else if (!FcStrUsesHome (data) || FcConfigHome ())
2026 if (!FcConfigAddCacheDir (parse->config, data))
2027 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2029 FcStrBufDestroy (&parse->pstack->str);
2037 FcParseInclude (FcConfigParse *parse)
2040 const FcChar8 *attr;
2041 FcBool ignore_missing = FcFalse;
2042 FcBool deprecated = FcFalse;
2043 FcChar8 *prefix = NULL, *p;
2045 s = FcStrBufDoneStatic (&parse->pstack->str);
2048 FcConfigMessage (parse, FcSevereError, "out of memory");
2051 attr = FcConfigGetAttribute (parse, "ignore_missing");
2052 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2053 ignore_missing = FcTrue;
2054 attr = FcConfigGetAttribute (parse, "deprecated");
2055 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2056 deprecated = FcTrue;
2057 attr = FcConfigGetAttribute (parse, "prefix");
2058 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2059 prefix = FcConfigXdgConfigHome ();
2062 size_t plen = strlen ((const char *)prefix);
2063 size_t dlen = strlen ((const char *)s);
2065 p = realloc (prefix, plen + 1 + dlen + 1);
2068 FcConfigMessage (parse, FcSevereError, "out of memory");
2072 prefix[plen] = FC_DIR_SEPARATOR;
2073 memcpy (&prefix[plen + 1], s, dlen);
2074 prefix[plen + 1 + dlen] = 0;
2077 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2078 parse->error = FcTrue;
2083 filename = FcConfigFilename(s);
2084 if (deprecated == FcTrue &&
2086 !FcFileIsLink (filename))
2088 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
2091 FcStrFree(filename);
2093 FcStrBufDestroy (&parse->pstack->str);
2100 typedef struct _FcOpMap {
2106 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2110 for (i = 0; i < nmap; i++)
2111 if (!strcmp ((char *) op, map[i].name))
2116 static const FcOpMap fcCompareOps[] = {
2117 { "eq", FcOpEqual },
2118 { "not_eq", FcOpNotEqual },
2119 { "less", FcOpLess },
2120 { "less_eq", FcOpLessEqual },
2121 { "more", FcOpMore },
2122 { "more_eq", FcOpMoreEqual },
2123 { "contains", FcOpContains },
2124 { "not_contains", FcOpNotContains }
2127 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2130 FcConfigLexCompare (const FcChar8 *compare)
2132 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2136 FcParseTest (FcConfigParse *parse)
2138 const FcChar8 *kind_string;
2140 const FcChar8 *qual_string;
2142 const FcChar8 *name;
2143 const FcChar8 *compare_string;
2147 const FcChar8 *iblanks_string;
2150 kind_string = FcConfigGetAttribute (parse, "target");
2152 kind = FcMatchDefault;
2155 if (!strcmp ((char *) kind_string, "pattern"))
2156 kind = FcMatchPattern;
2157 else if (!strcmp ((char *) kind_string, "font"))
2159 else if (!strcmp ((char *) kind_string, "scan"))
2161 else if (!strcmp ((char *) kind_string, "default"))
2162 kind = FcMatchDefault;
2165 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2169 qual_string = FcConfigGetAttribute (parse, "qual");
2174 if (!strcmp ((char *) qual_string, "any"))
2176 else if (!strcmp ((char *) qual_string, "all"))
2178 else if (!strcmp ((char *) qual_string, "first"))
2180 else if (!strcmp ((char *) qual_string, "not_first"))
2181 qual = FcQualNotFirst;
2184 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2188 name = FcConfigGetAttribute (parse, "name");
2191 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2194 compare_string = FcConfigGetAttribute (parse, "compare");
2195 if (!compare_string)
2196 compare = FcOpEqual;
2199 compare = FcConfigLexCompare (compare_string);
2200 if (compare == FcOpInvalid)
2202 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2206 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2211 if (!FcNameBool (iblanks_string, &f))
2213 FcConfigMessage (parse,
2215 "invalid test ignore-blanks \"%s\"", iblanks_string);
2218 flags |= FcOpFlagIgnoreBlanks;
2220 expr = FcPopBinary (parse, FcOpComma);
2223 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2226 if (expr->op == FcOpComma)
2228 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2230 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2233 FcConfigMessage (parse, FcSevereError, "out of memory");
2236 FcVStackPushTest (parse, test);
2239 static const FcOpMap fcModeOps[] = {
2240 { "assign", FcOpAssign },
2241 { "assign_replace", FcOpAssignReplace },
2242 { "prepend", FcOpPrepend },
2243 { "prepend_first", FcOpPrependFirst },
2244 { "append", FcOpAppend },
2245 { "append_last", FcOpAppendLast },
2248 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2251 FcConfigLexMode (const FcChar8 *mode)
2253 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2257 FcParseEdit (FcConfigParse *parse)
2259 const FcChar8 *name;
2260 const FcChar8 *mode_string;
2262 FcValueBinding binding;
2266 name = FcConfigGetAttribute (parse, "name");
2269 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2272 mode_string = FcConfigGetAttribute (parse, "mode");
2277 mode = FcConfigLexMode (mode_string);
2278 if (mode == FcOpInvalid)
2280 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2284 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2287 expr = FcPopBinary (parse, FcOpComma);
2288 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2289 mode, expr, binding);
2292 FcConfigMessage (parse, FcSevereError, "out of memory");
2293 FcExprDestroy (expr);
2296 if (!FcVStackPushEdit (parse, edit))
2297 FcEditDestroy (edit);
2301 FcParseMatch (FcConfigParse *parse)
2303 const FcChar8 *kind_name;
2309 kind_name = FcConfigGetAttribute (parse, "target");
2311 kind = FcMatchPattern;
2314 if (!strcmp ((char *) kind_name, "pattern"))
2315 kind = FcMatchPattern;
2316 else if (!strcmp ((char *) kind_name, "font"))
2318 else if (!strcmp ((char *) kind_name, "scan"))
2322 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2326 while ((vstack = FcVStackPeek (parse)))
2328 switch ((int) vstack->tag) {
2330 vstack->u.test->next = test;
2331 test = vstack->u.test;
2332 vstack->tag = FcVStackNone;
2335 vstack->u.edit->next = edit;
2336 edit = vstack->u.edit;
2337 vstack->tag = FcVStackNone;
2338 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
2340 FcConfigMessage (parse, FcSevereError,
2341 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2342 FcObjectName(edit->object));
2346 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2349 FcVStackPopAndDestroy (parse);
2351 if (!FcConfigAddEdit (parse->config, test, edit, kind))
2352 FcConfigMessage (parse, FcSevereError, "out of memory");
2356 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2360 while ((vstack = FcVStackPeek (parse)))
2362 switch ((int) vstack->tag) {
2364 if (!FcConfigGlobAdd (parse->config,
2366 element == FcElementAcceptfont))
2368 FcConfigMessage (parse, FcSevereError, "out of memory");
2371 case FcVStackPattern:
2372 if (!FcConfigPatternsAdd (parse->config,
2374 element == FcElementAcceptfont))
2376 FcConfigMessage (parse, FcSevereError, "out of memory");
2379 vstack->tag = FcVStackNone;
2382 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2385 FcVStackPopAndDestroy (parse);
2391 FcPopValue (FcConfigParse *parse)
2393 FcVStack *vstack = FcVStackPeek (parse);
2396 value.type = FcTypeVoid;
2401 switch ((int) vstack->tag) {
2402 case FcVStackString:
2403 value.u.s = FcSharedStr (vstack->u.string);
2405 value.type = FcTypeString;
2407 case FcVStackConstant:
2408 if (FcNameConstant (vstack->u.string, &value.u.i))
2409 value.type = FcTypeInteger;
2411 case FcVStackInteger:
2412 value.u.i = vstack->u.integer;
2413 value.type = FcTypeInteger;
2415 case FcVStackDouble:
2416 value.u.d = vstack->u._double;
2417 value.type = FcTypeDouble;
2420 value.u.b = vstack->u.bool_;
2421 value.type = FcTypeBool;
2423 case FcVStackCharSet:
2424 value.u.c = FcCharSetCopy (vstack->u.charset);
2426 value.type = FcTypeCharSet;
2428 case FcVStackLangSet:
2429 value.u.l = FcLangSetCopy (vstack->u.langset);
2431 value.type = FcTypeLangSet;
2434 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2438 FcVStackPopAndDestroy (parse);
2444 FcParsePatelt (FcConfigParse *parse)
2447 FcPattern *pattern = FcPatternCreate ();
2452 FcConfigMessage (parse, FcSevereError, "out of memory");
2456 name = (char *) FcConfigGetAttribute (parse, "name");
2459 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2460 FcPatternDestroy (pattern);
2466 value = FcPopValue (parse);
2467 if (value.type == FcTypeVoid)
2469 if (!FcPatternAdd (pattern, name, value, FcTrue))
2471 FcConfigMessage (parse, FcSevereError, "out of memory");
2472 FcValueDestroy(value);
2475 FcValueDestroy(value);
2478 FcVStackPushPattern (parse, pattern);
2482 FcParsePattern (FcConfigParse *parse)
2485 FcPattern *pattern = FcPatternCreate ();
2489 FcConfigMessage (parse, FcSevereError, "out of memory");
2493 while ((vstack = FcVStackPeek (parse)))
2495 switch ((int) vstack->tag) {
2496 case FcVStackPattern:
2497 if (!FcPatternAppend (pattern, vstack->u.pattern))
2499 FcConfigMessage (parse, FcSevereError, "out of memory");
2500 FcPatternDestroy (pattern);
2505 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2508 FcVStackPopAndDestroy (parse);
2511 FcVStackPushPattern (parse, pattern);
2515 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2517 FcConfigParse *parse = userData;
2522 switch (parse->pstack->element) {
2525 case FcElementFontconfig:
2530 case FcElementCacheDir:
2531 FcParseCacheDir (parse);
2533 case FcElementCache:
2534 data = FcStrBufDoneStatic (&parse->pstack->str);
2537 FcConfigMessage (parse, FcSevereError, "out of memory");
2540 /* discard this data; no longer used */
2541 FcStrBufDestroy (&parse->pstack->str);
2543 case FcElementInclude:
2544 FcParseInclude (parse);
2546 case FcElementConfig:
2548 case FcElementMatch:
2549 FcParseMatch (parse);
2551 case FcElementAlias:
2552 FcParseAlias (parse);
2555 case FcElementBlank:
2556 FcParseBlank (parse);
2558 case FcElementRescan:
2559 FcParseRescan (parse);
2562 case FcElementPrefer:
2563 FcParseFamilies (parse, FcVStackPrefer);
2565 case FcElementAccept:
2566 FcParseFamilies (parse, FcVStackAccept);
2568 case FcElementDefault:
2569 FcParseFamilies (parse, FcVStackDefault);
2571 case FcElementFamily:
2572 FcParseFamily (parse);
2576 FcParseTest (parse);
2579 FcParseEdit (parse);
2585 case FcElementDouble:
2586 FcParseDouble (parse);
2588 case FcElementString:
2589 FcParseString (parse, FcVStackString);
2591 case FcElementMatrix:
2592 FcParseMatrix (parse);
2594 case FcElementRange:
2595 FcParseRange (parse);
2598 FcParseBool (parse);
2600 case FcElementCharSet:
2601 FcParseCharSet (parse);
2603 case FcElementLangSet:
2604 FcParseLangSet (parse);
2606 case FcElementSelectfont:
2608 case FcElementAcceptfont:
2609 case FcElementRejectfont:
2610 FcParseAcceptRejectFont (parse, parse->pstack->element);
2613 FcParseString (parse, FcVStackGlob);
2615 case FcElementPattern:
2616 FcParsePattern (parse);
2618 case FcElementPatelt:
2619 FcParsePatelt (parse);
2622 FcParseString (parse, FcVStackField);
2624 case FcElementConst:
2625 FcParseString (parse, FcVStackConstant);
2628 FcParseBinary (parse, FcOpOr);
2631 FcParseBinary (parse, FcOpAnd);
2634 FcParseBinary (parse, FcOpEqual);
2636 case FcElementNotEq:
2637 FcParseBinary (parse, FcOpNotEqual);
2640 FcParseBinary (parse, FcOpLess);
2642 case FcElementLessEq:
2643 FcParseBinary (parse, FcOpLessEqual);
2646 FcParseBinary (parse, FcOpMore);
2648 case FcElementMoreEq:
2649 FcParseBinary (parse, FcOpMoreEqual);
2651 case FcElementContains:
2652 FcParseBinary (parse, FcOpContains);
2654 case FcElementNotContains:
2655 FcParseBinary (parse, FcOpNotContains);
2658 FcParseBinary (parse, FcOpPlus);
2660 case FcElementMinus:
2661 FcParseBinary (parse, FcOpMinus);
2663 case FcElementTimes:
2664 FcParseBinary (parse, FcOpTimes);
2666 case FcElementDivide:
2667 FcParseBinary (parse, FcOpDivide);
2670 FcParseUnary (parse, FcOpNot);
2673 FcParseBinary (parse, FcOpQuest);
2675 case FcElementFloor:
2676 FcParseUnary (parse, FcOpFloor);
2679 FcParseUnary (parse, FcOpCeil);
2681 case FcElementRound:
2682 FcParseUnary (parse, FcOpRound);
2684 case FcElementTrunc:
2685 FcParseUnary (parse, FcOpTrunc);
2687 case FcElementUnknown:
2690 (void) FcPStackPop (parse);
2694 FcCharacterData (void *userData, const XML_Char *s, int len)
2696 FcConfigParse *parse = userData;
2700 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2701 FcConfigMessage (parse, FcSevereError, "out of memory");
2705 FcStartDoctypeDecl (void *userData,
2706 const XML_Char *doctypeName,
2707 const XML_Char *sysid FC_UNUSED,
2708 const XML_Char *pubid FC_UNUSED,
2709 int has_internal_subset FC_UNUSED)
2711 FcConfigParse *parse = userData;
2713 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2714 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2717 #ifdef ENABLE_LIBXML2
2720 FcInternalSubsetDecl (void *userData,
2721 const XML_Char *doctypeName,
2722 const XML_Char *sysid,
2723 const XML_Char *pubid)
2725 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2729 FcExternalSubsetDecl (void *userData,
2730 const XML_Char *doctypeName,
2731 const XML_Char *sysid,
2732 const XML_Char *pubid)
2734 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2737 #else /* ENABLE_LIBXML2 */
2740 FcEndDoctypeDecl (void *userData FC_UNUSED)
2744 #endif /* ENABLE_LIBXML2 */
2747 FcSortCmpStr (const void *a, const void *b)
2749 const FcChar8 *as = *((FcChar8 **) a);
2750 const FcChar8 *bs = *((FcChar8 **) b);
2751 return FcStrCmp (as, bs);
2755 FcConfigParseAndLoadDir (FcConfig *config,
2756 const FcChar8 *name,
2762 FcBool ret = FcTrue;
2767 d = opendir ((char *) dir);
2771 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2777 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2784 strcpy ((char *) file, (char *) dir);
2785 strcat ((char *) file, "/");
2786 base = file + strlen ((char *) file);
2788 files = FcStrSetCreate ();
2795 if (FcDebug () & FC_DBG_CONFIG)
2796 printf ("\tScanning config dir %s\n", dir);
2798 while (ret && (e = readdir (d)))
2801 #define TAIL ".conf"
2804 * Add all files of the form [0-9]*.conf
2806 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2807 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2809 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2811 strcpy ((char *) base, (char *) e->d_name);
2812 if (!FcStrSetAdd (files, file))
2822 qsort (files->strs, files->num, sizeof (FcChar8 *),
2823 (int (*)(const void *, const void *)) FcSortCmpStr);
2824 for (i = 0; ret && i < files->num; i++)
2825 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2828 FcStrSetDestroy (files);
2834 return ret || !complain;
2838 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
2839 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
2843 FcConfigParseAndLoad (FcConfig *config,
2844 const FcChar8 *name,
2852 FcConfigParse parse;
2853 FcBool error = FcTrue;
2855 #ifdef ENABLE_LIBXML2
2863 if (!pGetSystemWindowsDirectory)
2865 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
2866 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
2867 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
2869 if (!pSHGetFolderPathA)
2871 HMODULE hSh = LoadLibraryA("shfolder.dll");
2872 /* the check is done later, because there is no provided fallback */
2874 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
2878 filename = FcConfigFilename (name);
2882 if (FcStrSetMember (config->configFiles, filename))
2884 FcStrFree (filename);
2888 if (!FcStrSetAdd (config->configFiles, filename))
2890 FcStrFree (filename);
2894 if (FcFileIsDir (filename))
2896 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2897 FcStrFree (filename);
2901 if (FcDebug () & FC_DBG_CONFIG)
2902 printf ("\tLoading config file %s\n", filename);
2904 fd = open ((char *) filename, O_RDONLY);
2906 FcStrFree (filename);
2910 #ifdef ENABLE_LIBXML2
2911 memset(&sax, 0, sizeof(sax));
2913 sax.internalSubset = FcInternalSubsetDecl;
2914 sax.externalSubset = FcExternalSubsetDecl;
2915 sax.startElement = FcStartElement;
2916 sax.endElement = FcEndElement;
2917 sax.characters = FcCharacterData;
2919 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2921 p = XML_ParserCreate ("UTF-8");
2923 FcStrFree (filename);
2928 if (!FcConfigInit (&parse, name, config, p))
2931 #ifndef ENABLE_LIBXML2
2933 XML_SetUserData (p, &parse);
2935 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2936 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2937 XML_SetCharacterDataHandler (p, FcCharacterData);
2939 #endif /* ENABLE_LIBXML2 */
2942 #ifndef ENABLE_LIBXML2
2943 buf = XML_GetBuffer (p, BUFSIZ);
2946 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2950 len = read (fd, buf, BUFSIZ);
2953 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2957 #ifdef ENABLE_LIBXML2
2958 if (xmlParseChunk (p, buf, len, len == 0))
2960 if (!XML_ParseBuffer (p, len, len == 0))
2963 FcConfigMessage (&parse, FcSevereError, "%s",
2964 XML_ErrorString (XML_GetErrorCode (p)));
2968 error = parse.error;
2970 FcConfigCleanup (&parse);
2977 if (error && complain)
2980 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2982 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2988 #include "fcaliastail.h"