]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Reduce amount of dirty rss by const'ing some data structures.
[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 #ifdef 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 const 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 slen;
928 int i;
929 FcChar8 **new;
930 FcChar8 *s;
931
932 if (!attr)
933 return 0;
934 slen = 0;
935 for (i = 0; attr[i]; i++)
936 slen += strlen ((char *) attr[i]) + 1;
937 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
938 if (!new)
939 return 0;
940 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
941 s = (FcChar8 *) (new + (i + 1));
942 for (i = 0; attr[i]; i++)
943 {
944 new[i] = s;
945 strcpy ((char *) s, (char *) attr[i]);
946 s += strlen ((char *) s) + 1;
947 }
948 new[i] = 0;
949 return new;
950 }
951
952 static FcBool
953 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
954 {
955 FcPStack *new = malloc (sizeof (FcPStack));
956
957 if (!new)
958 return FcFalse;
959 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
960 new->prev = parse->pstack;
961 new->element = element;
962 if (attr)
963 {
964 new->attr = FcConfigSaveAttr (attr);
965 if (!new->attr)
966 FcConfigMessage (parse, FcSevereError, "out of memory");
967 }
968 else
969 new->attr = 0;
970 FcStrBufInit (&new->str, 0, 0);
971 parse->pstack = new;
972 return FcTrue;
973 }
974
975 static FcBool
976 FcPStackPop (FcConfigParse *parse)
977 {
978 FcPStack *old;
979
980 if (!parse->pstack)
981 {
982 FcConfigMessage (parse, FcSevereError, "mismatching element");
983 return FcFalse;
984 }
985 FcVStackClear (parse);
986 old = parse->pstack;
987 parse->pstack = old->prev;
988 FcStrBufDestroy (&old->str);
989 if (old->attr)
990 {
991 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
992 free (old->attr);
993 }
994 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
995 free (old);
996 return FcTrue;
997 }
998
999 static FcBool
1000 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1001 {
1002 parse->pstack = 0;
1003 parse->vstack = 0;
1004 parse->error = FcFalse;
1005 parse->name = name;
1006 parse->config = config;
1007 parse->parser = parser;
1008 return FcTrue;
1009 }
1010
1011 static void
1012 FcConfigCleanup (FcConfigParse *parse)
1013 {
1014 while (parse->pstack)
1015 FcPStackPop (parse);
1016 }
1017
1018 static const FcChar8 *
1019 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1020 {
1021 FcChar8 **attrs;
1022 if (!parse->pstack)
1023 return 0;
1024
1025 attrs = parse->pstack->attr;
1026 if (!attrs)
1027 return 0;
1028
1029 while (*attrs)
1030 {
1031 if (!strcmp ((char *) *attrs, attr))
1032 return attrs[1];
1033 attrs += 2;
1034 }
1035 return 0;
1036 }
1037
1038 static void
1039 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1040 {
1041 FcConfigParse *parse = userData;
1042 FcElement element;
1043
1044 element = FcElementMap (name);
1045 if (element == FcElementUnknown)
1046 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1047
1048 if (!FcPStackPush (parse, element, attr))
1049 {
1050 FcConfigMessage (parse, FcSevereError, "out of memory");
1051 return;
1052 }
1053 return;
1054 }
1055
1056 static void
1057 FcParseBlank (FcConfigParse *parse)
1058 {
1059 int n = FcVStackElements (parse);
1060 while (n-- > 0)
1061 {
1062 FcVStack *v = FcVStackFetch (parse, n);
1063 if (v->tag != FcVStackInteger)
1064 FcConfigMessage (parse, FcSevereError, "non-integer blank");
1065 else
1066 {
1067 if (!parse->config->blanks)
1068 {
1069 parse->config->blanks = FcBlanksCreate ();
1070 if (!parse->config->blanks)
1071 {
1072 FcConfigMessage (parse, FcSevereError, "out of memory");
1073 break;
1074 }
1075 }
1076 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1077 {
1078 FcConfigMessage (parse, FcSevereError, "out of memory");
1079 break;
1080 }
1081 }
1082 }
1083 }
1084
1085 static void
1086 FcParseRescan (FcConfigParse *parse)
1087 {
1088 int n = FcVStackElements (parse);
1089 while (n-- > 0)
1090 {
1091 FcVStack *v = FcVStackFetch (parse, n);
1092 if (v->tag != FcVStackInteger)
1093 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1094 else
1095 parse->config->rescanInterval = v->u.integer;
1096 }
1097 }
1098
1099 static void
1100 FcParseInt (FcConfigParse *parse)
1101 {
1102 FcChar8 *s, *end;
1103 int l;
1104
1105 if (!parse->pstack)
1106 return;
1107 s = FcStrBufDone (&parse->pstack->str);
1108 if (!s)
1109 {
1110 FcConfigMessage (parse, FcSevereError, "out of memory");
1111 return;
1112 }
1113 end = 0;
1114 l = (int) strtol ((char *) s, (char **)&end, 0);
1115 if (end != s + strlen ((char *) s))
1116 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1117 else
1118 FcVStackPushInteger (parse, l);
1119 FcStrFree (s);
1120 }
1121
1122 /*
1123 * idea copied from glib g_ascii_strtod with
1124 * permission of the author (Alexander Larsson)
1125 */
1126
1127 #include <locale.h>
1128
1129 static double
1130 FcStrtod (char *s, char **end)
1131 {
1132 struct lconv *locale_data;
1133 char *dot;
1134 double v;
1135
1136 /*
1137 * Have to swap the decimal point to match the current locale
1138 * if that locale doesn't use 0x2e
1139 */
1140 if ((dot = strchr (s, 0x2e)) &&
1141 (locale_data = localeconv ()) &&
1142 (locale_data->decimal_point[0] != 0x2e ||
1143 locale_data->decimal_point[1] != 0))
1144 {
1145 char buf[128];
1146 int slen = strlen (s);
1147 int dlen = strlen (locale_data->decimal_point);
1148
1149 if (slen + dlen > (int) sizeof (buf))
1150 {
1151 if (end)
1152 *end = s;
1153 v = 0;
1154 }
1155 else
1156 {
1157 char *buf_end;
1158 /* mantissa */
1159 strncpy (buf, s, dot - s);
1160 /* decimal point */
1161 strcpy (buf + (dot - s), locale_data->decimal_point);
1162 /* rest of number */
1163 strcpy (buf + (dot - s) + dlen, dot + 1);
1164 buf_end = 0;
1165 v = strtod (buf, &buf_end);
1166 if (buf_end) {
1167 buf_end = s + (buf_end - buf);
1168 if (buf_end > dot)
1169 buf_end -= dlen - 1;
1170 }
1171 if (end)
1172 *end = buf_end;
1173 }
1174 }
1175 else
1176 v = strtod (s, end);
1177 return v;
1178 }
1179
1180 static void
1181 FcParseDouble (FcConfigParse *parse)
1182 {
1183 FcChar8 *s, *end;
1184 double d;
1185
1186 if (!parse->pstack)
1187 return;
1188 s = FcStrBufDone (&parse->pstack->str);
1189 if (!s)
1190 {
1191 FcConfigMessage (parse, FcSevereError, "out of memory");
1192 return;
1193 }
1194 end = 0;
1195 d = FcStrtod ((char *) s, (char **)&end);
1196 if (end != s + strlen ((char *) s))
1197 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1198 else
1199 FcVStackPushDouble (parse, d);
1200 FcStrFree (s);
1201 }
1202
1203 static void
1204 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1205 {
1206 FcChar8 *s;
1207
1208 if (!parse->pstack)
1209 return;
1210 s = FcStrBufDone (&parse->pstack->str);
1211 if (!s)
1212 {
1213 FcConfigMessage (parse, FcSevereError, "out of memory");
1214 return;
1215 }
1216 if (!FcVStackPushString (parse, tag, s))
1217 FcStrFree (s);
1218 }
1219
1220 static void
1221 FcParseMatrix (FcConfigParse *parse)
1222 {
1223 FcVStack *vstack;
1224 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1225 FcMatrix m;
1226
1227 while ((vstack = FcVStackPop (parse)))
1228 {
1229 double v;
1230 switch (vstack->tag) {
1231 case FcVStackInteger:
1232 v = vstack->u.integer;
1233 break;
1234 case FcVStackDouble:
1235 v = vstack->u._double;
1236 break;
1237 default:
1238 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1239 v = 1.0;
1240 break;
1241 }
1242 switch (matrix_state) {
1243 case m_xx: m.xx = v; break;
1244 case m_xy: m.xy = v; break;
1245 case m_yx: m.yx = v; break;
1246 case m_yy: m.yy = v; break;
1247 default: break;
1248 }
1249 FcVStackDestroy (vstack);
1250 matrix_state--;
1251 }
1252 if (matrix_state != m_done)
1253 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1254 else
1255 FcVStackPushMatrix (parse, &m);
1256 }
1257
1258 static FcBool
1259 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1260 {
1261 FcBool result = FcFalse;
1262
1263 if (!FcNameBool (bool, &result))
1264 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1265 bool);
1266 return result;
1267 }
1268
1269 static void
1270 FcParseBool (FcConfigParse *parse)
1271 {
1272 FcChar8 *s;
1273
1274 if (!parse->pstack)
1275 return;
1276 s = FcStrBufDone (&parse->pstack->str);
1277 if (!s)
1278 {
1279 FcConfigMessage (parse, FcSevereError, "out of memory");
1280 return;
1281 }
1282 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1283 FcStrFree (s);
1284 }
1285
1286 static void
1287 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1288 {
1289 FcVStack *vstack;
1290 FcExpr *left, *expr = 0, *new;
1291
1292 while ((vstack = FcVStackPop (parse)))
1293 {
1294 if (vstack->tag != FcVStackFamily)
1295 {
1296 FcConfigMessage (parse, FcSevereWarning, "non-family");
1297 FcVStackDestroy (vstack);
1298 continue;
1299 }
1300 left = vstack->u.expr;
1301 vstack->tag = FcVStackNone;
1302 FcVStackDestroy (vstack);
1303 if (expr)
1304 {
1305 new = FcExprCreateOp (left, FcOpComma, expr);
1306 if (!new)
1307 {
1308 FcConfigMessage (parse, FcSevereError, "out of memory");
1309 FcExprDestroy (left);
1310 FcExprDestroy (expr);
1311 break;
1312 }
1313 expr = new;
1314 }
1315 else
1316 expr = left;
1317 }
1318 if (expr)
1319 {
1320 if (!FcVStackPushExpr (parse, tag, expr))
1321 {
1322 FcConfigMessage (parse, FcSevereError, "out of memory");
1323 FcExprDestroy (expr);
1324 }
1325 }
1326 }
1327
1328 static void
1329 FcParseFamily (FcConfigParse *parse)
1330 {
1331 FcChar8 *s;
1332 FcExpr *expr;
1333
1334 if (!parse->pstack)
1335 return;
1336 s = FcStrBufDone (&parse->pstack->str);
1337 if (!s)
1338 {
1339 FcConfigMessage (parse, FcSevereError, "out of memory");
1340 return;
1341 }
1342 expr = FcExprCreateString (s);
1343 FcStrFree (s);
1344 if (expr)
1345 FcVStackPushExpr (parse, FcVStackFamily, expr);
1346 }
1347
1348 static void
1349 FcParseAlias (FcConfigParse *parse)
1350 {
1351 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1352 FcEdit *edit = 0, *next;
1353 FcVStack *vstack;
1354 FcTest *test;
1355
1356 while ((vstack = FcVStackPop (parse)))
1357 {
1358 switch (vstack->tag) {
1359 case FcVStackFamily:
1360 if (family)
1361 {
1362 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1363 if (!new)
1364 FcConfigMessage (parse, FcSevereError, "out of memory");
1365 else
1366 family = new;
1367 }
1368 else
1369 new = vstack->u.expr;
1370 if (new)
1371 {
1372 family = new;
1373 vstack->tag = FcVStackNone;
1374 }
1375 break;
1376 case FcVStackPrefer:
1377 if (prefer)
1378 FcExprDestroy (prefer);
1379 prefer = vstack->u.expr;
1380 vstack->tag = FcVStackNone;
1381 break;
1382 case FcVStackAccept:
1383 if (accept)
1384 FcExprDestroy (accept);
1385 accept = vstack->u.expr;
1386 vstack->tag = FcVStackNone;
1387 break;
1388 case FcVStackDefault:
1389 if (def)
1390 FcExprDestroy (def);
1391 def = vstack->u.expr;
1392 vstack->tag = FcVStackNone;
1393 break;
1394 default:
1395 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1396 break;
1397 }
1398 FcVStackDestroy (vstack);
1399 }
1400 if (!family)
1401 {
1402 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1403 if (prefer)
1404 FcExprDestroy (prefer);
1405 if (accept)
1406 FcExprDestroy (accept);
1407 if (def)
1408 FcExprDestroy (def);
1409 return;
1410 }
1411 if (prefer)
1412 {
1413 edit = FcEditCreate (parse,
1414 FcConfigSaveField ("family"),
1415 FcOpPrepend,
1416 prefer,
1417 FcValueBindingWeak);
1418 if (edit)
1419 edit->next = 0;
1420 else
1421 FcExprDestroy (prefer);
1422 }
1423 if (accept)
1424 {
1425 next = edit;
1426 edit = FcEditCreate (parse,
1427 FcConfigSaveField ("family"),
1428 FcOpAppend,
1429 accept,
1430 FcValueBindingWeak);
1431 if (edit)
1432 edit->next = next;
1433 else
1434 FcExprDestroy (accept);
1435 }
1436 if (def)
1437 {
1438 next = edit;
1439 edit = FcEditCreate (parse,
1440 FcConfigSaveField ("family"),
1441 FcOpAppendLast,
1442 def,
1443 FcValueBindingWeak);
1444 if (edit)
1445 edit->next = next;
1446 else
1447 FcExprDestroy (def);
1448 }
1449 if (edit)
1450 {
1451 test = FcTestCreate (parse, FcMatchPattern,
1452 FcQualAny,
1453 (FcChar8 *) FC_FAMILY,
1454 FcOpEqual,
1455 family);
1456 if (test)
1457 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1458 FcTestDestroy (test);
1459 }
1460 else
1461 FcExprDestroy (family);
1462 }
1463
1464 static FcExpr *
1465 FcPopExpr (FcConfigParse *parse)
1466 {
1467 FcVStack *vstack = FcVStackPop (parse);
1468 FcExpr *expr = 0;
1469 if (!vstack)
1470 return 0;
1471 switch (vstack->tag) {
1472 case FcVStackNone:
1473 break;
1474 case FcVStackString:
1475 case FcVStackFamily:
1476 expr = FcExprCreateString (vstack->u.string);
1477 break;
1478 case FcVStackField:
1479 expr = FcExprCreateField ((char *) vstack->u.string);
1480 break;
1481 case FcVStackConstant:
1482 expr = FcExprCreateConst (vstack->u.string);
1483 break;
1484 case FcVStackGlob:
1485 /* XXX: What's the correct action here? (CDW) */
1486 break;
1487 case FcVStackPrefer:
1488 case FcVStackAccept:
1489 case FcVStackDefault:
1490 expr = vstack->u.expr;
1491 vstack->tag = FcVStackNone;
1492 break;
1493 case FcVStackInteger:
1494 expr = FcExprCreateInteger (vstack->u.integer);
1495 break;
1496 case FcVStackDouble:
1497 expr = FcExprCreateDouble (vstack->u._double);
1498 break;
1499 case FcVStackMatrix:
1500 expr = FcExprCreateMatrix (vstack->u.matrix);
1501 break;
1502 case FcVStackBool:
1503 expr = FcExprCreateBool (vstack->u.bool);
1504 break;
1505 case FcVStackTest:
1506 break;
1507 case FcVStackExpr:
1508 expr = vstack->u.expr;
1509 vstack->tag = FcVStackNone;
1510 break;
1511 case FcVStackEdit:
1512 break;
1513 default:
1514 break;
1515 }
1516 FcVStackDestroy (vstack);
1517 return expr;
1518 }
1519
1520 /*
1521 * This builds a tree of binary operations. Note
1522 * that every operator is defined so that if only
1523 * a single operand is contained, the value of the
1524 * whole expression is the value of the operand.
1525 *
1526 * This code reduces in that case to returning that
1527 * operand.
1528 */
1529 static FcExpr *
1530 FcPopBinary (FcConfigParse *parse, FcOp op)
1531 {
1532 FcExpr *left, *expr = 0, *new;
1533
1534 while ((left = FcPopExpr (parse)))
1535 {
1536 if (expr)
1537 {
1538 new = FcExprCreateOp (left, op, expr);
1539 if (!new)
1540 {
1541 FcConfigMessage (parse, FcSevereError, "out of memory");
1542 FcExprDestroy (left);
1543 FcExprDestroy (expr);
1544 break;
1545 }
1546 expr = new;
1547 }
1548 else
1549 expr = left;
1550 }
1551 return expr;
1552 }
1553
1554 static void
1555 FcParseBinary (FcConfigParse *parse, FcOp op)
1556 {
1557 FcExpr *expr = FcPopBinary (parse, op);
1558 if (expr)
1559 FcVStackPushExpr (parse, FcVStackExpr, expr);
1560 }
1561
1562 /*
1563 * This builds a a unary operator, it consumes only
1564 * a single operand
1565 */
1566
1567 static FcExpr *
1568 FcPopUnary (FcConfigParse *parse, FcOp op)
1569 {
1570 FcExpr *operand, *new = 0;
1571
1572 if ((operand = FcPopExpr (parse)))
1573 {
1574 new = FcExprCreateOp (operand, op, 0);
1575 if (!new)
1576 {
1577 FcExprDestroy (operand);
1578 FcConfigMessage (parse, FcSevereError, "out of memory");
1579 }
1580 }
1581 return new;
1582 }
1583
1584 static void
1585 FcParseUnary (FcConfigParse *parse, FcOp op)
1586 {
1587 FcExpr *expr = FcPopUnary (parse, op);
1588 if (expr)
1589 FcVStackPushExpr (parse, FcVStackExpr, expr);
1590 }
1591
1592 static void
1593 FcParseInclude (FcConfigParse *parse)
1594 {
1595 FcChar8 *s;
1596 const FcChar8 *i;
1597 FcBool ignore_missing = FcFalse;
1598
1599 s = FcStrBufDone (&parse->pstack->str);
1600 if (!s)
1601 {
1602 FcConfigMessage (parse, FcSevereError, "out of memory");
1603 return;
1604 }
1605 i = FcConfigGetAttribute (parse, "ignore_missing");
1606 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1607 ignore_missing = FcTrue;
1608 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1609 parse->error = FcTrue;
1610 FcStrFree (s);
1611 }
1612
1613 typedef struct _FcOpMap {
1614 char name[16];
1615 FcOp op;
1616 } FcOpMap;
1617
1618 static FcOp
1619 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1620 {
1621 int i;
1622
1623 for (i = 0; i < nmap; i++)
1624 if (!strcmp ((char *) op, map[i].name))
1625 return map[i].op;
1626 return FcOpInvalid;
1627 }
1628
1629 static const FcOpMap fcCompareOps[] = {
1630 { "eq", FcOpEqual },
1631 { "not_eq", FcOpNotEqual },
1632 { "less", FcOpLess },
1633 { "less_eq", FcOpLessEqual },
1634 { "more", FcOpMore },
1635 { "more_eq", FcOpMoreEqual },
1636 { "contains", FcOpContains },
1637 { "not_contains", FcOpNotContains }
1638 };
1639
1640 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1641
1642 static FcOp
1643 FcConfigLexCompare (const FcChar8 *compare)
1644 {
1645 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1646 }
1647
1648
1649 static void
1650 FcParseTest (FcConfigParse *parse)
1651 {
1652 const FcChar8 *kind_string;
1653 FcMatchKind kind;
1654 const FcChar8 *qual_string;
1655 FcQual qual;
1656 const FcChar8 *name;
1657 const FcChar8 *compare_string;
1658 FcOp compare;
1659 FcExpr *expr;
1660 FcTest *test;
1661
1662 kind_string = FcConfigGetAttribute (parse, "target");
1663 if (!kind_string)
1664 kind = FcMatchDefault;
1665 else
1666 {
1667 if (!strcmp ((char *) kind_string, "pattern"))
1668 kind = FcMatchPattern;
1669 else if (!strcmp ((char *) kind_string, "font"))
1670 kind = FcMatchFont;
1671 else if (!strcmp ((char *) kind_string, "default"))
1672 kind = FcMatchDefault;
1673 else
1674 {
1675 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1676 return;
1677 }
1678 }
1679 qual_string = FcConfigGetAttribute (parse, "qual");
1680 if (!qual_string)
1681 qual = FcQualAny;
1682 else
1683 {
1684 if (!strcmp ((char *) qual_string, "any"))
1685 qual = FcQualAny;
1686 else if (!strcmp ((char *) qual_string, "all"))
1687 qual = FcQualAll;
1688 else if (!strcmp ((char *) qual_string, "first"))
1689 qual = FcQualFirst;
1690 else if (!strcmp ((char *) qual_string, "not_first"))
1691 qual = FcQualNotFirst;
1692 else
1693 {
1694 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1695 return;
1696 }
1697 }
1698 name = FcConfigGetAttribute (parse, "name");
1699 if (!name)
1700 {
1701 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1702 return;
1703 }
1704 compare_string = FcConfigGetAttribute (parse, "compare");
1705 if (!compare_string)
1706 compare = FcOpEqual;
1707 else
1708 {
1709 compare = FcConfigLexCompare (compare_string);
1710 if (compare == FcOpInvalid)
1711 {
1712 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1713 return;
1714 }
1715 }
1716 expr = FcPopBinary (parse, FcOpComma);
1717 if (!expr)
1718 {
1719 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1720 return;
1721 }
1722 test = FcTestCreate (parse, kind, qual, name, compare, expr);
1723 if (!test)
1724 {
1725 FcConfigMessage (parse, FcSevereError, "out of memory");
1726 return;
1727 }
1728 FcVStackPushTest (parse, test);
1729 }
1730
1731 static const FcOpMap fcModeOps[] = {
1732 { "assign", FcOpAssign },
1733 { "assign_replace", FcOpAssignReplace },
1734 { "prepend", FcOpPrepend },
1735 { "prepend_first", FcOpPrependFirst },
1736 { "append", FcOpAppend },
1737 { "append_last", FcOpAppendLast },
1738 };
1739
1740 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1741
1742 static FcOp
1743 FcConfigLexMode (const FcChar8 *mode)
1744 {
1745 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1746 }
1747
1748 static void
1749 FcParseEdit (FcConfigParse *parse)
1750 {
1751 const FcChar8 *name;
1752 const FcChar8 *mode_string;
1753 const FcChar8 *binding_string;
1754 FcOp mode;
1755 FcValueBinding binding;
1756 FcExpr *expr;
1757 FcEdit *edit;
1758
1759 name = FcConfigGetAttribute (parse, "name");
1760 if (!name)
1761 {
1762 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1763 return;
1764 }
1765 mode_string = FcConfigGetAttribute (parse, "mode");
1766 if (!mode_string)
1767 mode = FcOpAssign;
1768 else
1769 {
1770 mode = FcConfigLexMode (mode_string);
1771 if (mode == FcOpInvalid)
1772 {
1773 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1774 return;
1775 }
1776 }
1777 binding_string = FcConfigGetAttribute (parse, "binding");
1778 if (!binding_string)
1779 binding = FcValueBindingWeak;
1780 else
1781 {
1782 if (!strcmp ((char *) binding_string, "weak"))
1783 binding = FcValueBindingWeak;
1784 else if (!strcmp ((char *) binding_string, "strong"))
1785 binding = FcValueBindingStrong;
1786 else if (!strcmp ((char *) binding_string, "same"))
1787 binding = FcValueBindingSame;
1788 else
1789 {
1790 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1791 return;
1792 }
1793 }
1794 expr = FcPopBinary (parse, FcOpComma);
1795 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
1796 if (!edit)
1797 {
1798 FcConfigMessage (parse, FcSevereError, "out of memory");
1799 FcExprDestroy (expr);
1800 return;
1801 }
1802 if (!FcVStackPushEdit (parse, edit))
1803 FcEditDestroy (edit);
1804 }
1805
1806 static void
1807 FcParseMatch (FcConfigParse *parse)
1808 {
1809 const FcChar8 *kind_name;
1810 FcMatchKind kind;
1811 FcTest *test = 0;
1812 FcEdit *edit = 0;
1813 FcVStack *vstack;
1814
1815 kind_name = FcConfigGetAttribute (parse, "target");
1816 if (!kind_name)
1817 kind = FcMatchPattern;
1818 else
1819 {
1820 if (!strcmp ((char *) kind_name, "pattern"))
1821 kind = FcMatchPattern;
1822 else if (!strcmp ((char *) kind_name, "font"))
1823 kind = FcMatchFont;
1824 else
1825 {
1826 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1827 return;
1828 }
1829 }
1830 while ((vstack = FcVStackPop (parse)))
1831 {
1832 switch (vstack->tag) {
1833 case FcVStackTest:
1834 vstack->u.test->next = test;
1835 test = vstack->u.test;
1836 vstack->tag = FcVStackNone;
1837 break;
1838 case FcVStackEdit:
1839 vstack->u.edit->next = edit;
1840 edit = vstack->u.edit;
1841 vstack->tag = FcVStackNone;
1842 break;
1843 default:
1844 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1845 break;
1846 }
1847 FcVStackDestroy (vstack);
1848 }
1849 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1850 FcConfigMessage (parse, FcSevereError, "out of memory");
1851 }
1852
1853 static void
1854 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1855 {
1856 FcVStack *vstack;
1857
1858 while ((vstack = FcVStackPop (parse)))
1859 {
1860 switch (vstack->tag) {
1861 case FcVStackGlob:
1862 if (!FcConfigGlobAdd (parse->config,
1863 vstack->u.string,
1864 element == FcElementAcceptfont))
1865 {
1866 FcConfigMessage (parse, FcSevereError, "out of memory");
1867 }
1868 break;
1869 case FcVStackPattern:
1870 if (!FcConfigPatternsAdd (parse->config,
1871 vstack->u.pattern,
1872 element == FcElementAcceptfont))
1873 {
1874 FcConfigMessage (parse, FcSevereError, "out of memory");
1875 }
1876 else
1877 vstack->tag = FcVStackNone;
1878 break;
1879 default:
1880 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1881 break;
1882 }
1883 FcVStackDestroy (vstack);
1884 }
1885 }
1886
1887
1888 static FcValue
1889 FcPopValue (FcConfigParse *parse)
1890 {
1891 FcVStack *vstack = FcVStackPop (parse);
1892 FcValue value;
1893
1894 value.type = FcTypeVoid;
1895
1896 if (!vstack)
1897 return value;
1898
1899 switch (vstack->tag) {
1900 case FcVStackString:
1901 value.u.s = FcStrCopy (vstack->u.string);
1902 if (value.u.s)
1903 value.type = FcTypeString;
1904 break;
1905 case FcVStackConstant:
1906 if (FcNameConstant (vstack->u.string, &value.u.i))
1907 value.type = FcTypeInteger;
1908 break;
1909 case FcVStackInteger:
1910 value.u.i = vstack->u.integer;
1911 value.type = FcTypeInteger;
1912 break;
1913 case FcVStackDouble:
1914 value.u.d = vstack->u._double;
1915 value.type = FcTypeInteger;
1916 break;
1917 case FcVStackMatrix:
1918 value.u.m = FcMatrixCopy (vstack->u.matrix);
1919 if (value.u.m)
1920 value.type = FcTypeMatrix;
1921 break;
1922 case FcVStackBool:
1923 value.u.b = vstack->u.bool;
1924 value.type = FcTypeBool;
1925 break;
1926 default:
1927 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1928 vstack->tag);
1929 break;
1930 }
1931 FcVStackDestroy (vstack);
1932
1933 return value;
1934 }
1935
1936 static void
1937 FcParsePatelt (FcConfigParse *parse)
1938 {
1939 FcValue value;
1940 FcPattern *pattern = FcPatternCreate ();
1941 const char *name;
1942
1943 if (!pattern)
1944 {
1945 FcConfigMessage (parse, FcSevereError, "out of memory");
1946 return;
1947 }
1948
1949 name = (char *) FcConfigGetAttribute (parse, "name");
1950 if (!name)
1951 {
1952 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1953 return;
1954 }
1955
1956 for (;;)
1957 {
1958 value = FcPopValue (parse);
1959 if (value.type == FcTypeVoid)
1960 break;
1961 if (!FcPatternAdd (pattern, name, value, FcTrue))
1962 {
1963 FcConfigMessage (parse, FcSevereError, "out of memory");
1964 break;
1965 }
1966 }
1967
1968 FcVStackPushPattern (parse, FcPatternFreeze(pattern));
1969 FcPatternDestroy (pattern);
1970 }
1971
1972 static void
1973 FcParsePattern (FcConfigParse *parse)
1974 {
1975 FcVStack *vstack;
1976 FcPattern *pattern = FcPatternCreate ();
1977
1978 if (!pattern)
1979 {
1980 FcConfigMessage (parse, FcSevereError, "out of memory");
1981 return;
1982 }
1983
1984 while ((vstack = FcVStackPop (parse)))
1985 {
1986 switch (vstack->tag) {
1987 case FcVStackPattern:
1988 if (!FcPatternAppend (pattern, vstack->u.pattern))
1989 {
1990 FcConfigMessage (parse, FcSevereError, "out of memory");
1991 return;
1992 }
1993 break;
1994 default:
1995 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1996 break;
1997 }
1998 FcVStackDestroy (vstack);
1999 }
2000
2001 FcVStackPushPattern (parse, pattern);
2002 }
2003
2004 static void
2005 FcEndElement(void *userData, const XML_Char *name)
2006 {
2007 FcConfigParse *parse = userData;
2008 FcChar8 *data;
2009
2010 if (!parse->pstack)
2011 return;
2012 switch (parse->pstack->element) {
2013 case FcElementNone:
2014 break;
2015 case FcElementFontconfig:
2016 break;
2017 case FcElementDir:
2018 data = FcStrBufDone (&parse->pstack->str);
2019 if (!data)
2020 {
2021 FcConfigMessage (parse, FcSevereError, "out of memory");
2022 break;
2023 }
2024 #ifdef _WIN32
2025 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2026 {
2027 int rc;
2028 FcStrFree (data);
2029 data = malloc (1000);
2030 if (!data)
2031 {
2032 FcConfigMessage (parse, FcSevereError, "out of memory");
2033 break;
2034 }
2035 FcMemAlloc (FC_MEM_STRING, 1000);
2036 rc = GetWindowsDirectory (data, 800);
2037 if (rc == 0 || rc > 800)
2038 {
2039 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2040 FcStrFree (data);
2041 break;
2042 }
2043 if (data [strlen (data) - 1] != '\\')
2044 strcat (data, "\\");
2045 strcat (data, "fonts");
2046 }
2047 #endif
2048 if (!FcStrUsesHome (data) || FcConfigHome ())
2049 {
2050 if (!FcConfigAddDir (parse->config, data))
2051 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2052 }
2053 FcStrFree (data);
2054 break;
2055 case FcElementCache:
2056 data = FcStrBufDone (&parse->pstack->str);
2057 if (!data)
2058 {
2059 FcConfigMessage (parse, FcSevereError, "out of memory");
2060 break;
2061 }
2062 if (!FcStrUsesHome (data) || FcConfigHome ())
2063 {
2064 if (!FcConfigSetCache (parse->config, data))
2065 FcConfigMessage (parse, FcSevereError, "out of memory");
2066 }
2067 FcStrFree (data);
2068 break;
2069 case FcElementInclude:
2070 FcParseInclude (parse);
2071 break;
2072 case FcElementConfig:
2073 break;
2074 case FcElementMatch:
2075 FcParseMatch (parse);
2076 break;
2077 case FcElementAlias:
2078 FcParseAlias (parse);
2079 break;
2080
2081 case FcElementBlank:
2082 FcParseBlank (parse);
2083 break;
2084 case FcElementRescan:
2085 FcParseRescan (parse);
2086 break;
2087
2088 case FcElementPrefer:
2089 FcParseFamilies (parse, FcVStackPrefer);
2090 break;
2091 case FcElementAccept:
2092 FcParseFamilies (parse, FcVStackAccept);
2093 break;
2094 case FcElementDefault:
2095 FcParseFamilies (parse, FcVStackDefault);
2096 break;
2097 case FcElementFamily:
2098 FcParseFamily (parse);
2099 break;
2100
2101 case FcElementTest:
2102 FcParseTest (parse);
2103 break;
2104 case FcElementEdit:
2105 FcParseEdit (parse);
2106 break;
2107
2108 case FcElementInt:
2109 FcParseInt (parse);
2110 break;
2111 case FcElementDouble:
2112 FcParseDouble (parse);
2113 break;
2114 case FcElementString:
2115 FcParseString (parse, FcVStackString);
2116 break;
2117 case FcElementMatrix:
2118 FcParseMatrix (parse);
2119 break;
2120 case FcElementBool:
2121 FcParseBool (parse);
2122 break;
2123 case FcElementCharset:
2124 /* FcParseCharset (parse); */
2125 break;
2126 case FcElementSelectfont:
2127 break;
2128 case FcElementAcceptfont:
2129 case FcElementRejectfont:
2130 FcParseAcceptRejectFont (parse, parse->pstack->element);
2131 break;
2132 case FcElementGlob:
2133 FcParseString (parse, FcVStackGlob);
2134 break;
2135 case FcElementPattern:
2136 FcParsePattern (parse);
2137 break;
2138 case FcElementPatelt:
2139 FcParsePatelt (parse);
2140 break;
2141 case FcElementName:
2142 FcParseString (parse, FcVStackField);
2143 break;
2144 case FcElementConst:
2145 FcParseString (parse, FcVStackConstant);
2146 break;
2147 case FcElementOr:
2148 FcParseBinary (parse, FcOpOr);
2149 break;
2150 case FcElementAnd:
2151 FcParseBinary (parse, FcOpAnd);
2152 break;
2153 case FcElementEq:
2154 FcParseBinary (parse, FcOpEqual);
2155 break;
2156 case FcElementNotEq:
2157 FcParseBinary (parse, FcOpNotEqual);
2158 break;
2159 case FcElementLess:
2160 FcParseBinary (parse, FcOpLess);
2161 break;
2162 case FcElementLessEq:
2163 FcParseBinary (parse, FcOpLessEqual);
2164 break;
2165 case FcElementMore:
2166 FcParseBinary (parse, FcOpMore);
2167 break;
2168 case FcElementMoreEq:
2169 FcParseBinary (parse, FcOpMoreEqual);
2170 break;
2171 case FcElementContains:
2172 FcParseBinary (parse, FcOpContains);
2173 break;
2174 case FcElementNotContains:
2175 FcParseBinary (parse, FcOpNotContains);
2176 break;
2177 case FcElementPlus:
2178 FcParseBinary (parse, FcOpPlus);
2179 break;
2180 case FcElementMinus:
2181 FcParseBinary (parse, FcOpMinus);
2182 break;
2183 case FcElementTimes:
2184 FcParseBinary (parse, FcOpTimes);
2185 break;
2186 case FcElementDivide:
2187 FcParseBinary (parse, FcOpDivide);
2188 break;
2189 case FcElementNot:
2190 FcParseUnary (parse, FcOpNot);
2191 break;
2192 case FcElementIf:
2193 FcParseBinary (parse, FcOpQuest);
2194 break;
2195 case FcElementFloor:
2196 FcParseUnary (parse, FcOpFloor);
2197 break;
2198 case FcElementCeil:
2199 FcParseUnary (parse, FcOpCeil);
2200 break;
2201 case FcElementRound:
2202 FcParseUnary (parse, FcOpRound);
2203 break;
2204 case FcElementTrunc:
2205 FcParseUnary (parse, FcOpTrunc);
2206 break;
2207 case FcElementUnknown:
2208 break;
2209 }
2210 (void) FcPStackPop (parse);
2211 }
2212
2213 static void
2214 FcCharacterData (void *userData, const XML_Char *s, int len)
2215 {
2216 FcConfigParse *parse = userData;
2217
2218 if (!parse->pstack)
2219 return;
2220 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2221 FcConfigMessage (parse, FcSevereError, "out of memory");
2222 }
2223
2224 static void
2225 FcStartDoctypeDecl (void *userData,
2226 const XML_Char *doctypeName,
2227 const XML_Char *sysid,
2228 const XML_Char *pubid,
2229 int has_internal_subset)
2230 {
2231 FcConfigParse *parse = userData;
2232
2233 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2234 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2235 }
2236
2237 #ifdef ENABLE_LIBXML2
2238
2239 static void
2240 FcInternalSubsetDecl (void *userData,
2241 const XML_Char *doctypeName,
2242 const XML_Char *sysid,
2243 const XML_Char *pubid)
2244 {
2245 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2246 }
2247
2248 static void
2249 FcExternalSubsetDecl (void *userData,
2250 const XML_Char *doctypeName,
2251 const XML_Char *sysid,
2252 const XML_Char *pubid)
2253 {
2254 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2255 }
2256
2257 #else /* ENABLE_LIBXML2 */
2258
2259 static void
2260 FcEndDoctypeDecl (void *userData)
2261 {
2262 }
2263
2264 #endif /* ENABLE_LIBXML2 */
2265
2266 static FcBool
2267 FcConfigParseAndLoadDir (FcConfig *config,
2268 const FcChar8 *name,
2269 const FcChar8 *dir,
2270 FcBool complain)
2271 {
2272 DIR *d;
2273 struct dirent *e;
2274 FcBool ret = FcTrue;
2275 FcChar8 *file;
2276 FcChar8 *base;
2277 FcStrSet *files;
2278
2279 d = opendir ((char *) dir);
2280 if (!d)
2281 {
2282 if (complain)
2283 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2284 name);
2285 ret = FcFalse;
2286 goto bail0;
2287 }
2288 /* freed below */
2289 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2290 if (!file)
2291 {
2292 ret = FcFalse;
2293 goto bail1;
2294 }
2295
2296 strcpy ((char *) file, (char *) dir);
2297 strcat ((char *) file, "/");
2298 base = file + strlen ((char *) file);
2299
2300 files = FcStrSetCreate ();
2301 if (!files)
2302 {
2303 ret = FcFalse;
2304 goto bail2;
2305 }
2306
2307 if (FcDebug () & FC_DBG_CONFIG)
2308 printf ("\tScanning config dir %s\n", dir);
2309
2310 while (ret && (e = readdir (d)))
2311 {
2312 int d_len;
2313 #define TAIL ".conf"
2314 #define TAIL_LEN 5
2315 /*
2316 * Add all files of the form [0-9]*.conf
2317 */
2318 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2319 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2320 d_len > TAIL_LEN &&
2321 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2322 {
2323 strcpy ((char *) base, (char *) e->d_name);
2324 if (!FcStrSetAdd (files, file))
2325 {
2326 ret = FcFalse;
2327 goto bail3;
2328 }
2329 }
2330 }
2331 if (ret)
2332 {
2333 int i;
2334 qsort (files->strs, files->num, sizeof (FcChar8 *),
2335 (int (*)(const void *, const void *)) FcStrCmp);
2336 for (i = 0; ret && i < files->num; i++)
2337 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2338 }
2339 bail3:
2340 FcStrSetDestroy (files);
2341 bail2:
2342 free (file);
2343 bail1:
2344 closedir (d);
2345 bail0:
2346 return ret || !complain;
2347 }
2348
2349 FcBool
2350 FcConfigParseAndLoad (FcConfig *config,
2351 const FcChar8 *name,
2352 FcBool complain)
2353 {
2354
2355 XML_Parser p;
2356 FcChar8 *filename;
2357 int fd;
2358 int len;
2359 FcConfigParse parse;
2360 FcBool error = FcTrue;
2361
2362 #ifdef ENABLE_LIBXML2
2363 xmlSAXHandler sax;
2364 char buf[BUFSIZ];
2365 #else
2366 void *buf;
2367 #endif
2368
2369 filename = FcConfigFilename (name);
2370 if (!filename)
2371 goto bail0;
2372
2373 if (FcStrSetMember (config->configFiles, filename))
2374 {
2375 FcStrFree (filename);
2376 return FcTrue;
2377 }
2378
2379 if (!FcStrSetAdd (config->configFiles, filename))
2380 {
2381 FcStrFree (filename);
2382 goto bail0;
2383 }
2384
2385 if (FcFileIsDir (filename))
2386 {
2387 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2388 FcStrFree (filename);
2389 return ret;
2390 }
2391
2392 if (FcDebug () & FC_DBG_CONFIG)
2393 printf ("\tLoading config file %s\n", filename);
2394
2395 fd = open ((char *) filename, O_RDONLY);
2396 if (fd == -1) {
2397 FcStrFree (filename);
2398 goto bail0;
2399 }
2400
2401 #ifdef ENABLE_LIBXML2
2402 memset(&sax, 0, sizeof(sax));
2403
2404 sax.internalSubset = FcInternalSubsetDecl;
2405 sax.externalSubset = FcExternalSubsetDecl;
2406 sax.startElement = FcStartElement;
2407 sax.endElement = FcEndElement;
2408 sax.characters = FcCharacterData;
2409
2410 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2411 #else
2412 p = XML_ParserCreate ("UTF-8");
2413 #endif
2414 FcStrFree (filename);
2415
2416 if (!p)
2417 goto bail1;
2418
2419 if (!FcConfigInit (&parse, name, config, p))
2420 goto bail2;
2421
2422 #ifndef ENABLE_LIBXML2
2423
2424 XML_SetUserData (p, &parse);
2425
2426 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2427 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2428 XML_SetCharacterDataHandler (p, FcCharacterData);
2429
2430 #endif /* ENABLE_LIBXML2 */
2431
2432 do {
2433 #ifndef ENABLE_LIBXML2
2434 buf = XML_GetBuffer (p, BUFSIZ);
2435 if (!buf)
2436 {
2437 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2438 goto bail3;
2439 }
2440 #endif
2441 len = read (fd, buf, BUFSIZ);
2442 if (len < 0)
2443 {
2444 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2445 goto bail3;
2446 }
2447
2448 #ifdef ENABLE_LIBXML2
2449 if (xmlParseChunk (p, buf, len, len == 0))
2450 #else
2451 if (!XML_ParseBuffer (p, len, len == 0))
2452 #endif
2453 {
2454 FcConfigMessage (&parse, FcSevereError, "%s",
2455 XML_ErrorString (XML_GetErrorCode (p)));
2456 goto bail3;
2457 }
2458 } while (len != 0);
2459 error = parse.error;
2460 bail3:
2461 FcConfigCleanup (&parse);
2462 bail2:
2463 XML_ParserFree (p);
2464 bail1:
2465 close (fd);
2466 fd = -1;
2467 bail0:
2468 if (error && complain)
2469 {
2470 if (name)
2471 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2472 else
2473 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2474 return FcFalse;
2475 }
2476 return FcTrue;
2477 }