4 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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 Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD 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.
28 static xmlParserInputPtr
29 FcEntityLoader (const char *url, const char *id, xmlParserCtxtPtr ctxt)
31 xmlParserInputPtr ret;
34 file = FcConfigFilename ((FcChar8 *) url);
37 ret = xmlNewInputFromFile (ctxt, (char *) file);
43 FcConfigLoad (const FcChar8 *file)
46 xmlExternalEntityLoader previous;
48 previous = xmlGetExternalEntityLoader ();
49 xmlSetExternalEntityLoader (FcEntityLoader);
50 doc = xmlParseFile ((char *) file);
51 xmlSetExternalEntityLoader (previous);
57 FcConfigSave (char *file, xmlDocPtr doc)
63 FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr)
65 FcTest *test = (FcTest *) malloc (sizeof (FcTest));;
71 test->field = (char *) FcStrCopy ((FcChar8 *) field);
79 FcTestDestroy (FcTest *test)
82 FcTestDestroy (test->next);
83 FcExprDestroy (test->expr);
84 FcStrFree ((FcChar8 *) test->field);
89 FcExprCreateInteger (int i)
91 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
102 FcExprCreateDouble (double d)
104 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
115 FcExprCreateString (const FcChar8 *s)
117 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
122 e->u.sval = FcStrCopy (s);
128 FcExprCreateMatrix (const FcMatrix *m)
130 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
135 e->u.mval = FcMatrixCopy (m);
141 FcExprCreateBool (FcBool b)
143 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
154 FcExprCreateNil (void)
156 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
166 FcExprCreateField (const char *field)
168 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
179 FcExprCreateConst (const FcChar8 *constant)
181 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
186 e->u.constant = FcStrCopy (constant);
192 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
194 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
199 e->u.tree.left = left;
200 e->u.tree.right = right;
206 FcExprDestroy (FcExpr *e)
214 FcStrFree (e->u.sval);
217 FcMatrixFree (e->u.mval);
220 FcCharSetDestroy (e->u.cval);
225 FcStrFree ((FcChar8 *) e->u.field);
228 FcStrFree (e->u.constant);
231 case FcOpAssignReplace:
233 case FcOpPrependFirst:
252 FcExprDestroy (e->u.tree.right);
255 FcExprDestroy (e->u.tree.left);
265 FcEditCreate (const char *field, FcOp op, FcExpr *expr)
267 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
272 e->field = field; /* already saved in grammar */
280 FcEditDestroy (FcEdit *e)
283 FcEditDestroy (e->next);
284 FcStrFree ((FcChar8 *) e->field);
286 FcExprDestroy (e->expr);
290 FcConfigSaveField (const char *field)
292 return (char *) FcStrCopy ((FcChar8 *) field);
296 FcConfigParseError (char *fmt, ...)
300 va_start (args, fmt);
301 fprintf (stderr, "font configuration error: ");
302 vfprintf (stderr, fmt, args);
303 fprintf (stderr, "\n");
308 FcConfigContent (xmlDocPtr doc,
313 content = xmlNodeListGetString (doc, node->children, 1);
316 FcConfigParseError ("<%s> must have content",
324 FcConfigAttr (xmlDocPtr doc,
329 content = xmlNodeListGetString (doc, attr->children, 1);
332 FcConfigParseError ("attribute %s must have a value",
343 { "int", FcOpInteger },
344 { "double", FcOpDouble },
345 { "string", FcOpString },
346 { "matrix", FcOpMatrix },
347 { "bool", FcOpBool },
348 { "charset", FcOpCharSet },
349 { "name", FcOpField },
350 { "const", FcOpConst },
351 { "field", FcOpField },
356 { "not_eq", FcOpNotEqual },
357 { "less", FcOpLess },
358 { "less_eq", FcOpLessEqual },
359 { "more", FcOpMore },
360 { "more_eq", FcOpMoreEqual },
361 { "plus", FcOpPlus },
362 { "minus", FcOpMinus },
363 { "times", FcOpTimes },
364 { "divide", FcOpDivide },
366 { "assign", FcOpAssign },
367 { "assign_replace", FcOpAssignReplace },
368 { "prepend", FcOpPrepend },
369 { "prepend_first", FcOpPrependFirst },
370 { "append", FcOpAppend },
371 { "append_last", FcOpAppendLast },
374 #define NUM_OPS (sizeof fcOps / sizeof fcOps[0])
377 FcConfigLexOp (const xmlChar *op)
381 for (i = 0; i < NUM_OPS; i++)
382 if (!strcmp (op, fcOps[i].name)) return fcOps[i].op;
387 FcConfigLexBool (const xmlChar *bool)
389 if (*bool == 't' || *bool == 'T')
391 if (*bool == 'y' || *bool == 'Y')
399 FcConfigParseDir (FcConfig *config,
403 xmlChar *content = FcConfigContent (doc, dir);
407 return FcConfigAddDir (config, (FcChar8 *) content);
411 FcConfigParseCache (FcConfig *config,
415 xmlChar *content = FcConfigContent (doc, dir);
419 return FcConfigSetCache (config, (FcChar8 *) content);
423 FcConfigParseInclude (FcConfig *config,
427 xmlChar *content = FcConfigContent (doc, inc);
429 FcBool complain = FcTrue;
434 for (attr = inc->properties; attr; attr = attr->next)
436 if (attr->type != XML_ATTRIBUTE_NODE)
438 if (!strcmp (attr->name, "ignore_missing"))
439 complain = !FcConfigLexBool (FcConfigAttr (doc, attr));
441 return FcConfigParseAndLoad (config, (FcChar8 *) content, complain);
445 FcConfigParseBlank (FcConfig *config,
452 for (node = blank->children; node; node = node->next)
454 if (node->type != XML_ELEMENT_NODE)
456 if (!strcmp (node->name, "int"))
458 ucs4 = (FcChar32) strtol ((char *) FcConfigContent (doc, node), 0, 0);
461 config->blanks = FcBlanksCreate ();
465 if (!FcBlanksAdd (config->blanks, ucs4))
475 FcConfigParseConfig (FcConfig *config,
481 for (node = cfg->children; node; node = node->next)
483 if (node->type != XML_ELEMENT_NODE)
485 if (!strcmp (node->name, "blank"))
487 if (!FcConfigParseBlank (config, doc, node))
497 FcConfigParseMatrix (xmlDocPtr doc,
501 enum { m_xx, m_xy, m_yx, m_yy, m_done } matrix_state = m_xx;
507 for (; node; node = node->next)
509 if (node->type != XML_ELEMENT_NODE)
511 if (strcmp (node->name, "double"))
513 text = FcConfigContent (doc, node);
516 v = strtod ((char *) text, 0);
517 switch (matrix_state) {
518 case m_xx: m.xx = v; break;
519 case m_xy: m.xy = v; break;
520 case m_yx: m.yx = v; break;
521 case m_yy: m.yy = v; break;
531 FcConfigParseExpr (xmlDocPtr doc,
534 FcOp op = FcConfigLexOp (expr->name);
536 FcExpr *l = 0, *e = 0, *r = 0, *c = 0;
540 l = FcExprCreateInteger (strtol ((char *) FcConfigContent (doc, expr), 0, 0));
543 l = FcExprCreateDouble (strtod ((char *) FcConfigContent (doc, expr), 0));
546 l = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, expr));
549 l = FcExprCreateMatrix (FcConfigParseMatrix (doc, expr));
552 l = FcExprCreateBool (FcConfigLexBool(FcConfigContent (doc, expr)));
555 /* not sure what to do here yet */
558 l = FcExprCreateField ((char *) FcConfigContent (doc, expr));
561 l = FcExprCreateConst ((FcChar8 *) FcConfigContent (doc, expr));
564 for (node = expr->children; node; node = node->next)
566 if (node->type != XML_ELEMENT_NODE)
568 e = FcConfigParseExpr (doc, node);
581 if (!node && l && c && r)
583 e = FcExprCreateOp (c, FcOpQuest, r);
588 e = FcExprCreateOp (l, FcOpQuest, r);
591 node = expr->children;
593 if (node || !l || !c || !r || !e)
605 for (node = expr->children; node; node = node->next)
607 if (node->type != XML_ELEMENT_NODE)
609 e = FcConfigParseExpr (doc, node);
617 e = FcExprCreateOp (l, op, r);
633 * Special case for unary ops
637 e = FcExprCreateOp (l, op, 0);
653 FcConfigParseTest (xmlDocPtr doc,
658 FcQual qual = FcQualAny;
663 for (attr = test->properties; attr; attr = attr->next)
665 if (attr->type != XML_ATTRIBUTE_NODE)
667 if (!strcmp (attr->name, "qual"))
669 xmlChar *qual_name = FcConfigAttr (doc, attr);
672 else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "any"))
674 else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "all"))
677 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name"))
679 field = FcConfigAttr (doc, attr);
681 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "compare"))
683 xmlChar *compare = FcConfigAttr (doc, attr);
685 if (!compare || (op = FcConfigLexOp (compare)) == FcOpInvalid)
687 FcConfigParseError ("Invalid comparison %s",
688 compare ? (char *) compare : "<missing>");
696 for (node = test->children; node; node = node->next)
698 if (node->type != XML_ELEMENT_NODE)
700 expr = FcConfigParseExpr (doc, node);
708 FcConfigParseError ("Missing test expression");
712 return FcTestCreate (qual, (char *) field, op, expr);
716 FcConfigParseExprList (xmlDocPtr doc,
724 e = FcConfigParseExprList (doc, expr->next);
726 if (expr->type == XML_ELEMENT_NODE)
729 l = FcConfigParseExpr (doc, expr);
734 e = FcExprCreateOp (l, FcOpComma, r);
752 FcConfigParseEdit (xmlDocPtr doc,
757 FcOp mode = FcOpAssign;
761 for (attr = edit->properties; attr; attr = attr->next)
763 if (attr->type != XML_ATTRIBUTE_NODE)
765 if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name"))
766 name = FcConfigAttr (doc, attr);
767 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "mode"))
768 mode = FcConfigLexOp (FcConfigAttr (doc, attr));
771 e = FcConfigParseExprList (doc, edit->children);
773 ed = FcEditCreate ((char *) name, mode, e);
780 FcConfigParseMatch (FcConfig *config,
786 FcTest *tests = 0, **prevTest = &tests, *test;
787 FcEdit *edits = 0, **prevEdit = &edits, *edit;
788 FcMatchKind kind = FcMatchPattern;
789 FcBool found_kind = FcFalse;
791 for (node = match->children; node; node = node->next)
793 if (node->type != XML_ELEMENT_NODE)
795 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "test"))
797 test = FcConfigParseTest (doc, node);
801 prevTest = &test->next;
803 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "edit"))
805 edit = FcConfigParseEdit (doc, node);
809 prevEdit = &edit->next;
813 for (attr = match->properties; attr; attr = attr->next)
815 if (attr->type != XML_ATTRIBUTE_NODE)
817 if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "target"))
819 xmlChar *target = FcConfigAttr (doc, attr);
822 FcConfigParseError ("Missing match target");
825 else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "pattern"))
827 kind = FcMatchPattern;
830 else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "font"))
838 if (node || attr || !found_kind ||
839 !FcConfigAddEdit (config, tests, edits, kind))
842 FcTestDestroy (tests);
844 FcEditDestroy (edits);
852 FcConfigParseFamilies (xmlDocPtr doc,
855 FcExpr *next = 0, *this = 0, *expr = 0;
859 next = FcConfigParseFamilies (doc, family->next);
861 if (family->type == XML_ELEMENT_NODE &&
862 !FcStrCmpIgnoreCase ((FcChar8 *) family->name, (FcChar8 *) "family"))
864 this = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, family));
869 expr = FcExprCreateOp (this, FcOpComma, next);
882 FcExprDestroy (expr);
884 FcExprDestroy (this);
886 FcExprDestroy (next);
891 FcConfigParseAlias (FcConfig *config,
896 FcExpr *prefer = 0, *accept = 0, *def = 0;
898 FcEdit *edit = 0, *next;
901 for (node = alias->children; node; node = node->next)
903 if (node->type != XML_ELEMENT_NODE)
905 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "family"))
906 family = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, node));
907 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "prefer"))
908 prefer = FcConfigParseFamilies (doc, node->children);
909 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "accept"))
910 accept = FcConfigParseFamilies (doc, node->children);
911 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "default"))
912 def = FcConfigParseFamilies (doc, node->children);
919 edit = FcEditCreate (FcConfigSaveField ("family"),
928 edit = FcEditCreate (FcConfigSaveField ("family"),
937 edit = FcEditCreate (FcConfigSaveField ("family"),
945 test = FcTestCreate (FcQualAny,
946 FcConfigSaveField ("family"),
950 FcConfigAddEdit (config, test, edit, FcMatchPattern);
956 FcConfigParse (FcConfig *config,
962 cur = xmlDocGetRootElement (doc);
964 for (node = cur->children; node; node = node->next)
966 if (node->type != XML_ELEMENT_NODE)
968 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "dir"))
970 if (!FcConfigParseDir (config, doc, node))
973 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "cache"))
975 if (!FcConfigParseCache (config, doc, node))
978 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "include"))
980 if (!FcConfigParseInclude (config, doc, node))
983 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "config"))
985 if (!FcConfigParseConfig (config, doc, node))
988 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "match"))
990 if (!FcConfigParseMatch (config, doc, node))
993 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "alias"))
995 if (!FcConfigParseAlias (config, doc, node))
1000 FcConfigParseError ("invalid element %s", node->name);
1010 FcConfigParseAndLoad (FcConfig *config,
1011 const FcChar8 *file,
1017 doc = FcConfigLoad (file);
1020 ret = FcConfigAddConfigFile (config, file);
1022 ret = FcConfigParse (config, doc);
1029 FcConfigParseError ("Cannot load config file \"%s\"", file);
1031 FcConfigParseError ("Cannot load default config file");