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