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