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