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