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