]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
src/fccache.c (FcGlobalCacheLoad, FcGlobalCacheSave, FcDirCacheConsume,
[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, pattern);
1972 }
1973
1974 static void
1975 FcParsePattern (FcConfigParse *parse)
1976 {
1977 FcVStack *vstack;
1978 FcPattern *pattern = FcPatternCreate ();
1979
1980 if (!pattern)
1981 {
1982 FcConfigMessage (parse, FcSevereError, "out of memory");
1983 return;
1984 }
1985
1986 while ((vstack = FcVStackPop (parse)))
1987 {
1988 switch (vstack->tag) {
1989 case FcVStackPattern:
1990 if (!FcPatternAppend (pattern, vstack->u.pattern))
1991 {
1992 FcConfigMessage (parse, FcSevereError, "out of memory");
1993 return;
1994 }
1995 break;
1996 default:
1997 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1998 break;
1999 }
2000 FcVStackDestroy (vstack);
2001 }
2002
2003 FcVStackPushPattern (parse, pattern);
2004 }
2005
2006 static void
2007 FcEndElement(void *userData, const XML_Char *name)
2008 {
2009 FcConfigParse *parse = userData;
2010 FcChar8 *data;
2011
2012 if (!parse->pstack)
2013 return;
2014 switch (parse->pstack->element) {
2015 case FcElementNone:
2016 break;
2017 case FcElementFontconfig:
2018 break;
2019 case FcElementDir:
2020 data = FcStrBufDone (&parse->pstack->str);
2021 if (!data)
2022 {
2023 FcConfigMessage (parse, FcSevereError, "out of memory");
2024 break;
2025 }
2026 #ifdef _WIN32
2027 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2028 {
2029 int rc;
2030 FcStrFree (data);
2031 data = malloc (1000);
2032 if (!data)
2033 {
2034 FcConfigMessage (parse, FcSevereError, "out of memory");
2035 break;
2036 }
2037 FcMemAlloc (FC_MEM_STRING, 1000);
2038 rc = GetWindowsDirectory (data, 800);
2039 if (rc == 0 || rc > 800)
2040 {
2041 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2042 FcStrFree (data);
2043 break;
2044 }
2045 if (data [strlen (data) - 1] != '\\')
2046 strcat (data, "\\");
2047 strcat (data, "fonts");
2048 }
2049 #endif
2050 if (!FcStrUsesHome (data) || FcConfigHome ())
2051 {
2052 if (!FcConfigAddDir (parse->config, data))
2053 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2054 }
2055 FcStrFree (data);
2056 break;
2057 case FcElementCache:
2058 data = FcStrBufDone (&parse->pstack->str);
2059 if (!data)
2060 {
2061 FcConfigMessage (parse, FcSevereError, "out of memory");
2062 break;
2063 }
2064 if (!FcStrUsesHome (data) || FcConfigHome ())
2065 {
2066 if (!FcConfigSetCache (parse->config, data))
2067 FcConfigMessage (parse, FcSevereError, "out of memory");
2068 }
2069 FcStrFree (data);
2070 break;
2071 case FcElementInclude:
2072 FcParseInclude (parse);
2073 break;
2074 case FcElementConfig:
2075 break;
2076 case FcElementMatch:
2077 FcParseMatch (parse);
2078 break;
2079 case FcElementAlias:
2080 FcParseAlias (parse);
2081 break;
2082
2083 case FcElementBlank:
2084 FcParseBlank (parse);
2085 break;
2086 case FcElementRescan:
2087 FcParseRescan (parse);
2088 break;
2089
2090 case FcElementPrefer:
2091 FcParseFamilies (parse, FcVStackPrefer);
2092 break;
2093 case FcElementAccept:
2094 FcParseFamilies (parse, FcVStackAccept);
2095 break;
2096 case FcElementDefault:
2097 FcParseFamilies (parse, FcVStackDefault);
2098 break;
2099 case FcElementFamily:
2100 FcParseFamily (parse);
2101 break;
2102
2103 case FcElementTest:
2104 FcParseTest (parse);
2105 break;
2106 case FcElementEdit:
2107 FcParseEdit (parse);
2108 break;
2109
2110 case FcElementInt:
2111 FcParseInt (parse);
2112 break;
2113 case FcElementDouble:
2114 FcParseDouble (parse);
2115 break;
2116 case FcElementString:
2117 FcParseString (parse, FcVStackString);
2118 break;
2119 case FcElementMatrix:
2120 FcParseMatrix (parse);
2121 break;
2122 case FcElementBool:
2123 FcParseBool (parse);
2124 break;
2125 case FcElementCharset:
2126 /* FcParseCharset (parse); */
2127 break;
2128 case FcElementSelectfont:
2129 break;
2130 case FcElementAcceptfont:
2131 case FcElementRejectfont:
2132 FcParseAcceptRejectFont (parse, parse->pstack->element);
2133 break;
2134 case FcElementGlob:
2135 FcParseString (parse, FcVStackGlob);
2136 break;
2137 case FcElementPattern:
2138 FcParsePattern (parse);
2139 break;
2140 case FcElementPatelt:
2141 FcParsePatelt (parse);
2142 break;
2143 case FcElementName:
2144 FcParseString (parse, FcVStackField);
2145 break;
2146 case FcElementConst:
2147 FcParseString (parse, FcVStackConstant);
2148 break;
2149 case FcElementOr:
2150 FcParseBinary (parse, FcOpOr);
2151 break;
2152 case FcElementAnd:
2153 FcParseBinary (parse, FcOpAnd);
2154 break;
2155 case FcElementEq:
2156 FcParseBinary (parse, FcOpEqual);
2157 break;
2158 case FcElementNotEq:
2159 FcParseBinary (parse, FcOpNotEqual);
2160 break;
2161 case FcElementLess:
2162 FcParseBinary (parse, FcOpLess);
2163 break;
2164 case FcElementLessEq:
2165 FcParseBinary (parse, FcOpLessEqual);
2166 break;
2167 case FcElementMore:
2168 FcParseBinary (parse, FcOpMore);
2169 break;
2170 case FcElementMoreEq:
2171 FcParseBinary (parse, FcOpMoreEqual);
2172 break;
2173 case FcElementContains:
2174 FcParseBinary (parse, FcOpContains);
2175 break;
2176 case FcElementNotContains:
2177 FcParseBinary (parse, FcOpNotContains);
2178 break;
2179 case FcElementPlus:
2180 FcParseBinary (parse, FcOpPlus);
2181 break;
2182 case FcElementMinus:
2183 FcParseBinary (parse, FcOpMinus);
2184 break;
2185 case FcElementTimes:
2186 FcParseBinary (parse, FcOpTimes);
2187 break;
2188 case FcElementDivide:
2189 FcParseBinary (parse, FcOpDivide);
2190 break;
2191 case FcElementNot:
2192 FcParseUnary (parse, FcOpNot);
2193 break;
2194 case FcElementIf:
2195 FcParseBinary (parse, FcOpQuest);
2196 break;
2197 case FcElementFloor:
2198 FcParseUnary (parse, FcOpFloor);
2199 break;
2200 case FcElementCeil:
2201 FcParseUnary (parse, FcOpCeil);
2202 break;
2203 case FcElementRound:
2204 FcParseUnary (parse, FcOpRound);
2205 break;
2206 case FcElementTrunc:
2207 FcParseUnary (parse, FcOpTrunc);
2208 break;
2209 case FcElementUnknown:
2210 break;
2211 }
2212 (void) FcPStackPop (parse);
2213 }
2214
2215 static void
2216 FcCharacterData (void *userData, const XML_Char *s, int len)
2217 {
2218 FcConfigParse *parse = userData;
2219
2220 if (!parse->pstack)
2221 return;
2222 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2223 FcConfigMessage (parse, FcSevereError, "out of memory");
2224 }
2225
2226 static void
2227 FcStartDoctypeDecl (void *userData,
2228 const XML_Char *doctypeName,
2229 const XML_Char *sysid,
2230 const XML_Char *pubid,
2231 int has_internal_subset)
2232 {
2233 FcConfigParse *parse = userData;
2234
2235 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2236 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2237 }
2238
2239 #if ENABLE_LIBXML2
2240
2241 static void
2242 FcInternalSubsetDecl (void *userData,
2243 const XML_Char *doctypeName,
2244 const XML_Char *sysid,
2245 const XML_Char *pubid)
2246 {
2247 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2248 }
2249
2250 static void
2251 FcExternalSubsetDecl (void *userData,
2252 const XML_Char *doctypeName,
2253 const XML_Char *sysid,
2254 const XML_Char *pubid)
2255 {
2256 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2257 }
2258
2259 #else /* ENABLE_LIBXML2 */
2260
2261 static void
2262 FcEndDoctypeDecl (void *userData)
2263 {
2264 }
2265
2266 #endif /* ENABLE_LIBXML2 */
2267
2268 static FcBool
2269 FcConfigParseAndLoadDir (FcConfig *config,
2270 const FcChar8 *name,
2271 const FcChar8 *dir,
2272 FcBool complain)
2273 {
2274 DIR *d;
2275 struct dirent *e;
2276 FcBool ret = FcTrue;
2277 FcChar8 *file;
2278 FcChar8 *base;
2279 FcStrSet *files;
2280
2281 d = opendir ((char *) dir);
2282 if (!d)
2283 {
2284 if (complain)
2285 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2286 name);
2287 ret = FcFalse;
2288 goto bail0;
2289 }
2290 /* freed below */
2291 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2292 if (!file)
2293 {
2294 ret = FcFalse;
2295 goto bail1;
2296 }
2297
2298 strcpy ((char *) file, (char *) dir);
2299 strcat ((char *) file, "/");
2300 base = file + strlen ((char *) file);
2301
2302 files = FcStrSetCreate ();
2303 if (!files)
2304 {
2305 ret = FcFalse;
2306 goto bail2;
2307 }
2308
2309 if (FcDebug () & FC_DBG_CONFIG)
2310 printf ("\tScanning config dir %s\n", dir);
2311
2312 while (ret && (e = readdir (d)))
2313 {
2314 int d_len;
2315 #define TAIL ".conf"
2316 #define TAIL_LEN 5
2317 /*
2318 * Add all files of the form [0-9]*.conf
2319 */
2320 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2321 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2322 d_len > TAIL_LEN &&
2323 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2324 {
2325 strcpy ((char *) base, (char *) e->d_name);
2326 if (!FcStrSetAdd (files, file))
2327 {
2328 ret = FcFalse;
2329 goto bail3;
2330 }
2331 }
2332 }
2333 if (ret)
2334 {
2335 int i;
2336 qsort (files->strs, files->num, sizeof (FcChar8 *),
2337 (int (*)(const void *, const void *)) FcStrCmp);
2338 for (i = 0; ret && i < files->num; i++)
2339 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2340 }
2341 bail3:
2342 FcStrSetDestroy (files);
2343 bail2:
2344 free (file);
2345 bail1:
2346 closedir (d);
2347 bail0:
2348 return ret || !complain;
2349 }
2350
2351 FcBool
2352 FcConfigParseAndLoad (FcConfig *config,
2353 const FcChar8 *name,
2354 FcBool complain)
2355 {
2356
2357 XML_Parser p;
2358 FcChar8 *filename;
2359 int fd;
2360 int len;
2361 FcConfigParse parse;
2362 FcBool error = FcTrue;
2363
2364 #if ENABLE_LIBXML2
2365 xmlSAXHandler sax;
2366 char buf[BUFSIZ];
2367 #else
2368 void *buf;
2369 #endif
2370
2371 filename = FcConfigFilename (name);
2372 if (!filename)
2373 goto bail0;
2374
2375 if (FcStrSetMember (config->configFiles, filename))
2376 {
2377 FcStrFree (filename);
2378 return FcTrue;
2379 }
2380
2381 if (!FcStrSetAdd (config->configFiles, filename))
2382 {
2383 FcStrFree (filename);
2384 goto bail0;
2385 }
2386
2387 if (FcFileIsDir (filename))
2388 {
2389 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2390 FcStrFree (filename);
2391 return ret;
2392 }
2393
2394 if (FcDebug () & FC_DBG_CONFIG)
2395 printf ("\tLoading config file %s\n", filename);
2396
2397 fd = open ((char *) filename, O_RDONLY);
2398 if (fd == -1) {
2399 FcStrFree (filename);
2400 goto bail0;
2401 }
2402
2403 #if ENABLE_LIBXML2
2404 memset(&sax, 0, sizeof(sax));
2405
2406 sax.internalSubset = FcInternalSubsetDecl;
2407 sax.externalSubset = FcExternalSubsetDecl;
2408 sax.startElement = FcStartElement;
2409 sax.endElement = FcEndElement;
2410 sax.characters = FcCharacterData;
2411
2412 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2413 #else
2414 p = XML_ParserCreate ("UTF-8");
2415 #endif
2416 FcStrFree (filename);
2417
2418 if (!p)
2419 goto bail1;
2420
2421 if (!FcConfigInit (&parse, name, config, p))
2422 goto bail2;
2423
2424 #if !ENABLE_LIBXML2
2425
2426 XML_SetUserData (p, &parse);
2427
2428 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2429 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2430 XML_SetCharacterDataHandler (p, FcCharacterData);
2431
2432 #endif /* ENABLE_LIBXML2 */
2433
2434 do {
2435 #if !ENABLE_LIBXML2
2436 buf = XML_GetBuffer (p, BUFSIZ);
2437 if (!buf)
2438 {
2439 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2440 goto bail3;
2441 }
2442 #endif
2443 len = read (fd, buf, BUFSIZ);
2444 if (len < 0)
2445 {
2446 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2447 goto bail3;
2448 }
2449
2450 #if ENABLE_LIBXML2
2451 if (xmlParseChunk (p, buf, len, len == 0))
2452 #else
2453 if (!XML_ParseBuffer (p, len, len == 0))
2454 #endif
2455 {
2456 FcConfigMessage (&parse, FcSevereError, "%s",
2457 XML_ErrorString (XML_GetErrorCode (p)));
2458 goto bail3;
2459 }
2460 } while (len != 0);
2461 error = parse.error;
2462 bail3:
2463 FcConfigCleanup (&parse);
2464 bail2:
2465 XML_ParserFree (p);
2466 bail1:
2467 close (fd);
2468 fd = -1;
2469 bail0:
2470 if (error && complain)
2471 {
2472 if (name)
2473 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2474 else
2475 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2476 return FcFalse;
2477 }
2478 return FcTrue;
2479 }