2 * fontconfig/src/fcxml.c
4 * Copyright © 2002 Keith Packard
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
32 #include <libxml/parser.h>
34 #define XML_Char xmlChar
35 #define XML_Parser xmlParserCtxtPtr
36 #define XML_ParserFree xmlFreeParserCtxt
37 #define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
38 #define XML_GetErrorCode xmlCtxtGetLastError
39 #define XML_ErrorString(Error) (Error)->message
41 #else /* ENABLE_LIBXML2 */
43 #ifndef HAVE_XMLPARSE_H
44 #define HAVE_XMLPARSE_H 0
53 #endif /* ENABLE_LIBXML2 */
60 FcExprDestroy (FcExpr *e);
63 FcTestDestroy (FcTest *test)
65 FcExprDestroy (test->expr);
70 FcRuleDestroy (FcRule *rule)
72 FcRule *n = rule->next;
76 FcTestDestroy (rule->u.test);
79 FcEditDestroy (rule->u.edit);
90 FcExprCreateInteger (FcConfig *config, int i)
92 FcExpr *e = FcConfigAllocExpr (config);
102 FcExprCreateDouble (FcConfig *config, double d)
104 FcExpr *e = FcConfigAllocExpr (config);
114 FcExprCreateString (FcConfig *config, const FcChar8 *s)
116 FcExpr *e = FcConfigAllocExpr (config);
120 e->u.sval = FcStrdup (s);
125 static FcExprMatrix *
126 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
128 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
137 FcExprMatrixFreeShallow (FcExprMatrix *m)
146 FcExprMatrixFree (FcExprMatrix *m)
151 FcExprDestroy (m->xx);
152 FcExprDestroy (m->xy);
153 FcExprDestroy (m->yx);
154 FcExprDestroy (m->yy);
160 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
162 FcExpr *e = FcConfigAllocExpr (config);
166 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
172 FcExprCreateBool (FcConfig *config, FcBool b)
174 FcExpr *e = FcConfigAllocExpr (config);
184 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
186 FcExpr *e = FcConfigAllocExpr (config);
190 e->u.cval = FcCharSetCopy (charset);
196 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
198 FcExpr *e = FcConfigAllocExpr (config);
202 e->u.lval = FcLangSetCopy (langset);
208 FcExprCreateName (FcConfig *config, FcExprName name)
210 FcExpr *e = FcConfigAllocExpr (config);
220 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
222 FcExpr *e = FcConfigAllocExpr (config);
226 e->u.constant = FcStrdup (constant);
232 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
234 FcExpr *e = FcConfigAllocExpr (config);
238 e->u.tree.left = left;
239 e->u.tree.right = right;
245 FcExprDestroy (FcExpr *e)
249 switch (FC_OP_GET_OP (e->op)) {
258 FcExprMatrixFree (e->u.mexpr);
263 FcCharSetDestroy (e->u.cval);
266 FcLangSetDestroy (e->u.lval);
273 FcFree (e->u.constant);
276 case FcOpAssignReplace:
278 case FcOpPrependFirst:
294 case FcOpNotContains:
301 FcExprDestroy (e->u.tree.right);
308 FcExprDestroy (e->u.tree.left);
319 FcEditDestroy (FcEdit *e)
322 FcExprDestroy (e->expr);
326 typedef enum _FcElement {
373 FcElementNotContains,
387 static const struct {
391 { "fontconfig", FcElementFontconfig },
392 { "dir", FcElementDir },
393 { "cachedir", FcElementCacheDir },
394 { "cache", FcElementCache },
395 { "include", FcElementInclude },
396 { "config", FcElementConfig },
397 { "match", FcElementMatch },
398 { "alias", FcElementAlias },
400 { "blank", FcElementBlank },
401 { "rescan", FcElementRescan },
403 { "prefer", FcElementPrefer },
404 { "accept", FcElementAccept },
405 { "default", FcElementDefault },
406 { "family", FcElementFamily },
408 { "selectfont", FcElementSelectfont },
409 { "acceptfont", FcElementAcceptfont },
410 { "rejectfont", FcElementRejectfont },
411 { "glob", FcElementGlob },
412 { "pattern", FcElementPattern },
413 { "patelt", FcElementPatelt },
415 { "test", FcElementTest },
416 { "edit", FcElementEdit },
417 { "int", FcElementInt },
418 { "double", FcElementDouble },
419 { "string", FcElementString },
420 { "matrix", FcElementMatrix },
421 { "range", FcElementRange },
422 { "bool", FcElementBool },
423 { "charset", FcElementCharSet },
424 { "langset", FcElementLangSet },
425 { "name", FcElementName },
426 { "const", FcElementConst },
427 { "or", FcElementOr },
428 { "and", FcElementAnd },
429 { "eq", FcElementEq },
430 { "not_eq", FcElementNotEq },
431 { "less", FcElementLess },
432 { "less_eq", FcElementLessEq },
433 { "more", FcElementMore },
434 { "more_eq", FcElementMoreEq },
435 { "contains", FcElementContains },
436 { "not_contains", FcElementNotContains },
437 { "plus", FcElementPlus },
438 { "minus", FcElementMinus },
439 { "times", FcElementTimes },
440 { "divide", FcElementDivide },
441 { "not", FcElementNot },
442 { "if", FcElementIf },
443 { "floor", FcElementFloor },
444 { "ceil", FcElementCeil },
445 { "round", FcElementRound },
446 { "trunc", FcElementTrunc },
448 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
451 FcElementMap (const XML_Char *name)
455 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
456 if (!strcmp ((char *) name, fcElementMap[i].name))
457 return fcElementMap[i].element;
458 return FcElementUnknown;
461 typedef struct _FcPStack {
462 struct _FcPStack *prev;
466 FcChar8 *attr_buf_static[16];
469 typedef enum _FcVStackTag {
496 typedef struct _FcVStack {
497 struct _FcVStack *prev;
498 FcPStack *pstack; /* related parse element */
505 FcExprMatrix *matrix;
522 typedef struct _FcConfigParse {
529 unsigned int pstack_static_used;
530 FcPStack pstack_static[8];
531 unsigned int vstack_static_used;
532 FcVStack vstack_static[64];
535 typedef enum _FcConfigSeverity {
536 FcSevereInfo, FcSevereWarning, FcSevereError
540 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
542 const char *s = "unknown";
545 va_start (args, fmt);
548 case FcSevereInfo: s = "info"; break;
549 case FcSevereWarning: s = "warning"; break;
550 case FcSevereError: s = "error"; break;
555 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
556 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
558 fprintf (stderr, "Fontconfig %s: line %d: ", s,
559 (int)XML_GetCurrentLineNumber (parse->parser));
560 if (severe >= FcSevereError)
561 parse->error = FcTrue;
564 fprintf (stderr, "Fontconfig %s: ", s);
565 vfprintf (stderr, fmt, args);
566 fprintf (stderr, "\n");
572 FcPopExpr (FcConfigParse *parse);
576 FcTypeName (FcType type)
602 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
604 if (value == FcTypeInteger)
605 value = FcTypeDouble;
606 if (type == FcTypeInteger)
610 if ((value == FcTypeLangSet && type == FcTypeString) ||
611 (value == FcTypeString && type == FcTypeLangSet))
613 if (type == FcTypeUnknown)
615 /* It's perfectly fine to use user-define elements in expressions,
616 * so don't warn in that case. */
617 if (value == FcTypeUnknown)
619 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
620 FcTypeName (value), FcTypeName (type));
625 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
627 const FcObjectType *o;
630 /* If parsing the expression failed, some nodes may be NULL */
634 switch (FC_OP_GET_OP (expr->op)) {
637 FcTypecheckValue (parse, FcTypeDouble, type);
640 FcTypecheckValue (parse, FcTypeString, type);
643 FcTypecheckValue (parse, FcTypeMatrix, type);
646 FcTypecheckValue (parse, FcTypeBool, type);
649 FcTypecheckValue (parse, FcTypeCharSet, type);
652 FcTypecheckValue (parse, FcTypeLangSet, type);
657 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
659 FcTypecheckValue (parse, o->type, type);
662 c = FcNameGetConstant (expr->u.constant);
665 o = FcNameGetObjectType (c->object);
667 FcTypecheckValue (parse, o->type, type);
670 FcConfigMessage (parse, FcSevereWarning,
671 "invalid constant used : %s",
675 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
676 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
677 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
680 case FcOpAssignReplace:
689 case FcOpNotContains:
691 FcTypecheckValue (parse, FcTypeBool, type);
700 FcTypecheckExpr (parse, expr->u.tree.left, type);
701 FcTypecheckExpr (parse, expr->u.tree.right, type);
704 FcTypecheckValue (parse, FcTypeBool, type);
705 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
711 FcTypecheckValue (parse, FcTypeDouble, type);
712 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
720 FcTestCreate (FcConfigParse *parse,
723 const FcChar8 *field,
724 unsigned int compare,
727 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
731 const FcObjectType *o;
735 test->object = FcObjectFromName ((const char *) field);
738 o = FcNameGetObjectType (FcObjectName (test->object));
740 FcTypecheckExpr (parse, expr, o->type);
746 FcEditCreate (FcConfigParse *parse,
750 FcValueBinding binding)
752 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
756 const FcObjectType *o;
761 e->binding = binding;
762 o = FcNameGetObjectType (FcObjectName (e->object));
764 FcTypecheckExpr (parse, expr, o->type);
770 FcRuleCreate (FcRuleType type,
773 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
783 r->u.test = (FcTest *) p;
786 r->u.edit = (FcEdit *) p;
798 FcVStackCreateAndPush (FcConfigParse *parse)
802 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
803 new = &parse->vstack_static[parse->vstack_static_used++];
806 new = malloc (sizeof (FcVStack));
810 new->tag = FcVStackNone;
813 new->prev = parse->vstack;
814 new->pstack = parse->pstack ? parse->pstack->prev : 0;
821 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
823 FcVStack *vstack = FcVStackCreateAndPush (parse);
826 vstack->u.string = string;
832 FcVStackPushInteger (FcConfigParse *parse, int integer)
834 FcVStack *vstack = FcVStackCreateAndPush (parse);
837 vstack->u.integer = integer;
838 vstack->tag = FcVStackInteger;
843 FcVStackPushDouble (FcConfigParse *parse, double _double)
845 FcVStack *vstack = FcVStackCreateAndPush (parse);
848 vstack->u._double = _double;
849 vstack->tag = FcVStackDouble;
854 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
857 vstack = FcVStackCreateAndPush (parse);
860 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
861 vstack->tag = FcVStackMatrix;
866 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
868 FcVStack *vstack = FcVStackCreateAndPush (parse);
871 vstack->u.range.begin = range->begin;
872 vstack->u.range.end = range->end;
873 vstack->tag = FcVStackRange;
878 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
880 FcVStack *vstack = FcVStackCreateAndPush (parse);
883 vstack->u.bool_ = bool_;
884 vstack->tag = FcVStackBool;
889 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
894 vstack = FcVStackCreateAndPush (parse);
897 vstack->u.charset = charset;
898 vstack->tag = FcVStackCharSet;
903 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
908 vstack = FcVStackCreateAndPush (parse);
911 vstack->u.langset = langset;
912 vstack->tag = FcVStackLangSet;
917 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
919 FcVStack *vstack = FcVStackCreateAndPush (parse);
922 vstack->u.name.object = object;
923 vstack->u.name.kind = kind;
924 vstack->tag = FcVStackName;
929 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
931 FcVStack *vstack = FcVStackCreateAndPush (parse);
934 vstack->u.test = test;
935 vstack->tag = FcVStackTest;
940 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
942 FcVStack *vstack = FcVStackCreateAndPush (parse);
945 vstack->u.expr = expr;
951 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
953 FcVStack *vstack = FcVStackCreateAndPush (parse);
956 vstack->u.edit = edit;
957 vstack->tag = FcVStackEdit;
962 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
964 FcVStack *vstack = FcVStackCreateAndPush (parse);
967 vstack->u.pattern = pattern;
968 vstack->tag = FcVStackPattern;
973 FcVStackFetch (FcConfigParse *parse, int off)
977 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
982 FcVStackPeek (FcConfigParse *parse)
984 FcVStack *vstack = parse->vstack;
986 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
990 FcVStackPopAndDestroy (FcConfigParse *parse)
992 FcVStack *vstack = parse->vstack;
994 if (!vstack || vstack->pstack != parse->pstack)
997 parse->vstack = vstack->prev;
999 switch (vstack->tag) {
1004 case FcVStackFamily:
1006 case FcVStackString:
1007 case FcVStackConstant:
1009 FcStrFree (vstack->u.string);
1011 case FcVStackPattern:
1012 FcPatternDestroy (vstack->u.pattern);
1014 case FcVStackInteger:
1015 case FcVStackDouble:
1017 case FcVStackMatrix:
1018 FcExprMatrixFreeShallow (vstack->u.matrix);
1023 case FcVStackCharSet:
1024 FcCharSetDestroy (vstack->u.charset);
1026 case FcVStackLangSet:
1027 FcLangSetDestroy (vstack->u.langset);
1030 FcTestDestroy (vstack->u.test);
1033 case FcVStackPrefer:
1034 case FcVStackAccept:
1035 case FcVStackDefault:
1036 FcExprDestroy (vstack->u.expr);
1039 FcEditDestroy (vstack->u.edit);
1043 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1044 parse->vstack_static_used--;
1050 FcVStackClear (FcConfigParse *parse)
1052 while (FcVStackPeek (parse))
1053 FcVStackPopAndDestroy (parse);
1057 FcVStackElements (FcConfigParse *parse)
1060 FcVStack *vstack = parse->vstack;
1061 while (vstack && vstack->pstack == parse->pstack)
1064 vstack = vstack->prev;
1070 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1080 for (i = 0; attr[i]; i++)
1081 slen += strlen ((char *) attr[i]) + 1;
1084 slen += (i + 1) * sizeof (FcChar8 *);
1085 if (slen <= size_bytes)
1089 new = malloc (slen);
1092 FcConfigMessage (0, FcSevereError, "out of memory");
1096 s = (FcChar8 *) (new + (i + 1));
1097 for (i = 0; attr[i]; i++)
1100 strcpy ((char *) s, (char *) attr[i]);
1101 s += strlen ((char *) s) + 1;
1108 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1112 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1113 new = &parse->pstack_static[parse->pstack_static_used++];
1116 new = malloc (sizeof (FcPStack));
1121 new->prev = parse->pstack;
1122 new->element = element;
1123 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1124 FcStrBufInit (&new->str, 0, 0);
1125 parse->pstack = new;
1130 FcPStackPop (FcConfigParse *parse)
1136 FcConfigMessage (parse, FcSevereError, "mismatching element");
1140 if (parse->pstack->attr)
1142 /* Warn about unused attrs. */
1143 FcChar8 **attrs = parse->pstack->attr;
1148 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1154 FcVStackClear (parse);
1155 old = parse->pstack;
1156 parse->pstack = old->prev;
1157 FcStrBufDestroy (&old->str);
1159 if (old->attr && old->attr != old->attr_buf_static)
1162 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1163 parse->pstack_static_used--;
1170 FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1173 parse->pstack_static_used = 0;
1175 parse->vstack_static_used = 0;
1176 parse->error = FcFalse;
1178 parse->config = config;
1179 parse->parser = parser;
1184 FcConfigCleanup (FcConfigParse *parse)
1186 while (parse->pstack)
1187 FcPStackPop (parse);
1190 static const FcChar8 *
1191 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1197 attrs = parse->pstack->attr;
1203 if (!strcmp ((char *) *attrs, attr))
1205 attrs[0][0] = '\0'; /* Mark as used. */
1214 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1216 FcConfigParse *parse = userData;
1219 element = FcElementMap (name);
1220 if (element == FcElementUnknown)
1221 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1223 if (!FcPStackPush (parse, element, attr))
1225 FcConfigMessage (parse, FcSevereError, "out of memory");
1232 FcParseBlank (FcConfigParse *parse)
1234 int n = FcVStackElements (parse);
1238 FcVStack *v = FcVStackFetch (parse, n);
1239 if (!parse->config->blanks)
1241 parse->config->blanks = FcBlanksCreate ();
1242 if (!parse->config->blanks)
1245 switch ((int) v->tag) {
1246 case FcVStackInteger:
1247 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1251 if (v->u.range.begin <= v->u.range.end)
1253 for (i = v->u.range.begin; i <= v->u.range.end; i++)
1255 if (!FcBlanksAdd (parse->config->blanks, i))
1261 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1267 FcConfigMessage (parse, FcSevereError, "out of memory");
1271 FcParseRescan (FcConfigParse *parse)
1273 int n = FcVStackElements (parse);
1276 FcVStack *v = FcVStackFetch (parse, n);
1277 if (v->tag != FcVStackInteger)
1278 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1280 parse->config->rescanInterval = v->u.integer;
1285 FcParseInt (FcConfigParse *parse)
1292 s = FcStrBufDoneStatic (&parse->pstack->str);
1295 FcConfigMessage (parse, FcSevereError, "out of memory");
1299 l = (int) strtol ((char *) s, (char **)&end, 0);
1300 if (end != s + strlen ((char *) s))
1301 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1303 FcVStackPushInteger (parse, l);
1304 FcStrBufDestroy (&parse->pstack->str);
1308 * idea copied from glib g_ascii_strtod with
1309 * permission of the author (Alexander Larsson)
1315 FcStrtod (char *s, char **end)
1317 struct lconv *locale_data;
1322 * Have to swap the decimal point to match the current locale
1323 * if that locale doesn't use 0x2e
1325 if ((dot = strchr (s, 0x2e)) &&
1326 (locale_data = localeconv ()) &&
1327 (locale_data->decimal_point[0] != 0x2e ||
1328 locale_data->decimal_point[1] != 0))
1331 int slen = strlen (s);
1332 int dlen = strlen (locale_data->decimal_point);
1334 if (slen + dlen > (int) sizeof (buf))
1344 strncpy (buf, s, dot - s);
1346 strcpy (buf + (dot - s), locale_data->decimal_point);
1347 /* rest of number */
1348 strcpy (buf + (dot - s) + dlen, dot + 1);
1350 v = strtod (buf, &buf_end);
1352 buf_end = s + (buf_end - buf);
1354 buf_end -= dlen - 1;
1361 v = strtod (s, end);
1366 FcParseDouble (FcConfigParse *parse)
1373 s = FcStrBufDoneStatic (&parse->pstack->str);
1376 FcConfigMessage (parse, FcSevereError, "out of memory");
1380 d = FcStrtod ((char *) s, (char **)&end);
1381 if (end != s + strlen ((char *) s))
1382 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1384 FcVStackPushDouble (parse, d);
1385 FcStrBufDestroy (&parse->pstack->str);
1389 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1395 s = FcStrBufDone (&parse->pstack->str);
1398 FcConfigMessage (parse, FcSevereError, "out of memory");
1401 if (!FcVStackPushString (parse, tag, s))
1406 FcParseName (FcConfigParse *parse)
1408 const FcChar8 *kind_string;
1413 kind_string = FcConfigGetAttribute (parse, "target");
1415 kind = FcMatchDefault;
1418 if (!strcmp ((char *) kind_string, "pattern"))
1419 kind = FcMatchPattern;
1420 else if (!strcmp ((char *) kind_string, "font"))
1422 else if (!strcmp ((char *) kind_string, "default"))
1423 kind = FcMatchDefault;
1426 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1433 s = FcStrBufDone (&parse->pstack->str);
1436 FcConfigMessage (parse, FcSevereError, "out of memory");
1439 object = FcObjectFromName ((const char *) s);
1441 FcVStackPushName (parse, kind, object);
1447 FcParseMatrix (FcConfigParse *parse)
1451 m.yy = FcPopExpr (parse);
1452 m.yx = FcPopExpr (parse);
1453 m.xy = FcPopExpr (parse);
1454 m.xx = FcPopExpr (parse);
1456 if (FcPopExpr (parse))
1457 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1459 FcVStackPushMatrix (parse, &m);
1463 FcParseRange (FcConfigParse *parse)
1470 while ((vstack = FcVStackPeek (parse)))
1474 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1477 switch ((int) vstack->tag) {
1478 case FcVStackInteger:
1479 n = vstack->u.integer;
1482 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1491 FcVStackPopAndDestroy (parse);
1495 if (r.begin > r.end)
1497 FcConfigMessage (parse, FcSevereError, "invalid range");
1500 FcVStackPushRange (parse, &r);
1503 FcConfigMessage (parse, FcSevereError, "invalid range");
1507 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1509 FcBool result = FcFalse;
1511 if (!FcNameBool (bool_, &result))
1512 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1518 FcParseBool (FcConfigParse *parse)
1524 s = FcStrBufDoneStatic (&parse->pstack->str);
1527 FcConfigMessage (parse, FcSevereError, "out of memory");
1530 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1531 FcStrBufDestroy (&parse->pstack->str);
1535 FcParseCharSet (FcConfigParse *parse)
1538 FcCharSet *charset = FcCharSetCreate ();
1542 while ((vstack = FcVStackPeek (parse)))
1544 switch ((int) vstack->tag) {
1545 case FcVStackInteger:
1546 if (!FcCharSetAddChar (charset, vstack->u.integer))
1548 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1554 if (vstack->u.range.begin <= vstack->u.range.end)
1556 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1558 if (!FcCharSetAddChar (charset, i))
1560 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1568 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1571 FcVStackPopAndDestroy (parse);
1574 FcVStackPushCharSet (parse, charset);
1576 FcCharSetDestroy (charset);
1580 FcParseLangSet (FcConfigParse *parse)
1583 FcLangSet *langset = FcLangSetCreate ();
1586 while ((vstack = FcVStackPeek (parse)))
1588 switch ((int) vstack->tag) {
1589 case FcVStackString:
1590 if (!FcLangSetAdd (langset, vstack->u.string))
1592 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1598 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1601 FcVStackPopAndDestroy (parse);
1604 FcVStackPushLangSet (parse, langset);
1606 FcLangSetDestroy (langset);
1610 FcConfigLexBinding (FcConfigParse *parse,
1611 const FcChar8 *binding_string,
1612 FcValueBinding *binding_ret)
1614 FcValueBinding binding;
1616 if (!binding_string)
1617 binding = FcValueBindingWeak;
1620 if (!strcmp ((char *) binding_string, "weak"))
1621 binding = FcValueBindingWeak;
1622 else if (!strcmp ((char *) binding_string, "strong"))
1623 binding = FcValueBindingStrong;
1624 else if (!strcmp ((char *) binding_string, "same"))
1625 binding = FcValueBindingSame;
1628 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1632 *binding_ret = binding;
1637 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1640 FcExpr *left, *expr = 0, *new;
1642 while ((vstack = FcVStackPeek (parse)))
1644 if (vstack->tag != FcVStackFamily)
1646 FcConfigMessage (parse, FcSevereWarning, "non-family");
1647 FcVStackPopAndDestroy (parse);
1650 left = vstack->u.expr;
1651 vstack->tag = FcVStackNone;
1652 FcVStackPopAndDestroy (parse);
1655 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1658 FcConfigMessage (parse, FcSevereError, "out of memory");
1659 FcExprDestroy (left);
1660 FcExprDestroy (expr);
1670 if (!FcVStackPushExpr (parse, tag, expr))
1672 FcConfigMessage (parse, FcSevereError, "out of memory");
1673 FcExprDestroy (expr);
1679 FcParseFamily (FcConfigParse *parse)
1686 s = FcStrBufDoneStatic (&parse->pstack->str);
1689 FcConfigMessage (parse, FcSevereError, "out of memory");
1692 expr = FcExprCreateString (parse->config, s);
1693 FcStrBufDestroy (&parse->pstack->str);
1695 FcVStackPushExpr (parse, FcVStackFamily, expr);
1699 FcParseAlias (FcConfigParse *parse)
1701 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1704 FcRule *rule = NULL, *r;
1705 FcValueBinding binding;
1707 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1709 while ((vstack = FcVStackPeek (parse)))
1711 switch ((int) vstack->tag) {
1712 case FcVStackFamily:
1715 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1716 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1718 FcConfigMessage (parse, FcSevereError, "out of memory");
1723 new = vstack->u.expr;
1727 vstack->tag = FcVStackNone;
1730 case FcVStackPrefer:
1732 FcExprDestroy (prefer);
1733 prefer = vstack->u.expr;
1734 vstack->tag = FcVStackNone;
1736 case FcVStackAccept:
1738 FcExprDestroy (accept);
1739 accept = vstack->u.expr;
1740 vstack->tag = FcVStackNone;
1742 case FcVStackDefault:
1744 FcExprDestroy (def);
1745 def = vstack->u.expr;
1746 vstack->tag = FcVStackNone;
1751 r = FcRuleCreate (FcRuleTest, vstack->u.test);
1756 rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1757 vstack->tag = FcVStackNone;
1760 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1763 FcVStackPopAndDestroy (parse);
1767 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1769 FcExprDestroy (prefer);
1771 FcExprDestroy (accept);
1773 FcExprDestroy (def);
1775 FcRuleDestroy (rule);
1782 FcExprDestroy (family);
1787 FcTest *t = FcTestCreate (parse, FcMatchPattern,
1789 (FcChar8 *) FC_FAMILY,
1790 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1794 for (r = rule; r->next; r = r->next);
1795 r->next = FcRuleCreate (FcRuleTest, t);
1800 r = rule = FcRuleCreate (FcRuleTest, t);
1805 edit = FcEditCreate (parse,
1811 FcExprDestroy (prefer);
1814 r->next = FcRuleCreate (FcRuleEdit, edit);
1820 edit = FcEditCreate (parse,
1826 FcExprDestroy (accept);
1829 r->next = FcRuleCreate (FcRuleEdit, edit);
1835 edit = FcEditCreate (parse,
1841 FcExprDestroy (def);
1844 r->next = FcRuleCreate (FcRuleEdit, edit);
1848 if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
1849 FcRuleDestroy (rule);
1853 FcPopExpr (FcConfigParse *parse)
1855 FcVStack *vstack = FcVStackPeek (parse);
1859 switch ((int) vstack->tag) {
1862 case FcVStackString:
1863 case FcVStackFamily:
1864 expr = FcExprCreateString (parse->config, vstack->u.string);
1867 expr = FcExprCreateName (parse->config, vstack->u.name);
1869 case FcVStackConstant:
1870 expr = FcExprCreateConst (parse->config, vstack->u.string);
1873 /* XXX: What's the correct action here? (CDW) */
1875 case FcVStackPrefer:
1876 case FcVStackAccept:
1877 case FcVStackDefault:
1878 expr = vstack->u.expr;
1879 vstack->tag = FcVStackNone;
1881 case FcVStackInteger:
1882 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1884 case FcVStackDouble:
1885 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1887 case FcVStackMatrix:
1888 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1893 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1895 case FcVStackCharSet:
1896 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1898 case FcVStackLangSet:
1899 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1904 expr = vstack->u.expr;
1905 vstack->tag = FcVStackNone;
1912 FcVStackPopAndDestroy (parse);
1917 * This builds a tree of binary operations. Note
1918 * that every operator is defined so that if only
1919 * a single operand is contained, the value of the
1920 * whole expression is the value of the operand.
1922 * This code reduces in that case to returning that
1926 FcPopBinary (FcConfigParse *parse, FcOp op)
1928 FcExpr *left, *expr = 0, *new;
1930 while ((left = FcPopExpr (parse)))
1934 new = FcExprCreateOp (parse->config, left, op, expr);
1937 FcConfigMessage (parse, FcSevereError, "out of memory");
1938 FcExprDestroy (left);
1939 FcExprDestroy (expr);
1951 FcParseBinary (FcConfigParse *parse, FcOp op)
1953 FcExpr *expr = FcPopBinary (parse, op);
1955 FcVStackPushExpr (parse, FcVStackExpr, expr);
1959 * This builds a a unary operator, it consumes only
1964 FcPopUnary (FcConfigParse *parse, FcOp op)
1966 FcExpr *operand, *new = 0;
1968 if ((operand = FcPopExpr (parse)))
1970 new = FcExprCreateOp (parse->config, operand, op, 0);
1973 FcExprDestroy (operand);
1974 FcConfigMessage (parse, FcSevereError, "out of memory");
1981 FcParseUnary (FcConfigParse *parse, FcOp op)
1983 FcExpr *expr = FcPopUnary (parse, op);
1985 FcVStackPushExpr (parse, FcVStackExpr, expr);
1989 FcParseDir (FcConfigParse *parse)
1991 const FcChar8 *attr, *data;
1992 FcChar8 *prefix = NULL, *p;
1994 FcChar8 buffer[1000];
1997 attr = FcConfigGetAttribute (parse, "prefix");
1998 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1999 prefix = FcConfigXdgDataHome ();
2000 data = FcStrBufDoneStatic (&parse->pstack->str);
2003 FcConfigMessage (parse, FcSevereError, "out of memory");
2009 size_t plen = strlen ((const char *)prefix);
2010 size_t dlen = strlen ((const char *)data);
2012 p = realloc (prefix, plen + 1 + dlen + 1);
2015 FcConfigMessage (parse, FcSevereError, "out of memory");
2019 prefix[plen] = FC_DIR_SEPARATOR;
2020 memcpy (&prefix[plen + 1], data, dlen);
2021 prefix[plen + 1 + dlen] = 0;
2025 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2029 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2031 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2035 * Must use the multi-byte aware function to search
2036 * for backslash because East Asian double-byte code
2037 * pages have characters with backslash as the second
2040 p = _mbsrchr (data, '\\');
2042 strcat ((char *) data, "\\fonts");
2044 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2048 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2050 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2053 p = _mbsrchr (data, '\\');
2055 strcat ((char *) data, "\\..\\share\\fonts");
2057 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2061 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2062 if (rc == 0 || rc > sizeof (buffer) - 20)
2064 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2067 if (data [strlen ((const char *) data) - 1] != '\\')
2068 strcat ((char *) data, "\\");
2069 strcat ((char *) data, "fonts");
2072 if (strlen ((char *) data) == 0)
2073 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2074 else if (!FcStrUsesHome (data) || FcConfigHome ())
2076 if (!FcConfigAddDir (parse->config, data))
2077 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2079 FcStrBufDestroy (&parse->pstack->str);
2087 FcParseCacheDir (FcConfigParse *parse)
2089 const FcChar8 *attr;
2090 FcChar8 *prefix = NULL, *p, *data;
2092 attr = FcConfigGetAttribute (parse, "prefix");
2093 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2094 prefix = FcConfigXdgCacheHome ();
2095 data = FcStrBufDone (&parse->pstack->str);
2098 FcConfigMessage (parse, FcSevereError, "out of memory");
2103 size_t plen = strlen ((const char *)prefix);
2104 size_t dlen = strlen ((const char *)data);
2106 p = realloc (prefix, plen + 1 + dlen + 1);
2109 FcConfigMessage (parse, FcSevereError, "out of memory");
2114 prefix[plen] = FC_DIR_SEPARATOR;
2115 memcpy (&prefix[plen + 1], data, dlen);
2116 prefix[plen + 1 + dlen] = 0;
2121 if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2125 data = malloc (1000);
2128 FcConfigMessage (parse, FcSevereError, "out of memory");
2131 rc = GetTempPath (800, (LPSTR) data);
2132 if (rc == 0 || rc > 800)
2134 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2137 if (data [strlen ((const char *) data) - 1] != '\\')
2138 strcat ((char *) data, "\\");
2139 strcat ((char *) data, "fontconfig\\cache");
2141 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2143 char szFPath[MAX_PATH + 1];
2146 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2148 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2151 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2152 len = strlen(szFPath) + 1;
2157 FcConfigMessage (parse, FcSevereError, "out of memory");
2160 strncpy((char *) data, szFPath, len);
2163 if (strlen ((char *) data) == 0)
2164 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2165 else if (!FcStrUsesHome (data) || FcConfigHome ())
2167 if (!FcConfigAddCacheDir (parse->config, data))
2168 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2170 FcStrBufDestroy (&parse->pstack->str);
2178 FcParseInclude (FcConfigParse *parse)
2181 const FcChar8 *attr;
2182 FcBool ignore_missing = FcFalse;
2183 FcBool deprecated = FcFalse;
2184 FcChar8 *prefix = NULL, *p;
2185 static FcChar8 *userdir = NULL;
2186 static FcChar8 *userconf = NULL;
2188 s = FcStrBufDoneStatic (&parse->pstack->str);
2191 FcConfigMessage (parse, FcSevereError, "out of memory");
2194 attr = FcConfigGetAttribute (parse, "ignore_missing");
2195 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2196 ignore_missing = FcTrue;
2197 attr = FcConfigGetAttribute (parse, "deprecated");
2198 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2199 deprecated = FcTrue;
2200 attr = FcConfigGetAttribute (parse, "prefix");
2201 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2202 prefix = FcConfigXdgConfigHome ();
2205 size_t plen = strlen ((const char *)prefix);
2206 size_t dlen = strlen ((const char *)s);
2208 p = realloc (prefix, plen + 1 + dlen + 1);
2211 FcConfigMessage (parse, FcSevereError, "out of memory");
2215 prefix[plen] = FC_DIR_SEPARATOR;
2216 memcpy (&prefix[plen + 1], s, dlen);
2217 prefix[plen + 1 + dlen] = 0;
2219 if (FcFileIsDir (s))
2223 userdir = FcStrdup (s);
2225 else if (FcFileIsFile (s))
2229 userconf = FcStrdup (s);
2233 /* No config dir nor file on the XDG directory spec compliant place
2234 * so need to guess what it is supposed to be.
2236 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2242 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2243 parse->error = FcTrue;
2248 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2250 filename = FcConfigFilename(s);
2251 if (deprecated == FcTrue &&
2253 !FcFileIsLink (filename))
2255 if (FcFileIsDir (filename))
2257 FcChar8 *parent = FcStrDirname (userdir);
2259 if (!FcFileIsDir (parent))
2260 FcMakeDirectory (parent);
2262 if (FcFileIsDir (userdir) ||
2263 rename ((const char *)filename, (const char *)userdir) != 0 ||
2264 symlink ((const char *)userdir, (const char *)filename) != 0)
2268 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2269 warn_confd = FcTrue;
2275 FcChar8 *parent = FcStrDirname (userconf);
2277 if (!FcFileIsDir (parent))
2278 FcMakeDirectory (parent);
2280 if (FcFileIsFile (userconf) ||
2281 rename ((const char *)filename, (const char *)userconf) != 0 ||
2282 symlink ((const char *)userconf, (const char *)filename) != 0)
2286 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2293 FcStrFree(filename);
2296 FcStrBufDestroy (&parse->pstack->str);
2303 typedef struct _FcOpMap {
2309 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2313 for (i = 0; i < nmap; i++)
2314 if (!strcmp ((char *) op, map[i].name))
2319 static const FcOpMap fcCompareOps[] = {
2320 { "eq", FcOpEqual },
2321 { "not_eq", FcOpNotEqual },
2322 { "less", FcOpLess },
2323 { "less_eq", FcOpLessEqual },
2324 { "more", FcOpMore },
2325 { "more_eq", FcOpMoreEqual },
2326 { "contains", FcOpContains },
2327 { "not_contains", FcOpNotContains }
2330 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2333 FcConfigLexCompare (const FcChar8 *compare)
2335 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2339 FcParseTest (FcConfigParse *parse)
2341 const FcChar8 *kind_string;
2343 const FcChar8 *qual_string;
2345 const FcChar8 *name;
2346 const FcChar8 *compare_string;
2350 const FcChar8 *iblanks_string;
2353 kind_string = FcConfigGetAttribute (parse, "target");
2355 kind = FcMatchDefault;
2358 if (!strcmp ((char *) kind_string, "pattern"))
2359 kind = FcMatchPattern;
2360 else if (!strcmp ((char *) kind_string, "font"))
2362 else if (!strcmp ((char *) kind_string, "scan"))
2364 else if (!strcmp ((char *) kind_string, "default"))
2365 kind = FcMatchDefault;
2368 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2372 qual_string = FcConfigGetAttribute (parse, "qual");
2377 if (!strcmp ((char *) qual_string, "any"))
2379 else if (!strcmp ((char *) qual_string, "all"))
2381 else if (!strcmp ((char *) qual_string, "first"))
2383 else if (!strcmp ((char *) qual_string, "not_first"))
2384 qual = FcQualNotFirst;
2387 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2391 name = FcConfigGetAttribute (parse, "name");
2394 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2397 compare_string = FcConfigGetAttribute (parse, "compare");
2398 if (!compare_string)
2399 compare = FcOpEqual;
2402 compare = FcConfigLexCompare (compare_string);
2403 if (compare == FcOpInvalid)
2405 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2409 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2414 if (!FcNameBool (iblanks_string, &f))
2416 FcConfigMessage (parse,
2418 "invalid test ignore-blanks \"%s\"", iblanks_string);
2421 flags |= FcOpFlagIgnoreBlanks;
2423 expr = FcPopBinary (parse, FcOpComma);
2426 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2429 if (expr->op == FcOpComma)
2431 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2433 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2436 FcConfigMessage (parse, FcSevereError, "out of memory");
2439 FcVStackPushTest (parse, test);
2442 static const FcOpMap fcModeOps[] = {
2443 { "assign", FcOpAssign },
2444 { "assign_replace", FcOpAssignReplace },
2445 { "prepend", FcOpPrepend },
2446 { "prepend_first", FcOpPrependFirst },
2447 { "append", FcOpAppend },
2448 { "append_last", FcOpAppendLast },
2449 { "delete", FcOpDelete },
2450 { "delete_all", FcOpDeleteAll },
2453 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2456 FcConfigLexMode (const FcChar8 *mode)
2458 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2462 FcParseEdit (FcConfigParse *parse)
2464 const FcChar8 *name;
2465 const FcChar8 *mode_string;
2467 FcValueBinding binding;
2471 name = FcConfigGetAttribute (parse, "name");
2474 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2477 mode_string = FcConfigGetAttribute (parse, "mode");
2482 mode = FcConfigLexMode (mode_string);
2483 if (mode == FcOpInvalid)
2485 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2489 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2492 expr = FcPopBinary (parse, FcOpComma);
2493 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2496 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2497 FcExprDestroy (expr);
2500 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2501 mode, expr, binding);
2504 FcConfigMessage (parse, FcSevereError, "out of memory");
2505 FcExprDestroy (expr);
2508 if (!FcVStackPushEdit (parse, edit))
2509 FcEditDestroy (edit);
2513 FcParseMatch (FcConfigParse *parse)
2515 const FcChar8 *kind_name;
2518 FcRule *rule = NULL, *r;
2520 kind_name = FcConfigGetAttribute (parse, "target");
2522 kind = FcMatchPattern;
2525 if (!strcmp ((char *) kind_name, "pattern"))
2526 kind = FcMatchPattern;
2527 else if (!strcmp ((char *) kind_name, "font"))
2529 else if (!strcmp ((char *) kind_name, "scan"))
2533 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2537 while ((vstack = FcVStackPeek (parse)))
2539 switch ((int) vstack->tag) {
2541 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2545 vstack->tag = FcVStackNone;
2548 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2550 FcConfigMessage (parse, FcSevereError,
2551 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2552 FcObjectName(vstack->u.edit->object));
2554 FcRuleDestroy (rule);
2557 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2561 vstack->tag = FcVStackNone;
2564 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2567 FcVStackPopAndDestroy (parse);
2571 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2574 if (!FcConfigAddRule (parse->config, rule, kind))
2575 FcConfigMessage (parse, FcSevereError, "out of memory");
2579 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2583 while ((vstack = FcVStackPeek (parse)))
2585 switch ((int) vstack->tag) {
2587 if (!FcConfigGlobAdd (parse->config,
2589 element == FcElementAcceptfont))
2591 FcConfigMessage (parse, FcSevereError, "out of memory");
2594 case FcVStackPattern:
2595 if (!FcConfigPatternsAdd (parse->config,
2597 element == FcElementAcceptfont))
2599 FcConfigMessage (parse, FcSevereError, "out of memory");
2602 vstack->tag = FcVStackNone;
2605 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2608 FcVStackPopAndDestroy (parse);
2614 FcPopValue (FcConfigParse *parse)
2616 FcVStack *vstack = FcVStackPeek (parse);
2619 value.type = FcTypeVoid;
2624 switch ((int) vstack->tag) {
2625 case FcVStackString:
2626 value.u.s = FcStrdup (vstack->u.string);
2628 value.type = FcTypeString;
2630 case FcVStackConstant:
2631 if (FcNameConstant (vstack->u.string, &value.u.i))
2632 value.type = FcTypeInteger;
2634 case FcVStackInteger:
2635 value.u.i = vstack->u.integer;
2636 value.type = FcTypeInteger;
2638 case FcVStackDouble:
2639 value.u.d = vstack->u._double;
2640 value.type = FcTypeDouble;
2643 value.u.b = vstack->u.bool_;
2644 value.type = FcTypeBool;
2646 case FcVStackCharSet:
2647 value.u.c = FcCharSetCopy (vstack->u.charset);
2649 value.type = FcTypeCharSet;
2651 case FcVStackLangSet:
2652 value.u.l = FcLangSetCopy (vstack->u.langset);
2654 value.type = FcTypeLangSet;
2657 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2661 FcVStackPopAndDestroy (parse);
2667 FcParsePatelt (FcConfigParse *parse)
2670 FcPattern *pattern = FcPatternCreate ();
2675 FcConfigMessage (parse, FcSevereError, "out of memory");
2679 name = (char *) FcConfigGetAttribute (parse, "name");
2682 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2683 FcPatternDestroy (pattern);
2689 value = FcPopValue (parse);
2690 if (value.type == FcTypeVoid)
2692 if (!FcPatternAdd (pattern, name, value, FcTrue))
2694 FcConfigMessage (parse, FcSevereError, "out of memory");
2695 FcValueDestroy(value);
2698 FcValueDestroy(value);
2701 FcVStackPushPattern (parse, pattern);
2705 FcParsePattern (FcConfigParse *parse)
2708 FcPattern *pattern = FcPatternCreate ();
2712 FcConfigMessage (parse, FcSevereError, "out of memory");
2716 while ((vstack = FcVStackPeek (parse)))
2718 switch ((int) vstack->tag) {
2719 case FcVStackPattern:
2720 if (!FcPatternAppend (pattern, vstack->u.pattern))
2722 FcConfigMessage (parse, FcSevereError, "out of memory");
2723 FcPatternDestroy (pattern);
2728 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2731 FcVStackPopAndDestroy (parse);
2734 FcVStackPushPattern (parse, pattern);
2738 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2740 FcConfigParse *parse = userData;
2745 switch (parse->pstack->element) {
2748 case FcElementFontconfig:
2753 case FcElementCacheDir:
2754 FcParseCacheDir (parse);
2756 case FcElementCache:
2757 data = FcStrBufDoneStatic (&parse->pstack->str);
2760 FcConfigMessage (parse, FcSevereError, "out of memory");
2763 /* discard this data; no longer used */
2764 FcStrBufDestroy (&parse->pstack->str);
2766 case FcElementInclude:
2767 FcParseInclude (parse);
2769 case FcElementConfig:
2771 case FcElementMatch:
2772 FcParseMatch (parse);
2774 case FcElementAlias:
2775 FcParseAlias (parse);
2778 case FcElementBlank:
2779 FcParseBlank (parse);
2781 case FcElementRescan:
2782 FcParseRescan (parse);
2785 case FcElementPrefer:
2786 FcParseFamilies (parse, FcVStackPrefer);
2788 case FcElementAccept:
2789 FcParseFamilies (parse, FcVStackAccept);
2791 case FcElementDefault:
2792 FcParseFamilies (parse, FcVStackDefault);
2794 case FcElementFamily:
2795 FcParseFamily (parse);
2799 FcParseTest (parse);
2802 FcParseEdit (parse);
2808 case FcElementDouble:
2809 FcParseDouble (parse);
2811 case FcElementString:
2812 FcParseString (parse, FcVStackString);
2814 case FcElementMatrix:
2815 FcParseMatrix (parse);
2817 case FcElementRange:
2818 FcParseRange (parse);
2821 FcParseBool (parse);
2823 case FcElementCharSet:
2824 FcParseCharSet (parse);
2826 case FcElementLangSet:
2827 FcParseLangSet (parse);
2829 case FcElementSelectfont:
2831 case FcElementAcceptfont:
2832 case FcElementRejectfont:
2833 FcParseAcceptRejectFont (parse, parse->pstack->element);
2836 FcParseString (parse, FcVStackGlob);
2838 case FcElementPattern:
2839 FcParsePattern (parse);
2841 case FcElementPatelt:
2842 FcParsePatelt (parse);
2845 FcParseName (parse);
2847 case FcElementConst:
2848 FcParseString (parse, FcVStackConstant);
2851 FcParseBinary (parse, FcOpOr);
2854 FcParseBinary (parse, FcOpAnd);
2857 FcParseBinary (parse, FcOpEqual);
2859 case FcElementNotEq:
2860 FcParseBinary (parse, FcOpNotEqual);
2863 FcParseBinary (parse, FcOpLess);
2865 case FcElementLessEq:
2866 FcParseBinary (parse, FcOpLessEqual);
2869 FcParseBinary (parse, FcOpMore);
2871 case FcElementMoreEq:
2872 FcParseBinary (parse, FcOpMoreEqual);
2874 case FcElementContains:
2875 FcParseBinary (parse, FcOpContains);
2877 case FcElementNotContains:
2878 FcParseBinary (parse, FcOpNotContains);
2881 FcParseBinary (parse, FcOpPlus);
2883 case FcElementMinus:
2884 FcParseBinary (parse, FcOpMinus);
2886 case FcElementTimes:
2887 FcParseBinary (parse, FcOpTimes);
2889 case FcElementDivide:
2890 FcParseBinary (parse, FcOpDivide);
2893 FcParseUnary (parse, FcOpNot);
2896 FcParseBinary (parse, FcOpQuest);
2898 case FcElementFloor:
2899 FcParseUnary (parse, FcOpFloor);
2902 FcParseUnary (parse, FcOpCeil);
2904 case FcElementRound:
2905 FcParseUnary (parse, FcOpRound);
2907 case FcElementTrunc:
2908 FcParseUnary (parse, FcOpTrunc);
2910 case FcElementUnknown:
2913 (void) FcPStackPop (parse);
2917 FcCharacterData (void *userData, const XML_Char *s, int len)
2919 FcConfigParse *parse = userData;
2923 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2924 FcConfigMessage (parse, FcSevereError, "out of memory");
2928 FcStartDoctypeDecl (void *userData,
2929 const XML_Char *doctypeName,
2930 const XML_Char *sysid FC_UNUSED,
2931 const XML_Char *pubid FC_UNUSED,
2932 int has_internal_subset FC_UNUSED)
2934 FcConfigParse *parse = userData;
2936 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2937 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2940 #ifdef ENABLE_LIBXML2
2943 FcInternalSubsetDecl (void *userData,
2944 const XML_Char *doctypeName,
2945 const XML_Char *sysid,
2946 const XML_Char *pubid)
2948 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2952 FcExternalSubsetDecl (void *userData,
2953 const XML_Char *doctypeName,
2954 const XML_Char *sysid,
2955 const XML_Char *pubid)
2957 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2960 #else /* ENABLE_LIBXML2 */
2963 FcEndDoctypeDecl (void *userData FC_UNUSED)
2967 #endif /* ENABLE_LIBXML2 */
2970 FcSortCmpStr (const void *a, const void *b)
2972 const FcChar8 *as = *((FcChar8 **) a);
2973 const FcChar8 *bs = *((FcChar8 **) b);
2974 return FcStrCmp (as, bs);
2978 FcConfigParseAndLoadDir (FcConfig *config,
2979 const FcChar8 *name,
2985 FcBool ret = FcTrue;
2990 d = opendir ((char *) dir);
2994 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3000 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3007 strcpy ((char *) file, (char *) dir);
3008 strcat ((char *) file, "/");
3009 base = file + strlen ((char *) file);
3011 files = FcStrSetCreate ();
3018 if (FcDebug () & FC_DBG_CONFIG)
3019 printf ("\tScanning config dir %s\n", dir);
3021 while (ret && (e = readdir (d)))
3024 #define TAIL ".conf"
3027 * Add all files of the form [0-9]*.conf
3029 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3030 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3032 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3034 strcpy ((char *) base, (char *) e->d_name);
3035 if (!FcStrSetAdd (files, file))
3045 qsort (files->strs, files->num, sizeof (FcChar8 *),
3046 (int (*)(const void *, const void *)) FcSortCmpStr);
3047 for (i = 0; ret && i < files->num; i++)
3048 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
3051 FcStrSetDestroy (files);
3057 return ret || !complain;
3061 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3062 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3066 FcConfigParseAndLoad (FcConfig *config,
3067 const FcChar8 *name,
3075 FcConfigParse parse;
3076 FcBool error = FcTrue;
3078 #ifdef ENABLE_LIBXML2
3086 if (!pGetSystemWindowsDirectory)
3088 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3089 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3090 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3092 if (!pSHGetFolderPathA)
3094 HMODULE hSh = LoadLibraryA("shfolder.dll");
3095 /* the check is done later, because there is no provided fallback */
3097 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3101 filename = FcConfigFilename (name);
3105 if (FcStrSetMember (config->configFiles, filename))
3107 FcStrFree (filename);
3111 if (!FcStrSetAdd (config->configFiles, filename))
3113 FcStrFree (filename);
3117 if (FcFileIsDir (filename))
3119 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
3120 FcStrFree (filename);
3124 if (FcDebug () & FC_DBG_CONFIG)
3125 printf ("\tLoading config file %s\n", filename);
3127 fd = FcOpen ((char *) filename, O_RDONLY);
3129 FcStrFree (filename);
3133 #ifdef ENABLE_LIBXML2
3134 memset(&sax, 0, sizeof(sax));
3136 sax.internalSubset = FcInternalSubsetDecl;
3137 sax.externalSubset = FcExternalSubsetDecl;
3138 sax.startElement = FcStartElement;
3139 sax.endElement = FcEndElement;
3140 sax.characters = FcCharacterData;
3142 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3144 p = XML_ParserCreate ("UTF-8");
3146 FcStrFree (filename);
3151 if (!FcConfigParseInit (&parse, name, config, p))
3154 #ifndef ENABLE_LIBXML2
3156 XML_SetUserData (p, &parse);
3158 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3159 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3160 XML_SetCharacterDataHandler (p, FcCharacterData);
3162 #endif /* ENABLE_LIBXML2 */
3165 #ifndef ENABLE_LIBXML2
3166 buf = XML_GetBuffer (p, BUFSIZ);
3169 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3173 len = read (fd, buf, BUFSIZ);
3176 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3180 #ifdef ENABLE_LIBXML2
3181 if (xmlParseChunk (p, buf, len, len == 0))
3183 if (!XML_ParseBuffer (p, len, len == 0))
3186 FcConfigMessage (&parse, FcSevereError, "%s",
3187 XML_ErrorString (XML_GetErrorCode (p)));
3191 error = parse.error;
3193 FcConfigCleanup (&parse);
3200 if (error && complain)
3203 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3205 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3211 #include "fcaliastail.h"