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");