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