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