]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Use libxml2 if requested (with --enable-libxml2) or if expat is not
[fontconfig.git] / src / fcxml.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
3 *
4 * Copyright © 2002 Keith Packard
5 *
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.
15 *
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.
23 */
24
25 #include <stdarg.h>
26 #include "fcint.h"
27 #include <dirent.h>
28
29 #if ENABLE_LIBXML2
30
31 #include <libxml/parser.h>
32
33 #define XML_Char xmlChar
34 #define XML_Parser xmlParserCtxtPtr
35 #define XML_ParserFree xmlFreeParserCtxt
36 #define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
37 #define XML_GetErrorCode xmlCtxtGetLastError
38 #define XML_ErrorString(Error) (Error)->message
39
40 #else /* ENABLE_LIBXML2 */
41
42 #ifndef HAVE_XMLPARSE_H
43 #define HAVE_XMLPARSE_H 0
44 #endif
45
46 #if HAVE_XMLPARSE_H
47 #include <xmlparse.h>
48 #else
49 #include <expat.h>
50 #endif
51
52 #endif /* ENABLE_LIBXML2 */
53
54 #ifdef _WIN32
55 #define STRICT
56 #include <windows.h>
57 #undef STRICT
58 #endif
59
60
61 void
62 FcTestDestroy (FcTest *test)
63 {
64 if (test->next)
65 FcTestDestroy (test->next);
66 FcExprDestroy (test->expr);
67 FcStrFree ((FcChar8 *) test->field);
68 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
69 free (test);
70 }
71
72 FcExpr *
73 FcExprCreateInteger (int i)
74 {
75 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
76
77 if (e)
78 {
79 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
80 e->op = FcOpInteger;
81 e->u.ival = i;
82 }
83 return e;
84 }
85
86 FcExpr *
87 FcExprCreateDouble (double d)
88 {
89 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
90
91 if (e)
92 {
93 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
94 e->op = FcOpDouble;
95 e->u.dval = d;
96 }
97 return e;
98 }
99
100 FcExpr *
101 FcExprCreateString (const FcChar8 *s)
102 {
103 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
104
105 if (e)
106 {
107 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
108 e->op = FcOpString;
109 e->u.sval = FcStrCopy (s);
110 }
111 return e;
112 }
113
114 FcExpr *
115 FcExprCreateMatrix (const FcMatrix *m)
116 {
117 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119 if (e)
120 {
121 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
122 e->op = FcOpMatrix;
123 e->u.mval = FcMatrixCopy (m);
124 }
125 return e;
126 }
127
128 FcExpr *
129 FcExprCreateBool (FcBool b)
130 {
131 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
132
133 if (e)
134 {
135 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
136 e->op = FcOpBool;
137 e->u.bval = b;
138 }
139 return e;
140 }
141
142 FcExpr *
143 FcExprCreateNil (void)
144 {
145 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
146
147 if (e)
148 {
149 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
150 e->op = FcOpNil;
151 }
152 return e;
153 }
154
155 FcExpr *
156 FcExprCreateField (const char *field)
157 {
158 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
159
160 if (e)
161 {
162 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
163 e->op = FcOpField;
164 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
165 }
166 return e;
167 }
168
169 FcExpr *
170 FcExprCreateConst (const FcChar8 *constant)
171 {
172 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174 if (e)
175 {
176 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
177 e->op = FcOpConst;
178 e->u.constant = FcStrCopy (constant);
179 }
180 return e;
181 }
182
183 FcExpr *
184 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
185 {
186 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
187
188 if (e)
189 {
190 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
191 e->op = op;
192 e->u.tree.left = left;
193 e->u.tree.right = right;
194 }
195 return e;
196 }
197
198 void
199 FcExprDestroy (FcExpr *e)
200 {
201 if (!e)
202 return;
203 switch (e->op) {
204 case FcOpInteger:
205 break;
206 case FcOpDouble:
207 break;
208 case FcOpString:
209 FcStrFree (e->u.sval);
210 break;
211 case FcOpMatrix:
212 FcMatrixFree (e->u.mval);
213 break;
214 case FcOpCharSet:
215 FcCharSetDestroy (e->u.cval);
216 break;
217 case FcOpBool:
218 break;
219 case FcOpField:
220 FcStrFree ((FcChar8 *) e->u.field);
221 break;
222 case FcOpConst:
223 FcStrFree (e->u.constant);
224 break;
225 case FcOpAssign:
226 case FcOpAssignReplace:
227 case FcOpPrepend:
228 case FcOpPrependFirst:
229 case FcOpAppend:
230 case FcOpAppendLast:
231 break;
232 case FcOpOr:
233 case FcOpAnd:
234 case FcOpEqual:
235 case FcOpNotEqual:
236 case FcOpLess:
237 case FcOpLessEqual:
238 case FcOpMore:
239 case FcOpMoreEqual:
240 case FcOpContains:
241 case FcOpListing:
242 case FcOpNotContains:
243 case FcOpPlus:
244 case FcOpMinus:
245 case FcOpTimes:
246 case FcOpDivide:
247 case FcOpQuest:
248 case FcOpComma:
249 FcExprDestroy (e->u.tree.right);
250 /* fall through */
251 case FcOpNot:
252 case FcOpFloor:
253 case FcOpCeil:
254 case FcOpRound:
255 case FcOpTrunc:
256 FcExprDestroy (e->u.tree.left);
257 break;
258 case FcOpNil:
259 case FcOpInvalid:
260 break;
261 }
262 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
263 free (e);
264 }
265
266 void
267 FcEditDestroy (FcEdit *e)
268 {
269 if (e->next)
270 FcEditDestroy (e->next);
271 FcStrFree ((FcChar8 *) e->field);
272 if (e->expr)
273 FcExprDestroy (e->expr);
274 free (e);
275 }
276
277 char *
278 FcConfigSaveField (const char *field)
279 {
280 return (char *) FcStrCopy ((FcChar8 *) field);
281 }
282
283 typedef enum _FcElement {
284 FcElementNone,
285 FcElementFontconfig,
286 FcElementDir,
287 FcElementCache,
288 FcElementInclude,
289 FcElementConfig,
290 FcElementMatch,
291 FcElementAlias,
292
293 FcElementBlank,
294 FcElementRescan,
295
296 FcElementPrefer,
297 FcElementAccept,
298 FcElementDefault,
299 FcElementFamily,
300
301 FcElementSelectfont,
302 FcElementAcceptfont,
303 FcElementRejectfont,
304 FcElementGlob,
305 FcElementPattern,
306 FcElementPatelt,
307
308 FcElementTest,
309 FcElementEdit,
310 FcElementInt,
311 FcElementDouble,
312 FcElementString,
313 FcElementMatrix,
314 FcElementBool,
315 FcElementCharset,
316 FcElementName,
317 FcElementConst,
318 FcElementOr,
319 FcElementAnd,
320 FcElementEq,
321 FcElementNotEq,
322 FcElementLess,
323 FcElementLessEq,
324 FcElementMore,
325 FcElementMoreEq,
326 FcElementContains,
327 FcElementNotContains,
328 FcElementPlus,
329 FcElementMinus,
330 FcElementTimes,
331 FcElementDivide,
332 FcElementNot,
333 FcElementIf,
334 FcElementFloor,
335 FcElementCeil,
336 FcElementRound,
337 FcElementTrunc,
338 FcElementUnknown
339 } FcElement;
340
341 static struct {
342 const char name[16];
343 FcElement element;
344 } fcElementMap[] = {
345 { "fontconfig", FcElementFontconfig },
346 { "dir", FcElementDir },
347 { "cache", FcElementCache },
348 { "include", FcElementInclude },
349 { "config", FcElementConfig },
350 { "match", FcElementMatch },
351 { "alias", FcElementAlias },
352
353 { "blank", FcElementBlank },
354 { "rescan", FcElementRescan },
355
356 { "prefer", FcElementPrefer },
357 { "accept", FcElementAccept },
358 { "default", FcElementDefault },
359 { "family", FcElementFamily },
360
361 { "selectfont", FcElementSelectfont },
362 { "acceptfont", FcElementAcceptfont },
363 { "rejectfont", FcElementRejectfont },
364 { "glob", FcElementGlob },
365 { "pattern", FcElementPattern },
366 { "patelt", FcElementPatelt },
367
368 { "test", FcElementTest },
369 { "edit", FcElementEdit },
370 { "int", FcElementInt },
371 { "double", FcElementDouble },
372 { "string", FcElementString },
373 { "matrix", FcElementMatrix },
374 { "bool", FcElementBool },
375 { "charset", FcElementCharset },
376 { "name", FcElementName },
377 { "const", FcElementConst },
378 { "or", FcElementOr },
379 { "and", FcElementAnd },
380 { "eq", FcElementEq },
381 { "not_eq", FcElementNotEq },
382 { "less", FcElementLess },
383 { "less_eq", FcElementLessEq },
384 { "more", FcElementMore },
385 { "more_eq", FcElementMoreEq },
386 { "contains", FcElementContains },
387 { "not_contains", FcElementNotContains },
388 { "plus", FcElementPlus },
389 { "minus", FcElementMinus },
390 { "times", FcElementTimes },
391 { "divide", FcElementDivide },
392 { "not", FcElementNot },
393 { "if", FcElementIf },
394 { "floor", FcElementFloor },
395 { "ceil", FcElementCeil },
396 { "round", FcElementRound },
397 { "trunc", FcElementTrunc },
398 };
399 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
400
401 static FcElement
402 FcElementMap (const XML_Char *name)
403 {
404
405 int i;
406 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
407 if (!strcmp ((char *) name, fcElementMap[i].name))
408 return fcElementMap[i].element;
409 return FcElementUnknown;
410 }
411
412 typedef struct _FcPStack {
413 struct _FcPStack *prev;
414 FcElement element;
415 FcChar8 **attr;
416 FcStrBuf str;
417 } FcPStack;
418
419 typedef enum _FcVStackTag {
420 FcVStackNone,
421
422 FcVStackString,
423 FcVStackFamily,
424 FcVStackField,
425 FcVStackConstant,
426 FcVStackGlob,
427 FcVStackPattern,
428
429 FcVStackPrefer,
430 FcVStackAccept,
431 FcVStackDefault,
432
433 FcVStackInteger,
434 FcVStackDouble,
435 FcVStackMatrix,
436 FcVStackBool,
437
438 FcVStackTest,
439 FcVStackExpr,
440 FcVStackEdit
441 } FcVStackTag;
442
443 typedef struct _FcVStack {
444 struct _FcVStack *prev;
445 FcPStack *pstack; /* related parse element */
446 FcVStackTag tag;
447 union {
448 FcChar8 *string;
449
450 int integer;
451 double _double;
452 FcMatrix *matrix;
453 FcBool bool;
454
455 FcTest *test;
456 FcQual qual;
457 FcOp op;
458 FcExpr *expr;
459 FcEdit *edit;
460
461 FcPattern *pattern;
462 } u;
463 } FcVStack;
464
465 typedef struct _FcConfigParse {
466 FcPStack *pstack;
467 FcVStack *vstack;
468 FcBool error;
469 const FcChar8 *name;
470 FcConfig *config;
471 XML_Parser parser;
472 } FcConfigParse;
473
474 typedef enum _FcConfigSeverity {
475 FcSevereInfo, FcSevereWarning, FcSevereError
476 } FcConfigSeverity;
477
478 static void
479 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
480 {
481 const char *s = "unknown";
482 va_list args;
483
484 va_start (args, fmt);
485
486 switch (severe) {
487 case FcSevereInfo: s = "info"; break;
488 case FcSevereWarning: s = "warning"; break;
489 case FcSevereError: s = "error"; break;
490 }
491 if (parse)
492 {
493 if (parse->name)
494 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
495 parse->name, XML_GetCurrentLineNumber (parse->parser));
496 else
497 fprintf (stderr, "Fontconfig %s: line %d: ", s,
498 XML_GetCurrentLineNumber (parse->parser));
499 if (severe >= FcSevereError)
500 parse->error = FcTrue;
501 }
502 else
503 fprintf (stderr, "Fontconfig %s: ", s);
504 vfprintf (stderr, fmt, args);
505 fprintf (stderr, "\n");
506 va_end (args);
507 }
508
509
510 static const char *
511 FcTypeName (FcType type)
512 {
513 switch (type) {
514 case FcTypeVoid:
515 return "void";
516 case FcTypeInteger:
517 case FcTypeDouble:
518 return "number";
519 case FcTypeString:
520 return "string";
521 case FcTypeBool:
522 return "bool";
523 case FcTypeMatrix:
524 return "matrix";
525 case FcTypeCharSet:
526 return "charset";
527 case FcTypeFTFace:
528 return "FT_Face";
529 case FcTypeLangSet:
530 return "langset";
531 default:
532 return "unknown";
533 }
534 }
535
536 static void
537 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
538 {
539 if (value == FcTypeInteger)
540 value = FcTypeDouble;
541 if (type == FcTypeInteger)
542 type = FcTypeDouble;
543 if (value != type)
544 {
545 if ((value == FcTypeLangSet && type == FcTypeString) ||
546 (value == FcTypeString && type == FcTypeLangSet))
547 return;
548 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
549 FcTypeName (value), FcTypeName (type));
550 }
551 }
552
553 static void
554 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
555 {
556 const FcObjectType *o;
557 const FcConstant *c;
558
559 switch (expr->op) {
560 case FcOpInteger:
561 case FcOpDouble:
562 FcTypecheckValue (parse, FcTypeDouble, type);
563 break;
564 case FcOpString:
565 FcTypecheckValue (parse, FcTypeString, type);
566 break;
567 case FcOpMatrix:
568 FcTypecheckValue (parse, FcTypeMatrix, type);
569 break;
570 case FcOpBool:
571 FcTypecheckValue (parse, FcTypeBool, type);
572 break;
573 case FcOpCharSet:
574 FcTypecheckValue (parse, FcTypeCharSet, type);
575 break;
576 case FcOpNil:
577 break;
578 case FcOpField:
579 o = FcNameGetObjectType (expr->u.field);
580 if (o)
581 FcTypecheckValue (parse, o->type, type);
582 break;
583 case FcOpConst:
584 c = FcNameGetConstant (expr->u.constant);
585 if (c)
586 {
587 o = FcNameGetObjectType (c->object);
588 if (o)
589 FcTypecheckValue (parse, o->type, type);
590 }
591 break;
592 case FcOpQuest:
593 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
594 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
595 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
596 break;
597 case FcOpAssign:
598 case FcOpAssignReplace:
599 break;
600 case FcOpEqual:
601 case FcOpNotEqual:
602 case FcOpLess:
603 case FcOpLessEqual:
604 case FcOpMore:
605 case FcOpMoreEqual:
606 case FcOpContains:
607 case FcOpNotContains:
608 case FcOpListing:
609 FcTypecheckValue (parse, FcTypeBool, type);
610 break;
611 case FcOpComma:
612 case FcOpOr:
613 case FcOpAnd:
614 case FcOpPlus:
615 case FcOpMinus:
616 case FcOpTimes:
617 case FcOpDivide:
618 FcTypecheckExpr (parse, expr->u.tree.left, type);
619 FcTypecheckExpr (parse, expr->u.tree.right, type);
620 break;
621 case FcOpNot:
622 FcTypecheckValue (parse, FcTypeBool, type);
623 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
624 break;
625 case FcOpFloor:
626 case FcOpCeil:
627 case FcOpRound:
628 case FcOpTrunc:
629 FcTypecheckValue (parse, FcTypeDouble, type);
630 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
631 break;
632 default:
633 break;
634 }
635 }
636
637 static FcTest *
638 FcTestCreate (FcConfigParse *parse,
639 FcMatchKind kind,
640 FcQual qual,
641 const FcChar8 *field,
642 FcOp compare,
643 FcExpr *expr)
644 {
645 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
646
647 if (test)
648 {
649 const FcObjectType *o;
650
651 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
652 test->next = 0;
653 test->kind = kind;
654 test->qual = qual;
655 test->field = (char *) FcStrCopy (field);
656 test->op = compare;
657 test->expr = expr;
658 o = FcNameGetObjectType (test->field);
659 if (o)
660 FcTypecheckExpr (parse, expr, o->type);
661 }
662 return test;
663 }
664
665 static FcEdit *
666 FcEditCreate (FcConfigParse *parse,
667 const char *field,
668 FcOp op,
669 FcExpr *expr,
670 FcValueBinding binding)
671 {
672 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
673
674 if (e)
675 {
676 const FcObjectType *o;
677
678 e->next = 0;
679 e->field = field; /* already saved in grammar */
680 e->op = op;
681 e->expr = expr;
682 e->binding = binding;
683 o = FcNameGetObjectType (e->field);
684 if (o)
685 FcTypecheckExpr (parse, expr, o->type);
686 }
687 return e;
688 }
689
690 static void
691 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
692 {
693 vstack->prev = parse->vstack;
694 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
695 parse->vstack = vstack;
696 }
697
698 static FcVStack *
699 FcVStackCreate (void)
700 {
701 FcVStack *new;
702
703 new = malloc (sizeof (FcVStack));
704 if (!new)
705 return 0;
706 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
707 new->tag = FcVStackNone;
708 new->prev = 0;
709 return new;
710 }
711
712 static void
713 FcVStackDestroy (FcVStack *vstack)
714 {
715 FcVStack *prev;
716
717 for (; vstack; vstack = prev)
718 {
719 prev = vstack->prev;
720 switch (vstack->tag) {
721 case FcVStackNone:
722 break;
723 case FcVStackString:
724 case FcVStackFamily:
725 case FcVStackField:
726 case FcVStackConstant:
727 case FcVStackGlob:
728 FcStrFree (vstack->u.string);
729 break;
730 case FcVStackPattern:
731 FcPatternDestroy (vstack->u.pattern);
732 break;
733 case FcVStackInteger:
734 case FcVStackDouble:
735 break;
736 case FcVStackMatrix:
737 FcMatrixFree (vstack->u.matrix);
738 break;
739 case FcVStackBool:
740 break;
741 case FcVStackTest:
742 FcTestDestroy (vstack->u.test);
743 break;
744 case FcVStackExpr:
745 case FcVStackPrefer:
746 case FcVStackAccept:
747 case FcVStackDefault:
748 FcExprDestroy (vstack->u.expr);
749 break;
750 case FcVStackEdit:
751 FcEditDestroy (vstack->u.edit);
752 break;
753 }
754 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
755 free (vstack);
756 }
757 }
758
759 static FcBool
760 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
761 {
762 FcVStack *vstack = FcVStackCreate ();
763 if (!vstack)
764 return FcFalse;
765 vstack->u.string = string;
766 vstack->tag = tag;
767 FcVStackPush (parse, vstack);
768 return FcTrue;
769 }
770
771 static FcBool
772 FcVStackPushInteger (FcConfigParse *parse, int integer)
773 {
774 FcVStack *vstack = FcVStackCreate ();
775 if (!vstack)
776 return FcFalse;
777 vstack->u.integer = integer;
778 vstack->tag = FcVStackInteger;
779 FcVStackPush (parse, vstack);
780 return FcTrue;
781 }
782
783 static FcBool
784 FcVStackPushDouble (FcConfigParse *parse, double _double)
785 {
786 FcVStack *vstack = FcVStackCreate ();
787 if (!vstack)
788 return FcFalse;
789 vstack->u._double = _double;
790 vstack->tag = FcVStackDouble;
791 FcVStackPush (parse, vstack);
792 return FcTrue;
793 }
794
795 static FcBool
796 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
797 {
798 FcVStack *vstack = FcVStackCreate ();
799 if (!vstack)
800 return FcFalse;
801 matrix = FcMatrixCopy (matrix);
802 if (!matrix)
803 {
804 FcVStackDestroy (vstack);
805 return FcFalse;
806 }
807 vstack->u.matrix = matrix;
808 vstack->tag = FcVStackMatrix;
809 FcVStackPush (parse, vstack);
810 return FcTrue;
811 }
812
813 static FcBool
814 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
815 {
816 FcVStack *vstack = FcVStackCreate ();
817 if (!vstack)
818 return FcFalse;
819 vstack->u.bool = bool;
820 vstack->tag = FcVStackBool;
821 FcVStackPush (parse, vstack);
822 return FcTrue;
823 }
824
825 static FcBool
826 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
827 {
828 FcVStack *vstack = FcVStackCreate ();
829 if (!vstack)
830 return FcFalse;
831 vstack->u.test = test;
832 vstack->tag = FcVStackTest;
833 FcVStackPush (parse, vstack);
834 return FcTrue;
835 }
836
837 static FcBool
838 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
839 {
840 FcVStack *vstack = FcVStackCreate ();
841 if (!vstack)
842 return FcFalse;
843 vstack->u.expr = expr;
844 vstack->tag = tag;
845 FcVStackPush (parse, vstack);
846 return FcTrue;
847 }
848
849 static FcBool
850 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
851 {
852 FcVStack *vstack = FcVStackCreate ();
853 if (!vstack)
854 return FcFalse;
855 vstack->u.edit = edit;
856 vstack->tag = FcVStackEdit;
857 FcVStackPush (parse, vstack);
858 return FcTrue;
859 }
860
861 static FcBool
862 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
863 {
864 FcVStack *vstack = FcVStackCreate ();
865 if (!vstack)
866 return FcFalse;
867 vstack->u.pattern = pattern;
868 vstack->tag = FcVStackPattern;
869 FcVStackPush (parse, vstack);
870 return FcTrue;
871 }
872
873 static FcVStack *
874 FcVStackFetch (FcConfigParse *parse, int off)
875 {
876 FcVStack *vstack;
877
878 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
879 return vstack;
880 }
881
882 static void
883 FcVStackClear (FcConfigParse *parse)
884 {
885 while (parse->vstack && parse->vstack->pstack == parse->pstack)
886 {
887 FcVStack *vstack = parse->vstack;
888 parse->vstack = vstack->prev;
889 vstack->prev = 0;
890 FcVStackDestroy (vstack);
891 }
892 }
893
894 static FcVStack *
895 FcVStackPop (FcConfigParse *parse)
896 {
897 FcVStack *vstack = parse->vstack;
898
899 if (!vstack || vstack->pstack != parse->pstack)
900 return 0;
901 parse->vstack = vstack->prev;
902 vstack->prev = 0;
903 return vstack;
904 }
905
906 static int
907 FcVStackElements (FcConfigParse *parse)
908 {
909 int h = 0;
910 FcVStack *vstack = parse->vstack;
911 while (vstack && vstack->pstack == parse->pstack)
912 {
913 h++;
914 vstack = vstack->prev;
915 }
916 return h;
917 }
918
919 static FcChar8 **
920 FcConfigSaveAttr (const XML_Char **attr)
921 {
922 int n;
923 int slen;
924 int i;
925 FcChar8 **new;
926 FcChar8 *s;
927
928 if (!attr)
929 return 0;
930 slen = 0;
931 for (i = 0; attr[i]; i++)
932 slen += strlen (attr[i]) + 1;
933 n = i;
934 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
935 if (!new)
936 return 0;
937 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
938 s = (FcChar8 *) (new + (i + 1));
939 for (i = 0; attr[i]; i++)
940 {
941 new[i] = s;
942 strcpy ((char *) s, (char *) attr[i]);
943 s += strlen ((char *) s) + 1;
944 }
945 new[i] = 0;
946 return new;
947 }
948
949 static FcBool
950 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
951 {
952 FcPStack *new = malloc (sizeof (FcPStack));
953
954 if (!new)
955 return FcFalse;
956 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
957 new->prev = parse->pstack;
958 new->element = element;
959 if (attr)
960 {
961 new->attr = FcConfigSaveAttr (attr);
962 if (!new->attr)
963 FcConfigMessage (parse, FcSevereError, "out of memory");
964 }
965 else
966 new->attr = 0;
967 FcStrBufInit (&new->str, 0, 0);
968 parse->pstack = new;
969 return FcTrue;
970 }
971
972 static FcBool
973 FcPStackPop (FcConfigParse *parse)
974 {
975 FcPStack *old;
976
977 if (!parse->pstack)
978 {
979 FcConfigMessage (parse, FcSevereError, "mismatching element");
980 return FcFalse;
981 }
982 FcVStackClear (parse);
983 old = parse->pstack;
984 parse->pstack = old->prev;
985 FcStrBufDestroy (&old->str);
986 if (old->attr)
987 {
988 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
989 free (old->attr);
990 }
991 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
992 free (old);
993 return FcTrue;
994 }
995
996 static FcBool
997 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
998 {
999 parse->pstack = 0;
1000 parse->vstack = 0;
1001 parse->error = FcFalse;
1002 parse->name = name;
1003 parse->config = config;
1004 parse->parser = parser;
1005 return FcTrue;
1006 }
1007
1008 static void
1009 FcConfigCleanup (FcConfigParse *parse)
1010 {
1011 while (parse->pstack)
1012 FcPStackPop (parse);
1013 }
1014
1015 static const FcChar8 *
1016 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1017 {
1018 FcChar8 **attrs;
1019 if (!parse->pstack)
1020 return 0;
1021
1022 attrs = parse->pstack->attr;
1023 while (*attrs)
1024 {
1025 if (!strcmp ((char *) *attrs, attr))
1026 return attrs[1];
1027 attrs += 2;
1028 }
1029 return 0;
1030 }
1031
1032 static void
1033 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1034 {
1035 FcConfigParse *parse = userData;
1036 FcElement element;
1037
1038 element = FcElementMap (name);
1039 if (element == FcElementUnknown)
1040 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1041
1042 if (!FcPStackPush (parse, element, attr))
1043 {
1044 FcConfigMessage (parse, FcSevereError, "out of memory");
1045 return;
1046 }
1047 return;
1048 }
1049
1050 static void
1051 FcParseBlank (FcConfigParse *parse)
1052 {
1053 int n = FcVStackElements (parse);
1054 while (n-- > 0)
1055 {
1056 FcVStack *v = FcVStackFetch (parse, n);
1057 if (v->tag != FcVStackInteger)
1058 FcConfigMessage (parse, FcSevereError, "non-integer blank");
1059 else
1060 {
1061 if (!parse->config->blanks)
1062 {
1063 parse->config->blanks = FcBlanksCreate ();
1064 if (!parse->config->blanks)
1065 {
1066 FcConfigMessage (parse, FcSevereError, "out of memory");
1067 break;
1068 }
1069 }
1070 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1071 {
1072 FcConfigMessage (parse, FcSevereError, "out of memory");
1073 break;
1074 }
1075 }
1076 }
1077 }
1078
1079 static void
1080 FcParseRescan (FcConfigParse *parse)
1081 {
1082 int n = FcVStackElements (parse);
1083 while (n-- > 0)
1084 {
1085 FcVStack *v = FcVStackFetch (parse, n);
1086 if (v->tag != FcVStackInteger)
1087 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1088 else
1089 parse->config->rescanInterval = v->u.integer;
1090 }
1091 }
1092
1093 static void
1094 FcParseInt (FcConfigParse *parse)
1095 {
1096 FcChar8 *s, *end;
1097 int l;
1098
1099 if (!parse->pstack)
1100 return;
1101 s = FcStrBufDone (&parse->pstack->str);
1102 if (!s)
1103 {
1104 FcConfigMessage (parse, FcSevereError, "out of memory");
1105 return;
1106 }
1107 end = 0;
1108 l = (int) strtol ((char *) s, (char **)&end, 0);
1109 if (end != s + strlen ((char *) s))
1110 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1111 else
1112 FcVStackPushInteger (parse, l);
1113 FcStrFree (s);
1114 }
1115
1116 /*
1117 * idea copied from glib g_ascii_strtod with
1118 * permission of the author (Alexander Larsson)
1119 */
1120
1121 #include <locale.h>
1122
1123 static double
1124 FcStrtod (char *s, char **end)
1125 {
1126 struct lconv *locale_data;
1127 char *dot;
1128 double v;
1129
1130 /*
1131 * Have to swap the decimal point to match the current locale
1132 * if that locale doesn't use 0x2e
1133 */
1134 if ((dot = strchr (s, 0x2e)) &&
1135 (locale_data = localeconv ()) &&
1136 (locale_data->decimal_point[0] != 0x2e ||
1137 locale_data->decimal_point[1] != 0))
1138 {
1139 char buf[128];
1140 int slen = strlen (s);
1141 int dlen = strlen (locale_data->decimal_point);
1142
1143 if (slen + dlen > (int) sizeof (buf))
1144 {
1145 if (end)
1146 *end = s;
1147 v = 0;
1148 }
1149 else
1150 {
1151 char *buf_end;
1152 /* mantissa */
1153 strncpy (buf, s, dot - s);
1154 /* decimal point */
1155 strcpy (buf + (dot - s), locale_data->decimal_point);
1156 /* rest of number */
1157 strcpy (buf + (dot - s) + dlen, dot + 1);
1158 buf_end = 0;
1159 v = strtod (buf, &buf_end);
1160 if (buf_end) {
1161 buf_end = s + (buf_end - buf);
1162 if (buf_end > dot)
1163 buf_end -= dlen - 1;
1164 }
1165 if (end)
1166 *end = buf_end;
1167 }
1168 }
1169 else
1170 v = strtod (s, end);
1171 return v;
1172 }
1173
1174 static void
1175 FcParseDouble (FcConfigParse *parse)
1176 {
1177 FcChar8 *s, *end;
1178 double d;
1179
1180 if (!parse->pstack)
1181 return;
1182 s = FcStrBufDone (&parse->pstack->str);
1183 if (!s)
1184 {
1185 FcConfigMessage (parse, FcSevereError, "out of memory");
1186 return;
1187 }
1188 end = 0;
1189 d = FcStrtod ((char *) s, (char **)&end);
1190 if (end != s + strlen ((char *) s))
1191 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1192 else
1193 FcVStackPushDouble (parse, d);
1194 FcStrFree (s);
1195 }
1196
1197 static void
1198 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1199 {
1200 FcChar8 *s;
1201
1202 if (!parse->pstack)
1203 return;
1204 s = FcStrBufDone (&parse->pstack->str);
1205 if (!s)
1206 {
1207 FcConfigMessage (parse, FcSevereError, "out of memory");
1208 return;
1209 }
1210 if (!FcVStackPushString (parse, tag, s))
1211 FcStrFree (s);
1212 }
1213
1214 static void
1215 FcParseMatrix (FcConfigParse *parse)
1216 {
1217 FcVStack *vstack;
1218 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1219 FcMatrix m;
1220
1221 while ((vstack = FcVStackPop (parse)))
1222 {
1223 double v;
1224 switch (vstack->tag) {
1225 case FcVStackInteger:
1226 v = vstack->u.integer;
1227 break;
1228 case FcVStackDouble:
1229 v = vstack->u._double;
1230 break;
1231 default:
1232 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1233 v = 1.0;
1234 break;
1235 }
1236 switch (matrix_state) {
1237 case m_xx: m.xx = v; break;
1238 case m_xy: m.xy = v; break;
1239 case m_yx: m.yx = v; break;
1240 case m_yy: m.yy = v; break;
1241 default: break;
1242 }
1243 FcVStackDestroy (vstack);
1244 matrix_state--;
1245 }
1246 if (matrix_state != m_done)
1247 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1248 else
1249 FcVStackPushMatrix (parse, &m);
1250 }
1251
1252 static FcBool
1253 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1254 {
1255 FcBool result = FcFalse;
1256
1257 if (!FcNameBool (bool, &result))
1258 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1259 bool);
1260 return result;
1261 }
1262
1263 static void
1264 FcParseBool (FcConfigParse *parse)
1265 {
1266 FcChar8 *s;
1267
1268 if (!parse->pstack)
1269 return;
1270 s = FcStrBufDone (&parse->pstack->str);
1271 if (!s)
1272 {
1273 FcConfigMessage (parse, FcSevereError, "out of memory");
1274 return;
1275 }
1276 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1277 FcStrFree (s);
1278 }
1279
1280 static void
1281 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1282 {
1283 FcVStack *vstack;
1284 FcExpr *left, *expr = 0, *new;
1285
1286 while ((vstack = FcVStackPop (parse)))
1287 {
1288 if (vstack->tag != FcVStackFamily)
1289 {
1290 FcConfigMessage (parse, FcSevereWarning, "non-family");
1291 FcVStackDestroy (vstack);
1292 continue;
1293 }
1294 left = vstack->u.expr;
1295 vstack->tag = FcVStackNone;
1296 FcVStackDestroy (vstack);
1297 if (expr)
1298 {
1299 new = FcExprCreateOp (left, FcOpComma, expr);
1300 if (!new)
1301 {
1302 FcConfigMessage (parse, FcSevereError, "out of memory");
1303 FcExprDestroy (left);
1304 FcExprDestroy (expr);
1305 break;
1306 }
1307 expr = new;
1308 }
1309 else
1310 expr = left;
1311 }
1312 if (expr)
1313 {
1314 if (!FcVStackPushExpr (parse, tag, expr))
1315 {
1316 FcConfigMessage (parse, FcSevereError, "out of memory");
1317 if (expr)
1318 FcExprDestroy (expr);
1319 }
1320 }
1321 }
1322
1323 static void
1324 FcParseFamily (FcConfigParse *parse)
1325 {
1326 FcChar8 *s;
1327 FcExpr *expr;
1328
1329 if (!parse->pstack)
1330 return;
1331 s = FcStrBufDone (&parse->pstack->str);
1332 if (!s)
1333 {
1334 FcConfigMessage (parse, FcSevereError, "out of memory");
1335 return;
1336 }
1337 expr = FcExprCreateString (s);
1338 FcStrFree (s);
1339 if (expr)
1340 FcVStackPushExpr (parse, FcVStackFamily, expr);
1341 }
1342
1343 static void
1344 FcParseAlias (FcConfigParse *parse)
1345 {
1346 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1347 FcEdit *edit = 0, *next;
1348 FcVStack *vstack;
1349 FcTest *test;
1350
1351 while ((vstack = FcVStackPop (parse)))
1352 {
1353 switch (vstack->tag) {
1354 case FcVStackFamily:
1355 if (family)
1356 {
1357 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1358 if (!new)
1359 FcConfigMessage (parse, FcSevereError, "out of memory");
1360 else
1361 family = new;
1362 }
1363 else
1364 new = vstack->u.expr;
1365 if (new)
1366 {
1367 family = new;
1368 vstack->tag = FcVStackNone;
1369 }
1370 break;
1371 case FcVStackPrefer:
1372 if (prefer)
1373 FcExprDestroy (prefer);
1374 prefer = vstack->u.expr;
1375 vstack->tag = FcVStackNone;
1376 break;
1377 case FcVStackAccept:
1378 if (accept)
1379 FcExprDestroy (accept);
1380 accept = vstack->u.expr;
1381 vstack->tag = FcVStackNone;
1382 break;
1383 case FcVStackDefault:
1384 if (def)
1385 FcExprDestroy (def);
1386 def = vstack->u.expr;
1387 vstack->tag = FcVStackNone;
1388 break;
1389 default:
1390 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1391 break;
1392 }
1393 FcVStackDestroy (vstack);
1394 }
1395 if (!family)
1396 {
1397 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1398 if (prefer)
1399 FcExprDestroy (prefer);
1400 if (accept)
1401 FcExprDestroy (accept);
1402 if (def)
1403 FcExprDestroy (def);
1404 return;
1405 }
1406 if (prefer)
1407 {
1408 edit = FcEditCreate (parse,
1409 FcConfigSaveField ("family"),
1410 FcOpPrepend,
1411 prefer,
1412 FcValueBindingWeak);
1413 if (edit)
1414 edit->next = 0;
1415 else
1416 FcExprDestroy (prefer);
1417 }
1418 if (accept)
1419 {
1420 next = edit;
1421 edit = FcEditCreate (parse,
1422 FcConfigSaveField ("family"),
1423 FcOpAppend,
1424 accept,
1425 FcValueBindingWeak);
1426 if (edit)
1427 edit->next = next;
1428 else
1429 FcExprDestroy (accept);
1430 }
1431 if (def)
1432 {
1433 next = edit;
1434 edit = FcEditCreate (parse,
1435 FcConfigSaveField ("family"),
1436 FcOpAppendLast,
1437 def,
1438 FcValueBindingWeak);
1439 if (edit)
1440 edit->next = next;
1441 else
1442 FcExprDestroy (def);
1443 }
1444 if (edit)
1445 {
1446 test = FcTestCreate (parse, FcMatchPattern,
1447 FcQualAny,
1448 (FcChar8 *) FC_FAMILY,
1449 FcOpEqual,
1450 family);
1451 if (test)
1452 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1453 FcTestDestroy (test);
1454 }
1455 else
1456 FcExprDestroy (family);
1457 }
1458
1459 static FcExpr *
1460 FcPopExpr (FcConfigParse *parse)
1461 {
1462 FcVStack *vstack = FcVStackPop (parse);
1463 FcExpr *expr = 0;
1464 if (!vstack)
1465 return 0;
1466 switch (vstack->tag) {
1467 case FcVStackNone:
1468 break;
1469 case FcVStackString:
1470 case FcVStackFamily:
1471 expr = FcExprCreateString (vstack->u.string);
1472 break;
1473 case FcVStackField:
1474 expr = FcExprCreateField ((char *) vstack->u.string);
1475 break;
1476 case FcVStackConstant:
1477 expr = FcExprCreateConst (vstack->u.string);
1478 break;
1479 case FcVStackGlob:
1480 /* XXX: What's the correct action here? (CDW) */
1481 break;
1482 case FcVStackPrefer:
1483 case FcVStackAccept:
1484 case FcVStackDefault:
1485 expr = vstack->u.expr;
1486 vstack->tag = FcVStackNone;
1487 break;
1488 case FcVStackInteger:
1489 expr = FcExprCreateInteger (vstack->u.integer);
1490 break;
1491 case FcVStackDouble:
1492 expr = FcExprCreateDouble (vstack->u._double);
1493 break;
1494 case FcVStackMatrix:
1495 expr = FcExprCreateMatrix (vstack->u.matrix);
1496 break;
1497 case FcVStackBool:
1498 expr = FcExprCreateBool (vstack->u.bool);
1499 break;
1500 case FcVStackTest:
1501 break;
1502 case FcVStackExpr:
1503 expr = vstack->u.expr;
1504 vstack->tag = FcVStackNone;
1505 break;
1506 case FcVStackEdit:
1507 break;
1508 default:
1509 break;
1510 }
1511 FcVStackDestroy (vstack);
1512 return expr;
1513 }
1514
1515 /*
1516 * This builds a tree of binary operations. Note
1517 * that every operator is defined so that if only
1518 * a single operand is contained, the value of the
1519 * whole expression is the value of the operand.
1520 *
1521 * This code reduces in that case to returning that
1522 * operand.
1523 */
1524 static FcExpr *
1525 FcPopBinary (FcConfigParse *parse, FcOp op)
1526 {
1527 FcExpr *left, *expr = 0, *new;
1528
1529 while ((left = FcPopExpr (parse)))
1530 {
1531 if (expr)
1532 {
1533 new = FcExprCreateOp (left, op, expr);
1534 if (!new)
1535 {
1536 FcConfigMessage (parse, FcSevereError, "out of memory");
1537 FcExprDestroy (left);
1538 FcExprDestroy (expr);
1539 break;
1540 }
1541 expr = new;
1542 }
1543 else
1544 expr = left;
1545 }
1546 return expr;
1547 }
1548
1549 static void
1550 FcParseBinary (FcConfigParse *parse, FcOp op)
1551 {
1552 FcExpr *expr = FcPopBinary (parse, op);
1553 if (expr)
1554 FcVStackPushExpr (parse, FcVStackExpr, expr);
1555 }
1556
1557 /*
1558 * This builds a a unary operator, it consumes only
1559 * a single operand
1560 */
1561
1562 static FcExpr *
1563 FcPopUnary (FcConfigParse *parse, FcOp op)
1564 {
1565 FcExpr *operand, *new = 0;
1566
1567 if ((operand = FcPopExpr (parse)))
1568 {
1569 new = FcExprCreateOp (operand, op, 0);
1570 if (!new)
1571 {
1572 FcExprDestroy (operand);
1573 FcConfigMessage (parse, FcSevereError, "out of memory");
1574 }
1575 }
1576 return new;
1577 }
1578
1579 static void
1580 FcParseUnary (FcConfigParse *parse, FcOp op)
1581 {
1582 FcExpr *expr = FcPopUnary (parse, op);
1583 if (expr)
1584 FcVStackPushExpr (parse, FcVStackExpr, expr);
1585 }
1586
1587 static void
1588 FcParseInclude (FcConfigParse *parse)
1589 {
1590 FcChar8 *s;
1591 const FcChar8 *i;
1592 FcBool ignore_missing = FcFalse;
1593
1594 s = FcStrBufDone (&parse->pstack->str);
1595 if (!s)
1596 {
1597 FcConfigMessage (parse, FcSevereError, "out of memory");
1598 return;
1599 }
1600 i = FcConfigGetAttribute (parse, "ignore_missing");
1601 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1602 ignore_missing = FcTrue;
1603 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1604 parse->error = FcTrue;
1605 FcStrFree (s);
1606 }
1607
1608 typedef struct _FcOpMap {
1609 char name[16];
1610 FcOp op;
1611 } FcOpMap;
1612
1613 static FcOp
1614 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1615 {
1616 int i;
1617
1618 for (i = 0; i < nmap; i++)
1619 if (!strcmp ((char *) op, map[i].name))
1620 return map[i].op;
1621 return FcOpInvalid;
1622 }
1623
1624 static const FcOpMap fcCompareOps[] = {
1625 { "eq", FcOpEqual },
1626 { "not_eq", FcOpNotEqual },
1627 { "less", FcOpLess },
1628 { "less_eq", FcOpLessEqual },
1629 { "more", FcOpMore },
1630 { "more_eq", FcOpMoreEqual },
1631 { "contains", FcOpContains },
1632 { "not_contains", FcOpNotContains }
1633 };
1634
1635 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1636
1637 static FcOp
1638 FcConfigLexCompare (const FcChar8 *compare)
1639 {
1640 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1641 }
1642
1643
1644 static void
1645 FcParseTest (FcConfigParse *parse)
1646 {
1647 const FcChar8 *kind_string;
1648 FcMatchKind kind;
1649 const FcChar8 *qual_string;
1650 FcQual qual;
1651 const FcChar8 *name;
1652 const FcChar8 *compare_string;
1653 FcOp compare;
1654 FcExpr *expr;
1655 FcTest *test;
1656
1657 kind_string = FcConfigGetAttribute (parse, "target");
1658 if (!kind_string)
1659 kind = FcMatchDefault;
1660 else
1661 {
1662 if (!strcmp ((char *) kind_string, "pattern"))
1663 kind = FcMatchPattern;
1664 else if (!strcmp ((char *) kind_string, "font"))
1665 kind = FcMatchFont;
1666 else if (!strcmp ((char *) kind_string, "default"))
1667 kind = FcMatchDefault;
1668 else
1669 {
1670 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1671 return;
1672 }
1673 }
1674 qual_string = FcConfigGetAttribute (parse, "qual");
1675 if (!qual_string)
1676 qual = FcQualAny;
1677 else
1678 {
1679 if (!strcmp ((char *) qual_string, "any"))
1680 qual = FcQualAny;
1681 else if (!strcmp ((char *) qual_string, "all"))
1682 qual = FcQualAll;
1683 else if (!strcmp ((char *) qual_string, "first"))
1684 qual = FcQualFirst;
1685 else if (!strcmp ((char *) qual_string, "not_first"))
1686 qual = FcQualNotFirst;
1687 else
1688 {
1689 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1690 return;
1691 }
1692 }
1693 name = FcConfigGetAttribute (parse, "name");
1694 if (!name)
1695 {
1696 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1697 return;
1698 }
1699 compare_string = FcConfigGetAttribute (parse, "compare");
1700 if (!compare_string)
1701 compare = FcOpEqual;
1702 else
1703 {
1704 compare = FcConfigLexCompare (compare_string);
1705 if (compare == FcOpInvalid)
1706 {
1707 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1708 return;
1709 }
1710 }
1711 expr = FcPopBinary (parse, FcOpComma);
1712 if (!expr)
1713 {
1714 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1715 return;
1716 }
1717 test = FcTestCreate (parse, kind, qual, name, compare, expr);
1718 if (!test)
1719 {
1720 FcConfigMessage (parse, FcSevereError, "out of memory");
1721 return;
1722 }
1723 FcVStackPushTest (parse, test);
1724 }
1725
1726 static const FcOpMap fcModeOps[] = {
1727 { "assign", FcOpAssign },
1728 { "assign_replace", FcOpAssignReplace },
1729 { "prepend", FcOpPrepend },
1730 { "prepend_first", FcOpPrependFirst },
1731 { "append", FcOpAppend },
1732 { "append_last", FcOpAppendLast },
1733 };
1734
1735 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1736
1737 static FcOp
1738 FcConfigLexMode (const FcChar8 *mode)
1739 {
1740 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1741 }
1742
1743 static void
1744 FcParseEdit (FcConfigParse *parse)
1745 {
1746 const FcChar8 *name;
1747 const FcChar8 *mode_string;
1748 const FcChar8 *binding_string;
1749 FcOp mode;
1750 FcValueBinding binding;
1751 FcExpr *expr;
1752 FcEdit *edit;
1753
1754 name = FcConfigGetAttribute (parse, "name");
1755 if (!name)
1756 {
1757 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1758 return;
1759 }
1760 mode_string = FcConfigGetAttribute (parse, "mode");
1761 if (!mode_string)
1762 mode = FcOpAssign;
1763 else
1764 {
1765 mode = FcConfigLexMode (mode_string);
1766 if (mode == FcOpInvalid)
1767 {
1768 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1769 return;
1770 }
1771 }
1772 binding_string = FcConfigGetAttribute (parse, "binding");
1773 if (!binding_string)
1774 binding = FcValueBindingWeak;
1775 else
1776 {
1777 if (!strcmp ((char *) binding_string, "weak"))
1778 binding = FcValueBindingWeak;
1779 else if (!strcmp ((char *) binding_string, "strong"))
1780 binding = FcValueBindingStrong;
1781 else if (!strcmp ((char *) binding_string, "same"))
1782 binding = FcValueBindingSame;
1783 else
1784 {
1785 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1786 return;
1787 }
1788 }
1789 expr = FcPopBinary (parse, FcOpComma);
1790 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
1791 if (!edit)
1792 {
1793 FcConfigMessage (parse, FcSevereError, "out of memory");
1794 FcExprDestroy (expr);
1795 return;
1796 }
1797 if (!FcVStackPushEdit (parse, edit))
1798 FcEditDestroy (edit);
1799 }
1800
1801 static void
1802 FcParseMatch (FcConfigParse *parse)
1803 {
1804 const FcChar8 *kind_name;
1805 FcMatchKind kind;
1806 FcTest *test = 0;
1807 FcEdit *edit = 0;
1808 FcVStack *vstack;
1809
1810 kind_name = FcConfigGetAttribute (parse, "target");
1811 if (!kind_name)
1812 kind = FcMatchPattern;
1813 else
1814 {
1815 if (!strcmp ((char *) kind_name, "pattern"))
1816 kind = FcMatchPattern;
1817 else if (!strcmp ((char *) kind_name, "font"))
1818 kind = FcMatchFont;
1819 else
1820 {
1821 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1822 return;
1823 }
1824 }
1825 while ((vstack = FcVStackPop (parse)))
1826 {
1827 switch (vstack->tag) {
1828 case FcVStackTest:
1829 vstack->u.test->next = test;
1830 test = vstack->u.test;
1831 vstack->tag = FcVStackNone;
1832 break;
1833 case FcVStackEdit:
1834 vstack->u.edit->next = edit;
1835 edit = vstack->u.edit;
1836 vstack->tag = FcVStackNone;
1837 break;
1838 default:
1839 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1840 break;
1841 }
1842 FcVStackDestroy (vstack);
1843 }
1844 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1845 FcConfigMessage (parse, FcSevereError, "out of memory");
1846 }
1847
1848 static void
1849 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1850 {
1851 FcVStack *vstack;
1852
1853 while ((vstack = FcVStackPop (parse)))
1854 {
1855 switch (vstack->tag) {
1856 case FcVStackGlob:
1857 if (!FcConfigGlobAdd (parse->config,
1858 vstack->u.string,
1859 element == FcElementAcceptfont))
1860 {
1861 FcConfigMessage (parse, FcSevereError, "out of memory");
1862 }
1863 break;
1864 case FcVStackPattern:
1865 if (!FcConfigPatternsAdd (parse->config,
1866 vstack->u.pattern,
1867 element == FcElementAcceptfont))
1868 {
1869 FcConfigMessage (parse, FcSevereError, "out of memory");
1870 }
1871 else
1872 vstack->tag = FcVStackNone;
1873 break;
1874 default:
1875 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1876 break;
1877 }
1878 FcVStackDestroy (vstack);
1879 }
1880 }
1881
1882
1883 static FcValue
1884 FcPopValue (FcConfigParse *parse)
1885 {
1886 FcVStack *vstack = FcVStackPop (parse);
1887 FcValue value;
1888
1889 value.type = FcTypeVoid;
1890
1891 if (!vstack)
1892 return value;
1893
1894 switch (vstack->tag) {
1895 case FcVStackString:
1896 value.u.s = FcStrCopy (vstack->u.string);
1897 if (value.u.s)
1898 value.type = FcTypeString;
1899 break;
1900 case FcVStackConstant:
1901 if (FcNameConstant (vstack->u.string, &value.u.i))
1902 value.type = FcTypeInteger;
1903 break;
1904 case FcVStackInteger:
1905 value.u.i = vstack->u.integer;
1906 value.type = FcTypeInteger;
1907 break;
1908 case FcVStackDouble:
1909 value.u.d = vstack->u._double;
1910 value.type = FcTypeInteger;
1911 break;
1912 case FcVStackMatrix:
1913 value.u.m = FcMatrixCopy (vstack->u.matrix);
1914 if (value.u.m)
1915 value.type = FcTypeMatrix;
1916 break;
1917 case FcVStackBool:
1918 value.u.b = vstack->u.bool;
1919 value.type = FcTypeBool;
1920 break;
1921 default:
1922 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1923 vstack->tag);
1924 break;
1925 }
1926 FcVStackDestroy (vstack);
1927
1928 return value;
1929 }
1930
1931 static void
1932 FcParsePatelt (FcConfigParse *parse)
1933 {
1934 FcValue value;
1935 FcPattern *pattern = FcPatternCreate ();
1936 const char *name;
1937
1938 if (!pattern)
1939 {
1940 FcConfigMessage (parse, FcSevereError, "out of memory");
1941 return;
1942 }
1943
1944 name = (char *) FcConfigGetAttribute (parse, "name");
1945 if (!name)
1946 {
1947 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1948 return;
1949 }
1950
1951 for (;;)
1952 {
1953 value = FcPopValue (parse);
1954 if (value.type == FcTypeVoid)
1955 break;
1956 if (!FcPatternAdd (pattern, name, value, FcTrue))
1957 {
1958 FcConfigMessage (parse, FcSevereError, "out of memory");
1959 break;
1960 }
1961 }
1962
1963 FcVStackPushPattern (parse, pattern);
1964 }
1965
1966 static void
1967 FcParsePattern (FcConfigParse *parse)
1968 {
1969 FcVStack *vstack;
1970 FcPattern *pattern = FcPatternCreate ();
1971
1972 if (!pattern)
1973 {
1974 FcConfigMessage (parse, FcSevereError, "out of memory");
1975 return;
1976 }
1977
1978 while ((vstack = FcVStackPop (parse)))
1979 {
1980 switch (vstack->tag) {
1981 case FcVStackPattern:
1982 if (!FcPatternAppend (pattern, vstack->u.pattern))
1983 {
1984 FcConfigMessage (parse, FcSevereError, "out of memory");
1985 return;
1986 }
1987 break;
1988 default:
1989 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1990 break;
1991 }
1992 FcVStackDestroy (vstack);
1993 }
1994
1995 FcVStackPushPattern (parse, pattern);
1996 }
1997
1998 static void
1999 FcEndElement(void *userData, const XML_Char *name)
2000 {
2001 FcConfigParse *parse = userData;
2002 FcChar8 *data;
2003
2004 if (!parse->pstack)
2005 return;
2006 switch (parse->pstack->element) {
2007 case FcElementNone:
2008 break;
2009 case FcElementFontconfig:
2010 break;
2011 case FcElementDir:
2012 data = FcStrBufDone (&parse->pstack->str);
2013 if (!data)
2014 {
2015 FcConfigMessage (parse, FcSevereError, "out of memory");
2016 break;
2017 }
2018 #ifdef _WIN32
2019 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2020 {
2021 int rc;
2022 FcStrFree (data);
2023 data = malloc (1000);
2024 if (!data)
2025 {
2026 FcConfigMessage (parse, FcSevereError, "out of memory");
2027 break;
2028 }
2029 FcMemAlloc (FC_MEM_STRING, 1000);
2030 rc = GetWindowsDirectory (data, 800);
2031 if (rc == 0 || rc > 800)
2032 {
2033 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2034 FcStrFree (data);
2035 break;
2036 }
2037 if (data [strlen (data) - 1] != '\\')
2038 strcat (data, "\\");
2039 strcat (data, "fonts");
2040 }
2041 #endif
2042 if (!FcStrUsesHome (data) || FcConfigHome ())
2043 {
2044 if (!FcConfigAddDir (parse->config, data))
2045 FcConfigMessage (parse, FcSevereError, "out of memory");
2046 }
2047 FcStrFree (data);
2048 break;
2049 case FcElementCache:
2050 data = FcStrBufDone (&parse->pstack->str);
2051 if (!data)
2052 {
2053 FcConfigMessage (parse, FcSevereError, "out of memory");
2054 break;
2055 }
2056 if (!FcStrUsesHome (data) || FcConfigHome ())
2057 {
2058 if (!FcConfigSetCache (parse->config, data))
2059 FcConfigMessage (parse, FcSevereError, "out of memory");
2060 }
2061 FcStrFree (data);
2062 break;
2063 case FcElementInclude:
2064 FcParseInclude (parse);
2065 break;
2066 case FcElementConfig:
2067 break;
2068 case FcElementMatch:
2069 FcParseMatch (parse);
2070 break;
2071 case FcElementAlias:
2072 FcParseAlias (parse);
2073 break;
2074
2075 case FcElementBlank:
2076 FcParseBlank (parse);
2077 break;
2078 case FcElementRescan:
2079 FcParseRescan (parse);
2080 break;
2081
2082 case FcElementPrefer:
2083 FcParseFamilies (parse, FcVStackPrefer);
2084 break;
2085 case FcElementAccept:
2086 FcParseFamilies (parse, FcVStackAccept);
2087 break;
2088 case FcElementDefault:
2089 FcParseFamilies (parse, FcVStackDefault);
2090 break;
2091 case FcElementFamily:
2092 FcParseFamily (parse);
2093 break;
2094
2095 case FcElementTest:
2096 FcParseTest (parse);
2097 break;
2098 case FcElementEdit:
2099 FcParseEdit (parse);
2100 break;
2101
2102 case FcElementInt:
2103 FcParseInt (parse);
2104 break;
2105 case FcElementDouble:
2106 FcParseDouble (parse);
2107 break;
2108 case FcElementString:
2109 FcParseString (parse, FcVStackString);
2110 break;
2111 case FcElementMatrix:
2112 FcParseMatrix (parse);
2113 break;
2114 case FcElementBool:
2115 FcParseBool (parse);
2116 break;
2117 case FcElementCharset:
2118 /* FcParseCharset (parse); */
2119 break;
2120 case FcElementSelectfont:
2121 break;
2122 case FcElementAcceptfont:
2123 case FcElementRejectfont:
2124 FcParseAcceptRejectFont (parse, parse->pstack->element);
2125 break;
2126 case FcElementGlob:
2127 FcParseString (parse, FcVStackGlob);
2128 break;
2129 case FcElementPattern:
2130 FcParsePattern (parse);
2131 break;
2132 case FcElementPatelt:
2133 FcParsePatelt (parse);
2134 break;
2135 case FcElementName:
2136 FcParseString (parse, FcVStackField);
2137 break;
2138 case FcElementConst:
2139 FcParseString (parse, FcVStackConstant);
2140 break;
2141 case FcElementOr:
2142 FcParseBinary (parse, FcOpOr);
2143 break;
2144 case FcElementAnd:
2145 FcParseBinary (parse, FcOpAnd);
2146 break;
2147 case FcElementEq:
2148 FcParseBinary (parse, FcOpEqual);
2149 break;
2150 case FcElementNotEq:
2151 FcParseBinary (parse, FcOpNotEqual);
2152 break;
2153 case FcElementLess:
2154 FcParseBinary (parse, FcOpLess);
2155 break;
2156 case FcElementLessEq:
2157 FcParseBinary (parse, FcOpLessEqual);
2158 break;
2159 case FcElementMore:
2160 FcParseBinary (parse, FcOpMore);
2161 break;
2162 case FcElementMoreEq:
2163 FcParseBinary (parse, FcOpMoreEqual);
2164 break;
2165 case FcElementContains:
2166 FcParseBinary (parse, FcOpContains);
2167 break;
2168 case FcElementNotContains:
2169 FcParseBinary (parse, FcOpNotContains);
2170 break;
2171 case FcElementPlus:
2172 FcParseBinary (parse, FcOpPlus);
2173 break;
2174 case FcElementMinus:
2175 FcParseBinary (parse, FcOpMinus);
2176 break;
2177 case FcElementTimes:
2178 FcParseBinary (parse, FcOpTimes);
2179 break;
2180 case FcElementDivide:
2181 FcParseBinary (parse, FcOpDivide);
2182 break;
2183 case FcElementNot:
2184 FcParseUnary (parse, FcOpNot);
2185 break;
2186 case FcElementIf:
2187 FcParseBinary (parse, FcOpQuest);
2188 break;
2189 case FcElementFloor:
2190 FcParseUnary (parse, FcOpFloor);
2191 break;
2192 case FcElementCeil:
2193 FcParseUnary (parse, FcOpCeil);
2194 break;
2195 case FcElementRound:
2196 FcParseUnary (parse, FcOpRound);
2197 break;
2198 case FcElementTrunc:
2199 FcParseUnary (parse, FcOpTrunc);
2200 break;
2201 case FcElementUnknown:
2202 break;
2203 }
2204 (void) FcPStackPop (parse);
2205 }
2206
2207 static void
2208 FcCharacterData (void *userData, const XML_Char *s, int len)
2209 {
2210 FcConfigParse *parse = userData;
2211
2212 if (!parse->pstack)
2213 return;
2214 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2215 FcConfigMessage (parse, FcSevereError, "out of memory");
2216 }
2217
2218 static void
2219 FcStartDoctypeDecl (void *userData,
2220 const XML_Char *doctypeName,
2221 const XML_Char *sysid,
2222 const XML_Char *pubid,
2223 int has_internal_subset)
2224 {
2225 FcConfigParse *parse = userData;
2226
2227 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2228 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2229 }
2230
2231 #if ENABLE_LIBXML2
2232
2233 static void
2234 FcInternalSubsetDecl (void *userData,
2235 const XML_Char *doctypeName,
2236 const XML_Char *sysid,
2237 const XML_Char *pubid)
2238 {
2239 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2240 }
2241
2242 static void
2243 FcExternalSubsetDecl (void *userData,
2244 const XML_Char *doctypeName,
2245 const XML_Char *sysid,
2246 const XML_Char *pubid)
2247 {
2248 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2249 }
2250
2251 #else /* ENABLE_LIBXML2 */
2252
2253 static void
2254 FcEndDoctypeDecl (void *userData)
2255 {
2256 }
2257
2258 #endif /* ENABLE_LIBXML2 */
2259
2260 static FcBool
2261 FcConfigParseAndLoadDir (FcConfig *config,
2262 const FcChar8 *name,
2263 const FcChar8 *dir,
2264 FcBool complain)
2265 {
2266 DIR *d;
2267 struct dirent *e;
2268 FcBool ret = FcTrue;
2269 FcChar8 *file;
2270 FcChar8 *base;
2271 FcStrSet *files;
2272
2273 d = opendir ((char *) dir);
2274 if (!d)
2275 {
2276 if (complain)
2277 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2278 name);
2279 ret = FcFalse;
2280 goto bail0;
2281 }
2282 /* freed below */
2283 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2284 if (!file)
2285 {
2286 ret = FcFalse;
2287 goto bail1;
2288 }
2289
2290 strcpy ((char *) file, (char *) dir);
2291 strcat ((char *) file, "/");
2292 base = file + strlen ((char *) file);
2293
2294 files = FcStrSetCreate ();
2295 if (!files)
2296 {
2297 ret = FcFalse;
2298 goto bail2;
2299 }
2300
2301 if (FcDebug () & FC_DBG_CONFIG)
2302 printf ("\tScanning config dir %s\n", dir);
2303
2304 while (ret && (e = readdir (d)))
2305 {
2306 int d_len;
2307 #define TAIL ".conf"
2308 #define TAIL_LEN 5
2309 /*
2310 * Add all files of the form [0-9]*.conf
2311 */
2312 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2313 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2314 d_len > TAIL_LEN &&
2315 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2316 {
2317 strcpy ((char *) base, (char *) e->d_name);
2318 if (!FcStrSetAdd (files, file))
2319 {
2320 ret = FcFalse;
2321 goto bail3;
2322 }
2323 }
2324 }
2325 if (ret)
2326 {
2327 int i;
2328 qsort (files->strs, files->num, sizeof (FcChar8 *),
2329 (int (*)(const void *, const void *)) FcStrCmp);
2330 for (i = 0; ret && i < files->num; i++)
2331 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2332 }
2333 bail3:
2334 FcStrSetDestroy (files);
2335 bail2:
2336 free (file);
2337 bail1:
2338 closedir (d);
2339 bail0:
2340 return ret || !complain;
2341 }
2342
2343 FcBool
2344 FcConfigParseAndLoad (FcConfig *config,
2345 const FcChar8 *name,
2346 FcBool complain)
2347 {
2348
2349 XML_Parser p;
2350 FcChar8 *filename;
2351 FILE *f;
2352 int len;
2353 FcConfigParse parse;
2354 FcBool error = FcTrue;
2355
2356 #if ENABLE_LIBXML2
2357 xmlSAXHandler sax;
2358 char buf[BUFSIZ];
2359 #else
2360 void *buf;
2361 #endif
2362
2363 filename = FcConfigFilename (name);
2364 if (!filename)
2365 goto bail0;
2366
2367 if (!FcStrSetAdd (config->configFiles, filename))
2368 {
2369 FcStrFree (filename);
2370 goto bail0;
2371 }
2372
2373 if (FcFileIsDir (filename))
2374 {
2375 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2376 FcStrFree (filename);
2377 return ret;
2378 }
2379
2380 if (FcDebug () & FC_DBG_CONFIG)
2381 printf ("\tLoading config file %s\n", filename);
2382
2383 f = fopen ((char *) filename, "r");
2384 FcStrFree (filename);
2385 if (!f)
2386 goto bail0;
2387
2388 #if ENABLE_LIBXML2
2389 memset(&sax, 0, sizeof(sax));
2390
2391 sax.internalSubset = FcInternalSubsetDecl;
2392 sax.externalSubset = FcExternalSubsetDecl;
2393 sax.startElement = FcStartElement;
2394 sax.endElement = FcEndElement;
2395 sax.characters = FcCharacterData;
2396
2397 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, filename);
2398 #else
2399 p = XML_ParserCreate ("UTF-8");
2400 #endif
2401
2402 if (!p)
2403 goto bail1;
2404
2405 if (!FcConfigInit (&parse, name, config, p))
2406 goto bail2;
2407
2408 #if !ENABLE_LIBXML2
2409
2410 XML_SetUserData (p, &parse);
2411
2412 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2413 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2414 XML_SetCharacterDataHandler (p, FcCharacterData);
2415
2416 #endif /* ENABLE_LIBXML2 */
2417
2418 do {
2419 #if !ENABLE_LIBXML2
2420 buf = XML_GetBuffer (p, BUFSIZ);
2421 if (!buf)
2422 {
2423 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2424 goto bail3;
2425 }
2426 #endif
2427 len = fread (buf, 1, BUFSIZ, f);
2428 if (len < 0)
2429 {
2430 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2431 goto bail3;
2432 }
2433
2434 #if ENABLE_LIBXML2
2435 if (xmlParseChunk (p, buf, len, len == 0))
2436 #else
2437 if (!XML_ParseBuffer (p, len, len == 0))
2438 #endif
2439 {
2440 FcConfigMessage (&parse, FcSevereError, "%s",
2441 XML_ErrorString (XML_GetErrorCode (p)));
2442 goto bail3;
2443 }
2444 } while (len != 0);
2445 error = parse.error;
2446 bail3:
2447 FcConfigCleanup (&parse);
2448 bail2:
2449 XML_ParserFree (p);
2450 bail1:
2451 fclose (f);
2452 f = NULL;
2453 bail0:
2454 if (error && complain)
2455 {
2456 if (name)
2457 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2458 else
2459 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2460 return FcFalse;
2461 }
2462 return FcTrue;
2463 }