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