]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Expression parsing in fonts.conf file mis-freed elements. Constant identity
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.8 2002/05/22 04:12:35 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 vstack->tag = FcVStackNone;
1192 break;
1193 case FcVStackEdit:
1194 break;
1195 }
1196 FcVStackDestroy (vstack);
1197 return expr;
1198 }
1199
1200 static FcExpr *
1201 FcPopExprs (FcConfigParse *parse, FcOp op)
1202 {
1203 FcExpr *left, *expr = 0, *new;
1204
1205 while ((left = FcPopExpr (parse)))
1206 {
1207 if (expr)
1208 {
1209 new = FcExprCreateOp (left, op, expr);
1210 if (!new)
1211 {
1212 FcConfigMessage (parse, FcSevereError, "out of memory");
1213 FcExprDestroy (left);
1214 FcExprDestroy (expr);
1215 break;
1216 }
1217 expr = new;
1218 }
1219 else
1220 expr = left;
1221 }
1222 return expr;
1223 }
1224
1225 static void
1226 FcParseExpr (FcConfigParse *parse, FcOp op)
1227 {
1228 FcExpr *expr = FcPopExprs (parse, op);
1229 if (expr)
1230 FcVStackPushExpr (parse, FcVStackExpr, expr);
1231 }
1232
1233 static void
1234 FcParseInclude (FcConfigParse *parse)
1235 {
1236 FcChar8 *s;
1237 const FcChar8 *i;
1238 FcBool ignore_missing = FcFalse;
1239
1240 s = FcStrBufDone (&parse->pstack->str);
1241 if (!s)
1242 {
1243 FcConfigMessage (parse, FcSevereError, "out of memory");
1244 return;
1245 }
1246 i = FcConfigGetAttribute (parse, "ignore_missing");
1247 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1248 ignore_missing = FcTrue;
1249 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1250 parse->error = FcTrue;
1251 free (s);
1252 }
1253
1254 typedef struct _FcOpMap {
1255 char *name;
1256 FcOp op;
1257 } FcOpMap;
1258
1259 static FcOp
1260 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1261 {
1262 int i;
1263
1264 for (i = 0; i < nmap; i++)
1265 if (!strcmp ((char *) op, map[i].name))
1266 return map[i].op;
1267 return FcOpInvalid;
1268 }
1269
1270 static const FcOpMap fcCompareOps[] = {
1271 { "eq", FcOpEqual },
1272 { "not_eq", FcOpNotEqual },
1273 { "less", FcOpLess },
1274 { "less_eq", FcOpLessEqual },
1275 { "more", FcOpMore },
1276 { "more_eq", FcOpMoreEqual }
1277 };
1278
1279 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1280
1281 static FcOp
1282 FcConfigLexCompare (const FcChar8 *compare)
1283 {
1284 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1285 }
1286
1287
1288 static void
1289 FcParseTest (FcConfigParse *parse)
1290 {
1291 const FcChar8 *qual_string;
1292 FcQual qual;
1293 const FcChar8 *name;
1294 const FcChar8 *compare_string;
1295 FcOp compare;
1296 FcExpr *expr;
1297 FcTest *test;
1298
1299 qual_string = FcConfigGetAttribute (parse, "qual");
1300 if (!qual_string)
1301 qual = FcQualAny;
1302 else
1303 {
1304 if (!strcmp ((char *) qual_string, "any"))
1305 qual = FcQualAny;
1306 else if (!strcmp ((char *) qual_string, "all"))
1307 qual = FcQualAll;
1308 else
1309 {
1310 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1311 qual = FcQualAny;
1312 }
1313 }
1314 name = FcConfigGetAttribute (parse, "name");
1315 if (!name)
1316 {
1317 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1318 name = (FcChar8 *) FC_FAMILY;
1319 }
1320 compare_string = FcConfigGetAttribute (parse, "compare");
1321 if (!compare_string)
1322 compare = FcOpEqual;
1323 else
1324 {
1325 compare = FcConfigLexCompare (compare_string);
1326 if (compare == FcOpInvalid)
1327 {
1328 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1329 compare = FcOpEqual;
1330 }
1331 }
1332 expr = FcPopExprs (parse, FcOpComma);
1333 if (!expr)
1334 {
1335 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1336 return;
1337 }
1338 test = FcTestCreate (qual, name, compare, expr);
1339 if (!test)
1340 {
1341 FcConfigMessage (parse, FcSevereError, "out of memory");
1342 return;
1343 }
1344 FcVStackPushTest (parse, test);
1345 }
1346
1347 static const FcOpMap fcModeOps[] = {
1348 { "assign", FcOpAssign },
1349 { "assign_replace", FcOpAssignReplace },
1350 { "prepend", FcOpPrepend },
1351 { "prepend_first", FcOpPrependFirst },
1352 { "append", FcOpAppend },
1353 { "append_last", FcOpAppendLast },
1354 };
1355
1356 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1357
1358 static FcOp
1359 FcConfigLexMode (const FcChar8 *mode)
1360 {
1361 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1362 }
1363
1364 static void
1365 FcParseEdit (FcConfigParse *parse)
1366 {
1367 const FcChar8 *name;
1368 const FcChar8 *mode_string;
1369 FcOp mode;
1370 FcExpr *expr;
1371 FcEdit *edit;
1372
1373 name = FcConfigGetAttribute (parse, "name");
1374 if (!name)
1375 {
1376 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1377 name = (FcChar8 *) FC_FAMILY;
1378 }
1379 mode_string = FcConfigGetAttribute (parse, "mode");
1380 if (!mode_string)
1381 mode = FcOpAssign;
1382 else
1383 {
1384 mode = FcConfigLexMode (mode_string);
1385 if (mode == FcOpInvalid)
1386 {
1387 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1388 mode = FcOpAssign;
1389 }
1390 }
1391 expr = FcPopExprs (parse, FcOpComma);
1392 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr);
1393 if (!edit)
1394 {
1395 FcConfigMessage (parse, FcSevereError, "out of memory");
1396 FcExprDestroy (expr);
1397 return;
1398 }
1399 if (!FcVStackPushEdit (parse, edit))
1400 FcEditDestroy (edit);
1401 }
1402
1403 static void
1404 FcParseMatch (FcConfigParse *parse)
1405 {
1406 const FcChar8 *kind_name;
1407 FcMatchKind kind;
1408 FcTest *test = 0;
1409 FcEdit *edit = 0;
1410 FcVStack *vstack;
1411
1412 kind_name = FcConfigGetAttribute (parse, "target");
1413 if (!kind_name)
1414 kind = FcMatchPattern;
1415 else
1416 {
1417 if (!strcmp ((char *) kind_name, "pattern"))
1418 kind = FcMatchPattern;
1419 else if (!strcmp ((char *) kind_name, "font"))
1420 kind = FcMatchFont;
1421 else
1422 {
1423 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1424 kind = FcMatchPattern;
1425 }
1426 }
1427 while ((vstack = FcVStackPop (parse)))
1428 {
1429 switch (vstack->tag) {
1430 case FcVStackTest:
1431 vstack->u.test->next = test;
1432 test = vstack->u.test;
1433 vstack->tag = FcVStackNone;
1434 break;
1435 case FcVStackEdit:
1436 vstack->u.edit->next = edit;
1437 edit = vstack->u.edit;
1438 vstack->tag = FcVStackNone;
1439 break;
1440 default:
1441 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1442 break;
1443 }
1444 FcVStackDestroy (vstack);
1445 }
1446 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1447 FcConfigMessage (parse, FcSevereError, "out of memory");
1448 }
1449
1450 static void
1451 FcEndElement(void *userData, const XML_Char *name)
1452 {
1453 FcConfigParse *parse = userData;
1454 FcChar8 *data;
1455
1456 if (!parse->pstack)
1457 return;
1458 switch (parse->pstack->element) {
1459 case FcElementNone:
1460 break;
1461 case FcElementFontconfig:
1462 break;
1463 case FcElementDir:
1464 data = FcStrBufDone (&parse->pstack->str);
1465 if (!data)
1466 {
1467 FcConfigMessage (parse, FcSevereError, "out of memory");
1468 break;
1469 }
1470 if (!FcConfigAddDir (parse->config, data))
1471 FcConfigMessage (parse, FcSevereError, "out of memory");
1472 free (data);
1473 break;
1474 case FcElementCache:
1475 data = FcStrBufDone (&parse->pstack->str);
1476 if (!data)
1477 {
1478 FcConfigMessage (parse, FcSevereError, "out of memory");
1479 break;
1480 }
1481 if (!FcConfigSetCache (parse->config, data))
1482 FcConfigMessage (parse, FcSevereError, "out of memory");
1483 free (data);
1484 break;
1485 case FcElementInclude:
1486 FcParseInclude (parse);
1487 break;
1488 case FcElementConfig:
1489 break;
1490 case FcElementMatch:
1491 FcParseMatch (parse);
1492 break;
1493 case FcElementAlias:
1494 FcParseAlias (parse);
1495 break;
1496
1497 case FcElementBlank:
1498 FcParseBlank (parse);
1499 break;
1500 case FcElementRescan:
1501 FcParseRescan (parse);
1502 break;
1503
1504 case FcElementPrefer:
1505 FcParseFamilies (parse, FcVStackPrefer);
1506 break;
1507 case FcElementAccept:
1508 FcParseFamilies (parse, FcVStackAccept);
1509 break;
1510 case FcElementDefault:
1511 FcParseFamilies (parse, FcVStackDefault);
1512 break;
1513 case FcElementFamily:
1514 FcParseFamily (parse);
1515 break;
1516
1517 case FcElementTest:
1518 FcParseTest (parse);
1519 break;
1520 case FcElementEdit:
1521 FcParseEdit (parse);
1522 break;
1523
1524 case FcElementInt:
1525 FcParseInt (parse);
1526 break;
1527 case FcElementDouble:
1528 FcParseDouble (parse);
1529 break;
1530 case FcElementString:
1531 FcParseString (parse, FcVStackString);
1532 break;
1533 case FcElementMatrix:
1534 FcParseMatrix (parse);
1535 break;
1536 case FcElementBool:
1537 FcParseBool (parse);
1538 break;
1539 case FcElementCharset:
1540 /* FcParseCharset (parse); */
1541 break;
1542
1543 case FcElementName:
1544 FcParseString (parse, FcVStackField);
1545 break;
1546 case FcElementConst:
1547 FcParseString (parse, FcVStackConstant);
1548 break;
1549 case FcElementOr:
1550 FcParseExpr (parse, FcOpOr);
1551 break;
1552 case FcElementAnd:
1553 FcParseExpr (parse, FcOpAnd);
1554 break;
1555 case FcElementEq:
1556 FcParseExpr (parse, FcOpEqual);
1557 break;
1558 case FcElementNotEq:
1559 FcParseExpr (parse, FcOpNotEqual);
1560 break;
1561 case FcElementLess:
1562 FcParseExpr (parse, FcOpLess);
1563 break;
1564 case FcElementLessEq:
1565 FcParseExpr (parse, FcOpLessEqual);
1566 break;
1567 case FcElementMore:
1568 FcParseExpr (parse, FcOpMore);
1569 break;
1570 case FcElementMoreEq:
1571 FcParseExpr (parse, FcOpMoreEqual);
1572 break;
1573 case FcElementPlus:
1574 FcParseExpr (parse, FcOpPlus);
1575 break;
1576 case FcElementMinus:
1577 FcParseExpr (parse, FcOpMinus);
1578 break;
1579 case FcElementTimes:
1580 FcParseExpr (parse, FcOpTimes);
1581 break;
1582 case FcElementDivide:
1583 FcParseExpr (parse, FcOpDivide);
1584 break;
1585 case FcElementNot:
1586 FcParseExpr (parse, FcOpNot);
1587 break;
1588 case FcElementIf:
1589 FcParseExpr (parse, FcOpQuest);
1590 break;
1591 case FcElementUnknown:
1592 break;
1593 }
1594 (void) FcPStackPop (parse);
1595 }
1596
1597 static void
1598 FcCharacterData (void *userData, const XML_Char *s, int len)
1599 {
1600 FcConfigParse *parse = userData;
1601
1602 if (!parse->pstack)
1603 return;
1604 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1605 FcConfigMessage (parse, FcSevereError, "out of memory");
1606 }
1607
1608 static void
1609 FcStartDoctypeDecl (void *userData,
1610 const XML_Char *doctypeName,
1611 const XML_Char *sysid,
1612 const XML_Char *pubid,
1613 int has_internal_subset)
1614 {
1615 FcConfigParse *parse = userData;
1616
1617 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1618 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1619 }
1620
1621 static void
1622 FcEndDoctypeDecl (void *userData)
1623 {
1624 }
1625
1626 FcBool
1627 FcConfigParseAndLoad (FcConfig *config,
1628 const FcChar8 *name,
1629 FcBool complain)
1630 {
1631
1632 XML_Parser p;
1633 FcChar8 *filename;
1634 FILE *f;
1635 int len;
1636 void *buf;
1637 FcConfigParse parse;
1638 FcBool error = FcTrue;
1639
1640 filename = FcConfigFilename (name);
1641 if (!filename)
1642 goto bail0;
1643 f = fopen ((char *) filename, "r");
1644 free (filename);
1645 if (!f)
1646 goto bail0;
1647
1648 p = XML_ParserCreate ("UTF-8");
1649 if (!p)
1650 goto bail1;
1651
1652 if (!FcConfigInit (&parse, name, config, p))
1653 goto bail2;
1654
1655 XML_SetUserData (p, &parse);
1656
1657 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1658 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1659 XML_SetCharacterDataHandler (p, FcCharacterData);
1660
1661 do {
1662 buf = XML_GetBuffer (p, BUFSIZ);
1663 if (!buf)
1664 {
1665 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1666 goto bail3;
1667 }
1668 len = fread (buf, 1, BUFSIZ, f);
1669 if (len < 0)
1670 {
1671 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1672 goto bail3;
1673 }
1674 if (!XML_ParseBuffer (p, len, len == 0))
1675 {
1676 FcConfigMessage (&parse, FcSevereError, "%s",
1677 XML_ErrorString (XML_GetErrorCode (p)));
1678 goto bail3;
1679 }
1680 } while (len != 0);
1681 error = parse.error;
1682 bail3:
1683 FcConfigCleanup (&parse);
1684 bail2:
1685 XML_ParserFree (p);
1686 bail1:
1687 fclose (f);
1688 bail0:
1689 if (error && complain)
1690 {
1691 if (name)
1692 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1693 else
1694 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1695 return FcFalse;
1696 }
1697 return FcTrue;
1698 }