]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Replace silly avl sort with qsort, add FcPatternEqual
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.7 2002/05/21 17:06:22 keithp Exp $
3 *
4 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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
28 #if HAVE_EXPAT
29 #if HAVE_XMLPARSE_H
30 #include <xmlparse.h>
31 #else
32 #include <expat.h>
33 #endif
34 #endif
35
36 #if HAVE_XML2
37 #include "fclibxml2.h"
38 #endif
39
40 FcTest *
41 FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr)
42 {
43 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
44
45 if (test)
46 {
47 test->next = 0;
48 test->qual = qual;
49 test->field = (char *) FcStrCopy (field);
50 test->op = compare;
51 test->expr = expr;
52 }
53 return test;
54 }
55
56 void
57 FcTestDestroy (FcTest *test)
58 {
59 if (test->next)
60 FcTestDestroy (test->next);
61 FcExprDestroy (test->expr);
62 FcStrFree ((FcChar8 *) test->field);
63 free (test);
64 }
65
66 FcExpr *
67 FcExprCreateInteger (int i)
68 {
69 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
70
71 if (e)
72 {
73 e->op = FcOpInteger;
74 e->u.ival = i;
75 }
76 return e;
77 }
78
79 FcExpr *
80 FcExprCreateDouble (double d)
81 {
82 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
83
84 if (e)
85 {
86 e->op = FcOpDouble;
87 e->u.dval = d;
88 }
89 return e;
90 }
91
92 FcExpr *
93 FcExprCreateString (const FcChar8 *s)
94 {
95 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
96
97 if (e)
98 {
99 e->op = FcOpString;
100 e->u.sval = FcStrCopy (s);
101 }
102 return e;
103 }
104
105 FcExpr *
106 FcExprCreateMatrix (const FcMatrix *m)
107 {
108 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
109
110 if (e)
111 {
112 e->op = FcOpMatrix;
113 e->u.mval = FcMatrixCopy (m);
114 }
115 return e;
116 }
117
118 FcExpr *
119 FcExprCreateBool (FcBool b)
120 {
121 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
122
123 if (e)
124 {
125 e->op = FcOpBool;
126 e->u.bval = b;
127 }
128 return e;
129 }
130
131 FcExpr *
132 FcExprCreateNil (void)
133 {
134 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
135
136 if (e)
137 {
138 e->op = FcOpNil;
139 }
140 return e;
141 }
142
143 FcExpr *
144 FcExprCreateField (const char *field)
145 {
146 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
147
148 if (e)
149 {
150 e->op = FcOpField;
151 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
152 }
153 return e;
154 }
155
156 FcExpr *
157 FcExprCreateConst (const FcChar8 *constant)
158 {
159 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
160
161 if (e)
162 {
163 e->op = FcOpConst;
164 e->u.constant = FcStrCopy (constant);
165 }
166 return e;
167 }
168
169 FcExpr *
170 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
171 {
172 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174 if (e)
175 {
176 e->op = op;
177 e->u.tree.left = left;
178 e->u.tree.right = right;
179 }
180 return e;
181 }
182
183 void
184 FcExprDestroy (FcExpr *e)
185 {
186 switch (e->op) {
187 case FcOpInteger:
188 break;
189 case FcOpDouble:
190 break;
191 case FcOpString:
192 FcStrFree (e->u.sval);
193 break;
194 case FcOpMatrix:
195 FcMatrixFree (e->u.mval);
196 break;
197 case FcOpCharSet:
198 FcCharSetDestroy (e->u.cval);
199 break;
200 case FcOpBool:
201 break;
202 case FcOpField:
203 FcStrFree ((FcChar8 *) e->u.field);
204 break;
205 case FcOpConst:
206 FcStrFree (e->u.constant);
207 break;
208 case FcOpAssign:
209 case FcOpAssignReplace:
210 case FcOpPrepend:
211 case FcOpPrependFirst:
212 case FcOpAppend:
213 case FcOpAppendLast:
214 break;
215 case FcOpOr:
216 case FcOpAnd:
217 case FcOpEqual:
218 case FcOpContains:
219 case FcOpNotEqual:
220 case FcOpLess:
221 case FcOpLessEqual:
222 case FcOpMore:
223 case FcOpMoreEqual:
224 case FcOpPlus:
225 case FcOpMinus:
226 case FcOpTimes:
227 case FcOpDivide:
228 case FcOpQuest:
229 case FcOpComma:
230 FcExprDestroy (e->u.tree.right);
231 /* fall through */
232 case FcOpNot:
233 FcExprDestroy (e->u.tree.left);
234 break;
235 case FcOpNil:
236 case FcOpInvalid:
237 break;
238 }
239 free (e);
240 }
241
242 FcEdit *
243 FcEditCreate (const char *field, FcOp op, FcExpr *expr)
244 {
245 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
246
247 if (e)
248 {
249 e->next = 0;
250 e->field = field; /* already saved in grammar */
251 e->op = op;
252 e->expr = expr;
253 }
254 return e;
255 }
256
257 void
258 FcEditDestroy (FcEdit *e)
259 {
260 if (e->next)
261 FcEditDestroy (e->next);
262 FcStrFree ((FcChar8 *) e->field);
263 if (e->expr)
264 FcExprDestroy (e->expr);
265 }
266
267 char *
268 FcConfigSaveField (const char *field)
269 {
270 return (char *) FcStrCopy ((FcChar8 *) field);
271 }
272
273 typedef enum _FcElement {
274 FcElementNone,
275 FcElementFontconfig,
276 FcElementDir,
277 FcElementCache,
278 FcElementInclude,
279 FcElementConfig,
280 FcElementMatch,
281 FcElementAlias,
282
283 FcElementBlank,
284 FcElementRescan,
285
286 FcElementPrefer,
287 FcElementAccept,
288 FcElementDefault,
289 FcElementFamily,
290
291 FcElementTest,
292 FcElementEdit,
293 FcElementInt,
294 FcElementDouble,
295 FcElementString,
296 FcElementMatrix,
297 FcElementBool,
298 FcElementCharset,
299 FcElementName,
300 FcElementConst,
301 FcElementOr,
302 FcElementAnd,
303 FcElementEq,
304 FcElementNotEq,
305 FcElementLess,
306 FcElementLessEq,
307 FcElementMore,
308 FcElementMoreEq,
309 FcElementPlus,
310 FcElementMinus,
311 FcElementTimes,
312 FcElementDivide,
313 FcElementNot,
314 FcElementIf,
315 FcElementUnknown
316 } FcElement;
317
318 static FcElement
319 FcElementMap (const XML_Char *name)
320 {
321 static struct {
322 char *name;
323 FcElement element;
324 } fcElementMap[] = {
325 { "fontconfig", FcElementFontconfig },
326 { "dir", FcElementDir },
327 { "cache", FcElementCache },
328 { "include", FcElementInclude },
329 { "config", FcElementConfig },
330 { "match", FcElementMatch },
331 { "alias", FcElementAlias },
332
333 { "blank", FcElementBlank },
334 { "rescan", FcElementRescan },
335
336 { "prefer", FcElementPrefer },
337 { "accept", FcElementAccept },
338 { "default", FcElementDefault },
339 { "family", FcElementFamily },
340
341 { "test", FcElementTest },
342 { "edit", FcElementEdit },
343 { "int", FcElementInt },
344 { "double", FcElementDouble },
345 { "string", FcElementString },
346 { "matrix", FcElementMatrix },
347 { "bool", FcElementBool },
348 { "charset", FcElementCharset },
349 { "name", FcElementName },
350 { "const", FcElementConst },
351 { "or", FcElementOr },
352 { "and", FcElementAnd },
353 { "eq", FcElementEq },
354 { "not_eq", FcElementNotEq },
355 { "less", FcElementLess },
356 { "less_eq", FcElementLessEq },
357 { "more", FcElementMore },
358 { "more_eq", FcElementMoreEq },
359 { "plus", FcElementPlus },
360 { "minus", FcElementMinus },
361 { "times", FcElementTimes },
362 { "divide", FcElementDivide },
363 { "not", FcElementNot },
364 { "if", FcElementIf },
365
366 { 0, 0 }
367 };
368
369 int i;
370 for (i = 0; fcElementMap[i].name; i++)
371 if (!strcmp ((char *) name, fcElementMap[i].name))
372 return fcElementMap[i].element;
373 return FcElementUnknown;
374 }
375
376 typedef struct _FcPStack {
377 struct _FcPStack *prev;
378 FcElement element;
379 FcChar8 **attr;
380 FcStrBuf str;
381 } FcPStack;
382
383 typedef enum _FcVStackTag {
384 FcVStackNone,
385
386 FcVStackString,
387 FcVStackFamily,
388 FcVStackField,
389 FcVStackConstant,
390
391 FcVStackPrefer,
392 FcVStackAccept,
393 FcVStackDefault,
394
395 FcVStackInteger,
396 FcVStackDouble,
397 FcVStackMatrix,
398 FcVStackBool,
399
400 FcVStackTest,
401 FcVStackExpr,
402 FcVStackEdit
403 } FcVStackTag;
404
405 typedef struct _FcVStack {
406 struct _FcVStack *prev;
407 FcPStack *pstack; /* related parse element */
408 FcVStackTag tag;
409 union {
410 FcChar8 *string;
411
412 int integer;
413 double _double;
414 FcMatrix *matrix;
415 FcBool bool;
416
417 FcTest *test;
418 FcQual qual;
419 FcOp op;
420 FcExpr *expr;
421 FcEdit *edit;
422 } u;
423 } FcVStack;
424
425 typedef struct _FcConfigParse {
426 FcPStack *pstack;
427 FcVStack *vstack;
428 FcBool error;
429 const FcChar8 *name;
430 FcConfig *config;
431 XML_Parser parser;
432 } FcConfigParse;
433
434 typedef enum _FcConfigSeverity {
435 FcSevereInfo, FcSevereWarning, FcSevereError
436 } FcConfigSeverity;
437
438 static void
439 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
440 {
441 char *s = "unknown";
442 va_list args;
443
444 va_start (args, fmt);
445
446 switch (severe) {
447 case FcSevereInfo: s = "info"; break;
448 case FcSevereWarning: s = "warning"; break;
449 case FcSevereError: s = "error"; break;
450 }
451 if (parse)
452 {
453 if (parse->name)
454 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
455 parse->name, XML_GetCurrentLineNumber (parse->parser));
456 else
457 fprintf (stderr, "Fontconfig %s: line %d: ", s,
458 XML_GetCurrentLineNumber (parse->parser));
459 if (severe >= FcSevereError)
460 parse->error = FcTrue;
461 }
462 else
463 fprintf (stderr, "Fontconfig %s: ", s);
464 vfprintf (stderr, fmt, args);
465 fprintf (stderr, "\n");
466 va_end (args);
467 }
468
469 static void
470 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
471 {
472 vstack->prev = parse->vstack;
473 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
474 parse->vstack = vstack;
475 }
476
477 static FcVStack *
478 FcVStackCreate (void)
479 {
480 FcVStack *new;
481
482 new = malloc (sizeof (FcVStack));
483 if (!new)
484 return 0;
485 new->tag = FcVStackNone;
486 new->prev = 0;
487 return new;
488 }
489
490 static void
491 FcVStackDestroy (FcVStack *vstack)
492 {
493 FcVStack *prev;
494
495 for (; vstack; vstack = prev)
496 {
497 prev = vstack->prev;
498 switch (vstack->tag) {
499 case FcVStackNone:
500 break;
501 case FcVStackString:
502 case FcVStackFamily:
503 case FcVStackField:
504 case FcVStackConstant:
505 FcStrFree (vstack->u.string);
506 break;
507 case FcVStackInteger:
508 case FcVStackDouble:
509 break;
510 case FcVStackMatrix:
511 FcMatrixFree (vstack->u.matrix);
512 break;
513 case FcVStackBool:
514 break;
515 case FcVStackTest:
516 FcTestDestroy (vstack->u.test);
517 break;
518 case FcVStackExpr:
519 case FcVStackPrefer:
520 case FcVStackAccept:
521 case FcVStackDefault:
522 FcExprDestroy (vstack->u.expr);
523 break;
524 case FcVStackEdit:
525 FcEditDestroy (vstack->u.edit);
526 break;
527 }
528 free (vstack);
529 }
530 }
531
532 static FcBool
533 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
534 {
535 FcVStack *vstack = FcVStackCreate ();
536 if (!vstack)
537 return FcFalse;
538 vstack->u.string = string;
539 vstack->tag = tag;
540 FcVStackPush (parse, vstack);
541 return FcTrue;
542 }
543
544 static FcBool
545 FcVStackPushInteger (FcConfigParse *parse, int integer)
546 {
547 FcVStack *vstack = FcVStackCreate ();
548 if (!vstack)
549 return FcFalse;
550 vstack->u.integer = integer;
551 vstack->tag = FcVStackInteger;
552 FcVStackPush (parse, vstack);
553 return FcTrue;
554 }
555
556 static FcBool
557 FcVStackPushDouble (FcConfigParse *parse, double _double)
558 {
559 FcVStack *vstack = FcVStackCreate ();
560 if (!vstack)
561 return FcFalse;
562 vstack->u._double = _double;
563 vstack->tag = FcVStackDouble;
564 FcVStackPush (parse, vstack);
565 return FcTrue;
566 }
567
568 static FcBool
569 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
570 {
571 FcVStack *vstack = FcVStackCreate ();
572 if (!vstack)
573 return FcFalse;
574 matrix = FcMatrixCopy (matrix);
575 if (!matrix)
576 {
577 FcVStackDestroy (vstack);
578 return FcFalse;
579 }
580 vstack->u.matrix = matrix;
581 vstack->tag = FcVStackMatrix;
582 FcVStackPush (parse, vstack);
583 return FcTrue;
584 }
585
586 static FcBool
587 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
588 {
589 FcVStack *vstack = FcVStackCreate ();
590 if (!vstack)
591 return FcFalse;
592 vstack->u.bool = bool;
593 vstack->tag = FcVStackBool;
594 FcVStackPush (parse, vstack);
595 return FcTrue;
596 }
597
598 static FcBool
599 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
600 {
601 FcVStack *vstack = FcVStackCreate ();
602 if (!vstack)
603 return FcFalse;
604 vstack->u.test = test;
605 vstack->tag = FcVStackTest;
606 FcVStackPush (parse, vstack);
607 return FcTrue;
608 }
609
610 static FcBool
611 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
612 {
613 FcVStack *vstack = FcVStackCreate ();
614 if (!vstack)
615 return FcFalse;
616 vstack->u.expr = expr;
617 vstack->tag = tag;
618 FcVStackPush (parse, vstack);
619 return FcTrue;
620 }
621
622 static FcBool
623 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
624 {
625 FcVStack *vstack = FcVStackCreate ();
626 if (!vstack)
627 return FcFalse;
628 vstack->u.edit = edit;
629 vstack->tag = FcVStackEdit;
630 FcVStackPush (parse, vstack);
631 return FcTrue;
632 }
633
634 static FcVStack *
635 FcVStackFetch (FcConfigParse *parse, int off)
636 {
637 FcVStack *vstack;
638
639 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
640 return vstack;
641 }
642
643 static void
644 FcVStackClear (FcConfigParse *parse)
645 {
646 while (parse->vstack && parse->vstack->pstack == parse->pstack)
647 {
648 FcVStack *vstack = parse->vstack;
649 parse->vstack = vstack->prev;
650 vstack->prev = 0;
651 FcVStackDestroy (vstack);
652 }
653 }
654
655 static FcVStack *
656 FcVStackPop (FcConfigParse *parse)
657 {
658 FcVStack *vstack = parse->vstack;
659
660 if (!vstack || vstack->pstack != parse->pstack)
661 return 0;
662 parse->vstack = vstack->prev;
663 vstack->prev = 0;
664 return vstack;
665 }
666
667 static int
668 FcVStackElements (FcConfigParse *parse)
669 {
670 int h = 0;
671 FcVStack *vstack = parse->vstack;
672 while (vstack && vstack->pstack == parse->pstack)
673 {
674 h++;
675 vstack = vstack->prev;
676 }
677 return h;
678 }
679
680 static FcChar8 **
681 FcConfigSaveAttr (const XML_Char **attr)
682 {
683 int n;
684 int slen;
685 int i;
686 FcChar8 **new;
687 FcChar8 *s;
688
689 if (!attr)
690 return 0;
691 slen = 0;
692 for (i = 0; attr[i]; i++)
693 slen += strlen (attr[i]) + 1;
694 n = i;
695 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
696 if (!new)
697 return 0;
698 s = (FcChar8 *) (new + (i + 1));
699 for (i = 0; attr[i]; i++)
700 {
701 new[i] = s;
702 strcpy ((char *) s, (char *) attr[i]);
703 s += strlen ((char *) s) + 1;
704 }
705 new[i] = 0;
706 return new;
707 }
708
709 static FcBool
710 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
711 {
712 FcPStack *new = malloc (sizeof (FcPStack));
713
714 if (!new)
715 return FcFalse;
716 new->prev = parse->pstack;
717 new->element = element;
718 if (attr)
719 {
720 new->attr = FcConfigSaveAttr (attr);
721 if (!new->attr)
722 FcConfigMessage (parse, FcSevereError, "out of memory");
723 }
724 else
725 new->attr = 0;
726 FcStrBufInit (&new->str, 0, 0);
727 parse->pstack = new;
728 return FcTrue;
729 }
730
731 static FcBool
732 FcPStackPop (FcConfigParse *parse)
733 {
734 FcPStack *old;
735
736 if (!parse->pstack)
737 {
738 FcConfigMessage (parse, FcSevereError, "mismatching element");
739 return FcFalse;
740 }
741 FcVStackClear (parse);
742 old = parse->pstack;
743 parse->pstack = old->prev;
744 FcStrBufDestroy (&old->str);
745 if (old->attr)
746 free (old->attr);
747 free (old);
748 return FcTrue;
749 }
750
751 static FcBool
752 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
753 {
754 parse->pstack = 0;
755 parse->vstack = 0;
756 parse->error = FcFalse;
757 parse->name = name;
758 parse->config = config;
759 parse->parser = parser;
760 return FcTrue;
761 }
762
763 static void
764 FcConfigCleanup (FcConfigParse *parse)
765 {
766 while (parse->pstack)
767 FcPStackPop (parse);
768 }
769
770 static const FcChar8 *
771 FcConfigGetAttribute (FcConfigParse *parse, char *attr)
772 {
773 FcChar8 **attrs;
774 if (!parse->pstack)
775 return 0;
776
777 attrs = parse->pstack->attr;
778 while (*attrs)
779 {
780 if (!strcmp ((char *) *attrs, attr))
781 return attrs[1];
782 attrs += 2;
783 }
784 return 0;
785 }
786
787 static void
788 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
789 {
790 FcConfigParse *parse = userData;
791 FcElement element;
792
793 element = FcElementMap (name);
794 if (element == FcElementUnknown)
795 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
796
797 if (!FcPStackPush (parse, element, attr))
798 {
799 FcConfigMessage (parse, FcSevereError, "out of memory");
800 return;
801 }
802 return;
803 }
804
805 static void
806 FcParseBlank (FcConfigParse *parse)
807 {
808 int n = FcVStackElements (parse);
809 while (n-- > 0)
810 {
811 FcVStack *v = FcVStackFetch (parse, n);
812 if (v->tag != FcVStackInteger)
813 FcConfigMessage (parse, FcSevereError, "non-integer blank");
814 else
815 {
816 if (!parse->config->blanks)
817 {
818 parse->config->blanks = FcBlanksCreate ();
819 if (!parse->config->blanks)
820 {
821 FcConfigMessage (parse, FcSevereError, "out of memory");
822 break;
823 }
824 }
825 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
826 {
827 FcConfigMessage (parse, FcSevereError, "out of memory");
828 break;
829 }
830 }
831 }
832 }
833
834 static void
835 FcParseRescan (FcConfigParse *parse)
836 {
837 int n = FcVStackElements (parse);
838 while (n-- > 0)
839 {
840 FcVStack *v = FcVStackFetch (parse, n);
841 if (v->tag != FcVStackInteger)
842 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
843 else
844 parse->config->rescanInterval = v->u.integer;
845 }
846 }
847
848 static void
849 FcParseInt (FcConfigParse *parse)
850 {
851 FcChar8 *s, *end;
852 int l;
853
854 if (!parse->pstack)
855 return;
856 s = FcStrBufDone (&parse->pstack->str);
857 if (!s)
858 {
859 FcConfigMessage (parse, FcSevereError, "out of memory");
860 return;
861 }
862 end = 0;
863 l = (int) strtol ((char *) s, (char **)&end, 0);
864 if (end != s + strlen ((char *) s))
865 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
866 else
867 FcVStackPushInteger (parse, l);
868 FcStrFree (s);
869 }
870
871 static void
872 FcParseDouble (FcConfigParse *parse)
873 {
874 FcChar8 *s, *end;
875 double d;
876
877 if (!parse->pstack)
878 return;
879 s = FcStrBufDone (&parse->pstack->str);
880 if (!s)
881 {
882 FcConfigMessage (parse, FcSevereError, "out of memory");
883 return;
884 }
885 end = 0;
886 d = strtod ((char *) s, (char **)&end);
887 if (end != s + strlen ((char *) s))
888 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
889 else
890 FcVStackPushDouble (parse, d);
891 FcStrFree (s);
892 }
893
894 static void
895 FcParseString (FcConfigParse *parse, FcVStackTag tag)
896 {
897 FcChar8 *s;
898
899 if (!parse->pstack)
900 return;
901 s = FcStrBufDone (&parse->pstack->str);
902 if (!s)
903 {
904 FcConfigMessage (parse, FcSevereError, "out of memory");
905 return;
906 }
907 if (!FcVStackPushString (parse, tag, s))
908 FcStrFree (s);
909 }
910
911 static void
912 FcParseMatrix (FcConfigParse *parse)
913 {
914 FcVStack *vstack;
915 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
916 FcMatrix m;
917
918 while ((vstack = FcVStackPop (parse)))
919 {
920 double v;
921 switch (vstack->tag) {
922 case FcVStackInteger:
923 v = vstack->u.integer;
924 break;
925 case FcVStackDouble:
926 v = vstack->u._double;
927 break;
928 default:
929 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
930 v = 1.0;
931 break;
932 }
933 switch (matrix_state) {
934 case m_xx: m.xx = v; break;
935 case m_xy: m.xy = v; break;
936 case m_yx: m.yx = v; break;
937 case m_yy: m.yy = v; break;
938 default: break;
939 }
940 matrix_state--;
941 }
942 if (matrix_state != m_done)
943 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
944 else
945 FcVStackPushMatrix (parse, &m);
946 }
947
948 static FcBool
949 FcConfigLexBool (const FcChar8 *bool)
950 {
951 if (*bool == 't' || *bool == 'T')
952 return FcTrue;
953 if (*bool == 'y' || *bool == 'Y')
954 return FcTrue;
955 if (*bool == '1')
956 return FcTrue;
957 return FcFalse;
958 }
959
960 static void
961 FcParseBool (FcConfigParse *parse)
962 {
963 FcChar8 *s;
964
965 if (!parse->pstack)
966 return;
967 s = FcStrBufDone (&parse->pstack->str);
968 if (!s)
969 {
970 FcConfigMessage (parse, FcSevereError, "out of memory");
971 return;
972 }
973 FcVStackPushBool (parse, FcConfigLexBool (s));
974 FcStrFree (s);
975 }
976
977 static void
978 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
979 {
980 FcVStack *vstack;
981 FcExpr *left, *expr = 0, *new;
982
983 while ((vstack = FcVStackPop (parse)))
984 {
985 if (vstack->tag != FcVStackFamily)
986 {
987 FcConfigMessage (parse, FcSevereWarning, "non-family");
988 FcVStackDestroy (vstack);
989 continue;
990 }
991 left = vstack->u.expr;
992 vstack->tag = FcVStackNone;
993 FcVStackDestroy (vstack);
994 if (expr)
995 {
996 new = FcExprCreateOp (left, FcOpComma, expr);
997 if (!new)
998 {
999 FcConfigMessage (parse, FcSevereError, "out of memory");
1000 FcExprDestroy (left);
1001 FcExprDestroy (expr);
1002 break;
1003 }
1004 expr = new;
1005 }
1006 else
1007 expr = left;
1008 }
1009 if (expr)
1010 {
1011 if (!FcVStackPushExpr (parse, tag, expr))
1012 {
1013 FcConfigMessage (parse, FcSevereError, "out of memory");
1014 if (expr)
1015 FcExprDestroy (expr);
1016 }
1017 }
1018 }
1019
1020 static void
1021 FcParseFamily (FcConfigParse *parse)
1022 {
1023 FcChar8 *s;
1024 FcExpr *expr;
1025
1026 if (!parse->pstack)
1027 return;
1028 s = FcStrBufDone (&parse->pstack->str);
1029 if (!s)
1030 {
1031 FcConfigMessage (parse, FcSevereError, "out of memory");
1032 return;
1033 }
1034 expr = FcExprCreateString (s);
1035 FcStrFree (s);
1036 if (expr)
1037 FcVStackPushExpr (parse, FcVStackFamily, expr);
1038 }
1039
1040 static void
1041 FcParseAlias (FcConfigParse *parse)
1042 {
1043 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1044 FcEdit *edit = 0, *next;
1045 FcVStack *vstack;
1046 FcTest *test;
1047
1048 while ((vstack = FcVStackPop (parse)))
1049 {
1050 switch (vstack->tag) {
1051 case FcVStackFamily:
1052 if (family)
1053 {
1054 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1055 if (!new)
1056 FcConfigMessage (parse, FcSevereError, "out of memory");
1057 else
1058 family = new;
1059 }
1060 else
1061 new = vstack->u.expr;
1062 if (new)
1063 {
1064 family = new;
1065 vstack->tag = FcVStackNone;
1066 }
1067 break;
1068 case FcVStackPrefer:
1069 if (prefer)
1070 FcExprDestroy (prefer);
1071 prefer = vstack->u.expr;
1072 vstack->tag = FcVStackNone;
1073 break;
1074 case FcVStackAccept:
1075 if (accept)
1076 FcExprDestroy (accept);
1077 accept = vstack->u.expr;
1078 vstack->tag = FcVStackNone;
1079 break;
1080 case FcVStackDefault:
1081 if (def)
1082 FcExprDestroy (def);
1083 def = vstack->u.expr;
1084 vstack->tag = FcVStackNone;
1085 break;
1086 default:
1087 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1088 break;
1089 }
1090 FcVStackDestroy (vstack);
1091 }
1092 if (!family)
1093 {
1094 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1095 if (prefer)
1096 FcExprDestroy (prefer);
1097 if (accept)
1098 FcExprDestroy (accept);
1099 if (def)
1100 FcExprDestroy (def);
1101 return;
1102 }
1103 if (prefer)
1104 {
1105 edit = FcEditCreate (FcConfigSaveField ("family"),
1106 FcOpPrepend,
1107 prefer);
1108 if (edit)
1109 edit->next = 0;
1110 else
1111 FcExprDestroy (prefer);
1112 }
1113 if (accept)
1114 {
1115 next = edit;
1116 edit = FcEditCreate (FcConfigSaveField ("family"),
1117 FcOpAppend,
1118 accept);
1119 if (edit)
1120 edit->next = next;
1121 else
1122 FcExprDestroy (accept);
1123 }
1124 if (def)
1125 {
1126 next = edit;
1127 edit = FcEditCreate (FcConfigSaveField ("family"),
1128 FcOpAppendLast,
1129 def);
1130 if (edit)
1131 edit->next = next;
1132 else
1133 FcExprDestroy (def);
1134 }
1135 if (edit)
1136 {
1137 test = FcTestCreate (FcQualAny,
1138 FcStrCopy ((FcChar8 *) "family"),
1139 FcOpEqual,
1140 family);
1141 if (test)
1142 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1143 FcTestDestroy (test);
1144 }
1145 else
1146 FcExprDestroy (family);
1147 }
1148
1149 static FcExpr *
1150 FcPopExpr (FcConfigParse *parse)
1151 {
1152 FcVStack *vstack = FcVStackPop (parse);
1153 FcExpr *expr = 0;
1154 if (!vstack)
1155 return 0;
1156 switch (vstack->tag) {
1157 case FcVStackNone:
1158 break;
1159 case FcVStackString:
1160 case FcVStackFamily:
1161 expr = FcExprCreateString (vstack->u.string);
1162 break;
1163 case FcVStackField:
1164 expr = FcExprCreateField ((char *) vstack->u.string);
1165 break;
1166 case FcVStackConstant:
1167 expr = FcExprCreateConst (vstack->u.string);
1168 break;
1169 case FcVStackPrefer:
1170 case FcVStackAccept:
1171 case FcVStackDefault:
1172 expr = vstack->u.expr;
1173 vstack->tag = FcVStackNone;
1174 break;
1175 case FcVStackInteger:
1176 expr = FcExprCreateInteger (vstack->u.integer);
1177 break;
1178 case FcVStackDouble:
1179 expr = FcExprCreateDouble (vstack->u._double);
1180 break;
1181 case FcVStackMatrix:
1182 expr = FcExprCreateMatrix (vstack->u.matrix);
1183 break;
1184 case FcVStackBool:
1185 expr = FcExprCreateBool (vstack->u.bool);
1186 break;
1187 case FcVStackTest:
1188 break;
1189 case FcVStackExpr:
1190 expr = vstack->u.expr;
1191 break;
1192 case FcVStackEdit:
1193 break;
1194 }
1195 FcVStackDestroy (vstack);
1196 return expr;
1197 }
1198
1199 static FcExpr *
1200 FcPopExprs (FcConfigParse *parse, FcOp op)
1201 {
1202 FcExpr *left, *expr = 0, *new;
1203
1204 while ((left = FcPopExpr (parse)))
1205 {
1206 if (expr)
1207 {
1208 new = FcExprCreateOp (left, op, expr);
1209 if (!new)
1210 {
1211 FcConfigMessage (parse, FcSevereError, "out of memory");
1212 FcExprDestroy (left);
1213 FcExprDestroy (expr);
1214 break;
1215 }
1216 expr = new;
1217 }
1218 else
1219 expr = left;
1220 }
1221 return expr;
1222 }
1223
1224 static void
1225 FcParseExpr (FcConfigParse *parse, FcOp op)
1226 {
1227 FcExpr *expr = FcPopExprs (parse, op);
1228 if (expr)
1229 FcVStackPushExpr (parse, FcVStackExpr, expr);
1230 }
1231
1232 static void
1233 FcParseInclude (FcConfigParse *parse)
1234 {
1235 FcChar8 *s;
1236 const FcChar8 *i;
1237 FcBool ignore_missing = FcFalse;
1238
1239 s = FcStrBufDone (&parse->pstack->str);
1240 if (!s)
1241 {
1242 FcConfigMessage (parse, FcSevereError, "out of memory");
1243 return;
1244 }
1245 i = FcConfigGetAttribute (parse, "ignore_missing");
1246 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1247 ignore_missing = FcTrue;
1248 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1249 parse->error = FcTrue;
1250 free (s);
1251 }
1252
1253 typedef struct _FcOpMap {
1254 char *name;
1255 FcOp op;
1256 } FcOpMap;
1257
1258 static FcOp
1259 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1260 {
1261 int i;
1262
1263 for (i = 0; i < nmap; i++)
1264 if (!strcmp ((char *) op, map[i].name))
1265 return map[i].op;
1266 return FcOpInvalid;
1267 }
1268
1269 static const FcOpMap fcCompareOps[] = {
1270 { "eq", FcOpEqual },
1271 { "not_eq", FcOpNotEqual },
1272 { "less", FcOpLess },
1273 { "less_eq", FcOpLessEqual },
1274 { "more", FcOpMore },
1275 { "more_eq", FcOpMoreEqual }
1276 };
1277
1278 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1279
1280 static FcOp
1281 FcConfigLexCompare (const FcChar8 *compare)
1282 {
1283 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1284 }
1285
1286
1287 static void
1288 FcParseTest (FcConfigParse *parse)
1289 {
1290 const FcChar8 *qual_string;
1291 FcQual qual;
1292 const FcChar8 *name;
1293 const FcChar8 *compare_string;
1294 FcOp compare;
1295 FcExpr *expr;
1296 FcTest *test;
1297
1298 qual_string = FcConfigGetAttribute (parse, "qual");
1299 if (!qual_string)
1300 qual = FcQualAny;
1301 else
1302 {
1303 if (!strcmp ((char *) qual_string, "any"))
1304 qual = FcQualAny;
1305 else if (!strcmp ((char *) qual_string, "all"))
1306 qual = FcQualAll;
1307 else
1308 {
1309 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1310 qual = FcQualAny;
1311 }
1312 }
1313 name = FcConfigGetAttribute (parse, "name");
1314 if (!name)
1315 {
1316 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1317 name = (FcChar8 *) FC_FAMILY;
1318 }
1319 compare_string = FcConfigGetAttribute (parse, "compare");
1320 if (!compare_string)
1321 compare = FcOpEqual;
1322 else
1323 {
1324 compare = FcConfigLexCompare (compare_string);
1325 if (compare == FcOpInvalid)
1326 {
1327 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1328 compare = FcOpEqual;
1329 }
1330 }
1331 expr = FcPopExprs (parse, FcOpComma);
1332 if (!expr)
1333 {
1334 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1335 return;
1336 }
1337 test = FcTestCreate (qual, name, compare, expr);
1338 if (!test)
1339 {
1340 FcConfigMessage (parse, FcSevereError, "out of memory");
1341 return;
1342 }
1343 FcVStackPushTest (parse, test);
1344 }
1345
1346 static const FcOpMap fcModeOps[] = {
1347 { "assign", FcOpAssign },
1348 { "assign_replace", FcOpAssignReplace },
1349 { "prepend", FcOpPrepend },
1350 { "prepend_first", FcOpPrependFirst },
1351 { "append", FcOpAppend },
1352 { "append_last", FcOpAppendLast },
1353 };
1354
1355 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1356
1357 static FcOp
1358 FcConfigLexMode (const FcChar8 *mode)
1359 {
1360 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1361 }
1362
1363 static void
1364 FcParseEdit (FcConfigParse *parse)
1365 {
1366 const FcChar8 *name;
1367 const FcChar8 *mode_string;
1368 FcOp mode;
1369 FcExpr *expr;
1370 FcEdit *edit;
1371
1372 name = FcConfigGetAttribute (parse, "name");
1373 if (!name)
1374 {
1375 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1376 name = (FcChar8 *) FC_FAMILY;
1377 }
1378 mode_string = FcConfigGetAttribute (parse, "mode");
1379 if (!mode_string)
1380 mode = FcOpEqual;
1381 else
1382 {
1383 mode = FcConfigLexMode (mode_string);
1384 if (mode == FcOpInvalid)
1385 {
1386 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1387 mode = FcOpAssign;
1388 }
1389 }
1390 expr = FcPopExprs (parse, FcOpComma);
1391 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr);
1392 if (!edit)
1393 {
1394 FcConfigMessage (parse, FcSevereError, "out of memory");
1395 FcExprDestroy (expr);
1396 return;
1397 }
1398 if (!FcVStackPushEdit (parse, edit))
1399 FcEditDestroy (edit);
1400 }
1401
1402 static void
1403 FcParseMatch (FcConfigParse *parse)
1404 {
1405 const FcChar8 *kind_name;
1406 FcMatchKind kind;
1407 FcTest *test = 0;
1408 FcEdit *edit = 0;
1409 FcVStack *vstack;
1410
1411 kind_name = FcConfigGetAttribute (parse, "target");
1412 if (!kind_name)
1413 kind = FcMatchPattern;
1414 else
1415 {
1416 if (!strcmp ((char *) kind_name, "pattern"))
1417 kind = FcMatchPattern;
1418 else if (!strcmp ((char *) kind_name, "font"))
1419 kind = FcMatchFont;
1420 else
1421 {
1422 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1423 kind = FcMatchPattern;
1424 }
1425 }
1426 while ((vstack = FcVStackPop (parse)))
1427 {
1428 switch (vstack->tag) {
1429 case FcVStackTest:
1430 vstack->u.test->next = test;
1431 test = vstack->u.test;
1432 vstack->tag = FcVStackNone;
1433 break;
1434 case FcVStackEdit:
1435 vstack->u.edit->next = edit;
1436 edit = vstack->u.edit;
1437 vstack->tag = FcVStackNone;
1438 break;
1439 default:
1440 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1441 break;
1442 }
1443 FcVStackDestroy (vstack);
1444 }
1445 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1446 FcConfigMessage (parse, FcSevereError, "out of memory");
1447 }
1448
1449 static void
1450 FcEndElement(void *userData, const XML_Char *name)
1451 {
1452 FcConfigParse *parse = userData;
1453 FcChar8 *data;
1454
1455 if (!parse->pstack)
1456 return;
1457 switch (parse->pstack->element) {
1458 case FcElementNone:
1459 break;
1460 case FcElementFontconfig:
1461 break;
1462 case FcElementDir:
1463 data = FcStrBufDone (&parse->pstack->str);
1464 if (!data)
1465 {
1466 FcConfigMessage (parse, FcSevereError, "out of memory");
1467 break;
1468 }
1469 if (!FcConfigAddDir (parse->config, data))
1470 FcConfigMessage (parse, FcSevereError, "out of memory");
1471 free (data);
1472 break;
1473 case FcElementCache:
1474 data = FcStrBufDone (&parse->pstack->str);
1475 if (!data)
1476 {
1477 FcConfigMessage (parse, FcSevereError, "out of memory");
1478 break;
1479 }
1480 if (!FcConfigSetCache (parse->config, data))
1481 FcConfigMessage (parse, FcSevereError, "out of memory");
1482 free (data);
1483 break;
1484 case FcElementInclude:
1485 FcParseInclude (parse);
1486 break;
1487 case FcElementConfig:
1488 break;
1489 case FcElementMatch:
1490 FcParseMatch (parse);
1491 break;
1492 case FcElementAlias:
1493 FcParseAlias (parse);
1494 break;
1495
1496 case FcElementBlank:
1497 FcParseBlank (parse);
1498 break;
1499 case FcElementRescan:
1500 FcParseRescan (parse);
1501 break;
1502
1503 case FcElementPrefer:
1504 FcParseFamilies (parse, FcVStackPrefer);
1505 break;
1506 case FcElementAccept:
1507 FcParseFamilies (parse, FcVStackAccept);
1508 break;
1509 case FcElementDefault:
1510 FcParseFamilies (parse, FcVStackDefault);
1511 break;
1512 case FcElementFamily:
1513 FcParseFamily (parse);
1514 break;
1515
1516 case FcElementTest:
1517 FcParseTest (parse);
1518 break;
1519 case FcElementEdit:
1520 FcParseEdit (parse);
1521 break;
1522
1523 case FcElementInt:
1524 FcParseInt (parse);
1525 break;
1526 case FcElementDouble:
1527 FcParseDouble (parse);
1528 break;
1529 case FcElementString:
1530 FcParseString (parse, FcVStackString);
1531 break;
1532 case FcElementMatrix:
1533 FcParseMatrix (parse);
1534 break;
1535 case FcElementBool:
1536 FcParseBool (parse);
1537 break;
1538 case FcElementCharset:
1539 /* FcParseCharset (parse); */
1540 break;
1541
1542 case FcElementName:
1543 FcParseString (parse, FcVStackField);
1544 break;
1545 case FcElementConst:
1546 FcParseString (parse, FcVStackConstant);
1547 break;
1548 case FcElementOr:
1549 FcParseExpr (parse, FcOpOr);
1550 break;
1551 case FcElementAnd:
1552 FcParseExpr (parse, FcOpAnd);
1553 break;
1554 case FcElementEq:
1555 FcParseExpr (parse, FcOpEqual);
1556 break;
1557 case FcElementNotEq:
1558 FcParseExpr (parse, FcOpNotEqual);
1559 break;
1560 case FcElementLess:
1561 FcParseExpr (parse, FcOpLess);
1562 break;
1563 case FcElementLessEq:
1564 FcParseExpr (parse, FcOpLessEqual);
1565 break;
1566 case FcElementMore:
1567 FcParseExpr (parse, FcOpMore);
1568 break;
1569 case FcElementMoreEq:
1570 FcParseExpr (parse, FcOpMoreEqual);
1571 break;
1572 case FcElementPlus:
1573 FcParseExpr (parse, FcOpPlus);
1574 break;
1575 case FcElementMinus:
1576 FcParseExpr (parse, FcOpMinus);
1577 break;
1578 case FcElementTimes:
1579 FcParseExpr (parse, FcOpTimes);
1580 break;
1581 case FcElementDivide:
1582 FcParseExpr (parse, FcOpDivide);
1583 break;
1584 case FcElementNot:
1585 FcParseExpr (parse, FcOpNot);
1586 break;
1587 case FcElementIf:
1588 FcParseExpr (parse, FcOpQuest);
1589 break;
1590 case FcElementUnknown:
1591 break;
1592 }
1593 (void) FcPStackPop (parse);
1594 }
1595
1596 static void
1597 FcCharacterData (void *userData, const XML_Char *s, int len)
1598 {
1599 FcConfigParse *parse = userData;
1600
1601 if (!parse->pstack)
1602 return;
1603 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1604 FcConfigMessage (parse, FcSevereError, "out of memory");
1605 }
1606
1607 static void
1608 FcStartDoctypeDecl (void *userData,
1609 const XML_Char *doctypeName,
1610 const XML_Char *sysid,
1611 const XML_Char *pubid,
1612 int has_internal_subset)
1613 {
1614 FcConfigParse *parse = userData;
1615
1616 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1617 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1618 }
1619
1620 static void
1621 FcEndDoctypeDecl (void *userData)
1622 {
1623 }
1624
1625 FcBool
1626 FcConfigParseAndLoad (FcConfig *config,
1627 const FcChar8 *name,
1628 FcBool complain)
1629 {
1630
1631 XML_Parser p;
1632 FcChar8 *filename;
1633 FILE *f;
1634 int len;
1635 void *buf;
1636 FcConfigParse parse;
1637 FcBool error = FcTrue;
1638
1639 filename = FcConfigFilename (name);
1640 if (!filename)
1641 goto bail0;
1642 f = fopen ((char *) filename, "r");
1643 free (filename);
1644 if (!f)
1645 goto bail0;
1646
1647 p = XML_ParserCreate ("UTF-8");
1648 if (!p)
1649 goto bail1;
1650
1651 if (!FcConfigInit (&parse, name, config, p))
1652 goto bail2;
1653
1654 XML_SetUserData (p, &parse);
1655
1656 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1657 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1658 XML_SetCharacterDataHandler (p, FcCharacterData);
1659
1660 do {
1661 buf = XML_GetBuffer (p, BUFSIZ);
1662 if (!buf)
1663 {
1664 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1665 goto bail3;
1666 }
1667 len = fread (buf, 1, BUFSIZ, f);
1668 if (len < 0)
1669 {
1670 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1671 goto bail3;
1672 }
1673 if (!XML_ParseBuffer (p, len, len == 0))
1674 {
1675 FcConfigMessage (&parse, FcSevereError, "%s",
1676 XML_ErrorString (XML_GetErrorCode (p)));
1677 goto bail3;
1678 }
1679 } while (len != 0);
1680 error = parse.error;
1681 bail3:
1682 FcConfigCleanup (&parse);
1683 bail2:
1684 XML_ParserFree (p);
1685 bail1:
1686 fclose (f);
1687 bail0:
1688 if (error && complain)
1689 {
1690 if (name)
1691 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1692 else
1693 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1694 return FcFalse;
1695 }
1696 return FcTrue;
1697 }