]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Eliminate unused vars reported by Intel's compiler.
[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 <fcntl.h>
26 #include <stdarg.h>
27 #include "fcint.h"
28 #include <dirent.h>
29
30 #if 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 FcElementCache,
289 FcElementInclude,
290 FcElementConfig,
291 FcElementMatch,
292 FcElementAlias,
293
294 FcElementBlank,
295 FcElementRescan,
296
297 FcElementPrefer,
298 FcElementAccept,
299 FcElementDefault,
300 FcElementFamily,
301
302 FcElementSelectfont,
303 FcElementAcceptfont,
304 FcElementRejectfont,
305 FcElementGlob,
306 FcElementPattern,
307 FcElementPatelt,
308
309 FcElementTest,
310 FcElementEdit,
311 FcElementInt,
312 FcElementDouble,
313 FcElementString,
314 FcElementMatrix,
315 FcElementBool,
316 FcElementCharset,
317 FcElementName,
318 FcElementConst,
319 FcElementOr,
320 FcElementAnd,
321 FcElementEq,
322 FcElementNotEq,
323 FcElementLess,
324 FcElementLessEq,
325 FcElementMore,
326 FcElementMoreEq,
327 FcElementContains,
328 FcElementNotContains,
329 FcElementPlus,
330 FcElementMinus,
331 FcElementTimes,
332 FcElementDivide,
333 FcElementNot,
334 FcElementIf,
335 FcElementFloor,
336 FcElementCeil,
337 FcElementRound,
338 FcElementTrunc,
339 FcElementUnknown
340 } FcElement;
341
342 static struct {
343 const char name[16];
344 FcElement element;
345 } fcElementMap[] = {
346 { "fontconfig", FcElementFontconfig },
347 { "dir", FcElementDir },
348 { "cache", FcElementCache },
349 { "include", FcElementInclude },
350 { "config", FcElementConfig },
351 { "match", FcElementMatch },
352 { "alias", FcElementAlias },
353
354 { "blank", FcElementBlank },
355 { "rescan", FcElementRescan },
356
357 { "prefer", FcElementPrefer },
358 { "accept", FcElementAccept },
359 { "default", FcElementDefault },
360 { "family", FcElementFamily },
361
362 { "selectfont", FcElementSelectfont },
363 { "acceptfont", FcElementAcceptfont },
364 { "rejectfont", FcElementRejectfont },
365 { "glob", FcElementGlob },
366 { "pattern", FcElementPattern },
367 { "patelt", FcElementPatelt },
368
369 { "test", FcElementTest },
370 { "edit", FcElementEdit },
371 { "int", FcElementInt },
372 { "double", FcElementDouble },
373 { "string", FcElementString },
374 { "matrix", FcElementMatrix },
375 { "bool", FcElementBool },
376 { "charset", FcElementCharset },
377 { "name", FcElementName },
378 { "const", FcElementConst },
379 { "or", FcElementOr },
380 { "and", FcElementAnd },
381 { "eq", FcElementEq },
382 { "not_eq", FcElementNotEq },
383 { "less", FcElementLess },
384 { "less_eq", FcElementLessEq },
385 { "more", FcElementMore },
386 { "more_eq", FcElementMoreEq },
387 { "contains", FcElementContains },
388 { "not_contains", FcElementNotContains },
389 { "plus", FcElementPlus },
390 { "minus", FcElementMinus },
391 { "times", FcElementTimes },
392 { "divide", FcElementDivide },
393 { "not", FcElementNot },
394 { "if", FcElementIf },
395 { "floor", FcElementFloor },
396 { "ceil", FcElementCeil },
397 { "round", FcElementRound },
398 { "trunc", FcElementTrunc },
399 };
400 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
401
402 static FcElement
403 FcElementMap (const XML_Char *name)
404 {
405
406 int i;
407 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
408 if (!strcmp ((char *) name, fcElementMap[i].name))
409 return fcElementMap[i].element;
410 return FcElementUnknown;
411 }
412
413 typedef struct _FcPStack {
414 struct _FcPStack *prev;
415 FcElement element;
416 FcChar8 **attr;
417 FcStrBuf str;
418 } FcPStack;
419
420 typedef enum _FcVStackTag {
421 FcVStackNone,
422
423 FcVStackString,
424 FcVStackFamily,
425 FcVStackField,
426 FcVStackConstant,
427 FcVStackGlob,
428 FcVStackPattern,
429
430 FcVStackPrefer,
431 FcVStackAccept,
432 FcVStackDefault,
433
434 FcVStackInteger,
435 FcVStackDouble,
436 FcVStackMatrix,
437 FcVStackBool,
438
439 FcVStackTest,
440 FcVStackExpr,
441 FcVStackEdit
442 } FcVStackTag;
443
444 typedef struct _FcVStack {
445 struct _FcVStack *prev;
446 FcPStack *pstack; /* related parse element */
447 FcVStackTag tag;
448 union {
449 FcChar8 *string;
450
451 int integer;
452 double _double;
453 FcMatrix *matrix;
454 FcBool bool;
455
456 FcTest *test;
457 FcQual qual;
458 FcOp op;
459 FcExpr *expr;
460 FcEdit *edit;
461
462 FcPattern *pattern;
463 } u;
464 } FcVStack;
465
466 typedef struct _FcConfigParse {
467 FcPStack *pstack;
468 FcVStack *vstack;
469 FcBool error;
470 const FcChar8 *name;
471 FcConfig *config;
472 XML_Parser parser;
473 } FcConfigParse;
474
475 typedef enum _FcConfigSeverity {
476 FcSevereInfo, FcSevereWarning, FcSevereError
477 } FcConfigSeverity;
478
479 static void
480 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
481 {
482 const char *s = "unknown";
483 va_list args;
484
485 va_start (args, fmt);
486
487 switch (severe) {
488 case FcSevereInfo: s = "info"; break;
489 case FcSevereWarning: s = "warning"; break;
490 case FcSevereError: s = "error"; break;
491 }
492 if (parse)
493 {
494 if (parse->name)
495 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
496 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
497 else
498 fprintf (stderr, "Fontconfig %s: line %d: ", s,
499 (int)XML_GetCurrentLineNumber (parse->parser));
500 if (severe >= FcSevereError)
501 parse->error = FcTrue;
502 }
503 else
504 fprintf (stderr, "Fontconfig %s: ", s);
505 vfprintf (stderr, fmt, args);
506 fprintf (stderr, "\n");
507 va_end (args);
508 }
509
510
511 static const char *
512 FcTypeName (FcType type)
513 {
514 switch (type) {
515 case FcTypeVoid:
516 return "void";
517 case FcTypeInteger:
518 case FcTypeDouble:
519 return "number";
520 case FcTypeString:
521 return "string";
522 case FcTypeBool:
523 return "bool";
524 case FcTypeMatrix:
525 return "matrix";
526 case FcTypeCharSet:
527 return "charset";
528 case FcTypeFTFace:
529 return "FT_Face";
530 case FcTypeLangSet:
531 return "langset";
532 default:
533 return "unknown";
534 }
535 }
536
537 static void
538 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
539 {
540 if (value == FcTypeInteger)
541 value = FcTypeDouble;
542 if (type == FcTypeInteger)
543 type = FcTypeDouble;
544 if (value != type)
545 {
546 if ((value == FcTypeLangSet && type == FcTypeString) ||
547 (value == FcTypeString && type == FcTypeLangSet))
548 return;
549 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
550 FcTypeName (value), FcTypeName (type));
551 }
552 }
553
554 static void
555 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
556 {
557 const FcObjectType *o;
558 const FcConstant *c;
559
560 switch (expr->op) {
561 case FcOpInteger:
562 case FcOpDouble:
563 FcTypecheckValue (parse, FcTypeDouble, type);
564 break;
565 case FcOpString:
566 FcTypecheckValue (parse, FcTypeString, type);
567 break;
568 case FcOpMatrix:
569 FcTypecheckValue (parse, FcTypeMatrix, type);
570 break;
571 case FcOpBool:
572 FcTypecheckValue (parse, FcTypeBool, type);
573 break;
574 case FcOpCharSet:
575 FcTypecheckValue (parse, FcTypeCharSet, type);
576 break;
577 case FcOpNil:
578 break;
579 case FcOpField:
580 o = FcNameGetObjectType (expr->u.field);
581 if (o)
582 FcTypecheckValue (parse, o->type, type);
583 break;
584 case FcOpConst:
585 c = FcNameGetConstant (expr->u.constant);
586 if (c)
587 {
588 o = FcNameGetObjectType (c->object);
589 if (o)
590 FcTypecheckValue (parse, o->type, type);
591 }
592 else
593 FcConfigMessage (parse, FcSevereWarning,
594 "invalid constant used : %s",
595 expr->u.constant);
596 break;
597 case FcOpQuest:
598 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
599 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
600 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
601 break;
602 case FcOpAssign:
603 case FcOpAssignReplace:
604 break;
605 case FcOpEqual:
606 case FcOpNotEqual:
607 case FcOpLess:
608 case FcOpLessEqual:
609 case FcOpMore:
610 case FcOpMoreEqual:
611 case FcOpContains:
612 case FcOpNotContains:
613 case FcOpListing:
614 FcTypecheckValue (parse, FcTypeBool, type);
615 break;
616 case FcOpComma:
617 case FcOpOr:
618 case FcOpAnd:
619 case FcOpPlus:
620 case FcOpMinus:
621 case FcOpTimes:
622 case FcOpDivide:
623 FcTypecheckExpr (parse, expr->u.tree.left, type);
624 FcTypecheckExpr (parse, expr->u.tree.right, type);
625 break;
626 case FcOpNot:
627 FcTypecheckValue (parse, FcTypeBool, type);
628 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
629 break;
630 case FcOpFloor:
631 case FcOpCeil:
632 case FcOpRound:
633 case FcOpTrunc:
634 FcTypecheckValue (parse, FcTypeDouble, type);
635 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
636 break;
637 default:
638 break;
639 }
640 }
641
642 static FcTest *
643 FcTestCreate (FcConfigParse *parse,
644 FcMatchKind kind,
645 FcQual qual,
646 const FcChar8 *field,
647 FcOp compare,
648 FcExpr *expr)
649 {
650 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
651
652 if (test)
653 {
654 const FcObjectType *o;
655
656 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
657 test->next = 0;
658 test->kind = kind;
659 test->qual = qual;
660 test->field = (char *) FcStrCopy (field);
661 test->op = compare;
662 test->expr = expr;
663 o = FcNameGetObjectType (test->field);
664 if (o)
665 FcTypecheckExpr (parse, expr, o->type);
666 }
667 return test;
668 }
669
670 static FcEdit *
671 FcEditCreate (FcConfigParse *parse,
672 const char *field,
673 FcOp op,
674 FcExpr *expr,
675 FcValueBinding binding)
676 {
677 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
678
679 if (e)
680 {
681 const FcObjectType *o;
682
683 e->next = 0;
684 e->field = field; /* already saved in grammar */
685 e->op = op;
686 e->expr = expr;
687 e->binding = binding;
688 o = FcNameGetObjectType (e->field);
689 if (o)
690 FcTypecheckExpr (parse, expr, o->type);
691 }
692 return e;
693 }
694
695 static void
696 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
697 {
698 vstack->prev = parse->vstack;
699 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
700 parse->vstack = vstack;
701 }
702
703 static FcVStack *
704 FcVStackCreate (void)
705 {
706 FcVStack *new;
707
708 new = malloc (sizeof (FcVStack));
709 if (!new)
710 return 0;
711 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
712 new->tag = FcVStackNone;
713 new->prev = 0;
714 return new;
715 }
716
717 static void
718 FcVStackDestroy (FcVStack *vstack)
719 {
720 FcVStack *prev;
721
722 for (; vstack; vstack = prev)
723 {
724 prev = vstack->prev;
725 switch (vstack->tag) {
726 case FcVStackNone:
727 break;
728 case FcVStackString:
729 case FcVStackFamily:
730 case FcVStackField:
731 case FcVStackConstant:
732 case FcVStackGlob:
733 FcStrFree (vstack->u.string);
734 break;
735 case FcVStackPattern:
736 FcPatternDestroy (vstack->u.pattern);
737 break;
738 case FcVStackInteger:
739 case FcVStackDouble:
740 break;
741 case FcVStackMatrix:
742 FcMatrixFree (vstack->u.matrix);
743 break;
744 case FcVStackBool:
745 break;
746 case FcVStackTest:
747 FcTestDestroy (vstack->u.test);
748 break;
749 case FcVStackExpr:
750 case FcVStackPrefer:
751 case FcVStackAccept:
752 case FcVStackDefault:
753 FcExprDestroy (vstack->u.expr);
754 break;
755 case FcVStackEdit:
756 FcEditDestroy (vstack->u.edit);
757 break;
758 }
759 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
760 free (vstack);
761 }
762 }
763
764 static FcBool
765 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
766 {
767 FcVStack *vstack = FcVStackCreate ();
768 if (!vstack)
769 return FcFalse;
770 vstack->u.string = string;
771 vstack->tag = tag;
772 FcVStackPush (parse, vstack);
773 return FcTrue;
774 }
775
776 static FcBool
777 FcVStackPushInteger (FcConfigParse *parse, int integer)
778 {
779 FcVStack *vstack = FcVStackCreate ();
780 if (!vstack)
781 return FcFalse;
782 vstack->u.integer = integer;
783 vstack->tag = FcVStackInteger;
784 FcVStackPush (parse, vstack);
785 return FcTrue;
786 }
787
788 static FcBool
789 FcVStackPushDouble (FcConfigParse *parse, double _double)
790 {
791 FcVStack *vstack = FcVStackCreate ();
792 if (!vstack)
793 return FcFalse;
794 vstack->u._double = _double;
795 vstack->tag = FcVStackDouble;
796 FcVStackPush (parse, vstack);
797 return FcTrue;
798 }
799
800 static FcBool
801 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
802 {
803 FcVStack *vstack = FcVStackCreate ();
804 if (!vstack)
805 return FcFalse;
806 matrix = FcMatrixCopy (matrix);
807 if (!matrix)
808 {
809 FcVStackDestroy (vstack);
810 return FcFalse;
811 }
812 vstack->u.matrix = matrix;
813 vstack->tag = FcVStackMatrix;
814 FcVStackPush (parse, vstack);
815 return FcTrue;
816 }
817
818 static FcBool
819 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
820 {
821 FcVStack *vstack = FcVStackCreate ();
822 if (!vstack)
823 return FcFalse;
824 vstack->u.bool = bool;
825 vstack->tag = FcVStackBool;
826 FcVStackPush (parse, vstack);
827 return FcTrue;
828 }
829
830 static FcBool
831 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
832 {
833 FcVStack *vstack = FcVStackCreate ();
834 if (!vstack)
835 return FcFalse;
836 vstack->u.test = test;
837 vstack->tag = FcVStackTest;
838 FcVStackPush (parse, vstack);
839 return FcTrue;
840 }
841
842 static FcBool
843 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
844 {
845 FcVStack *vstack = FcVStackCreate ();
846 if (!vstack)
847 return FcFalse;
848 vstack->u.expr = expr;
849 vstack->tag = tag;
850 FcVStackPush (parse, vstack);
851 return FcTrue;
852 }
853
854 static FcBool
855 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
856 {
857 FcVStack *vstack = FcVStackCreate ();
858 if (!vstack)
859 return FcFalse;
860 vstack->u.edit = edit;
861 vstack->tag = FcVStackEdit;
862 FcVStackPush (parse, vstack);
863 return FcTrue;
864 }
865
866 static FcBool
867 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
868 {
869 FcVStack *vstack = FcVStackCreate ();
870 if (!vstack)
871 return FcFalse;
872 vstack->u.pattern = pattern;
873 vstack->tag = FcVStackPattern;
874 FcVStackPush (parse, vstack);
875 return FcTrue;
876 }
877
878 static FcVStack *
879 FcVStackFetch (FcConfigParse *parse, int off)
880 {
881 FcVStack *vstack;
882
883 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
884 return vstack;
885 }
886
887 static void
888 FcVStackClear (FcConfigParse *parse)
889 {
890 while (parse->vstack && parse->vstack->pstack == parse->pstack)
891 {
892 FcVStack *vstack = parse->vstack;
893 parse->vstack = vstack->prev;
894 vstack->prev = 0;
895 FcVStackDestroy (vstack);
896 }
897 }
898
899 static FcVStack *
900 FcVStackPop (FcConfigParse *parse)
901 {
902 FcVStack *vstack = parse->vstack;
903
904 if (!vstack || vstack->pstack != parse->pstack)
905 return 0;
906 parse->vstack = vstack->prev;
907 vstack->prev = 0;
908 return vstack;
909 }
910
911 static int
912 FcVStackElements (FcConfigParse *parse)
913 {
914 int h = 0;
915 FcVStack *vstack = parse->vstack;
916 while (vstack && vstack->pstack == parse->pstack)
917 {
918 h++;
919 vstack = vstack->prev;
920 }
921 return h;
922 }
923
924 static FcChar8 **
925 FcConfigSaveAttr (const XML_Char **attr)
926 {
927 int slen;
928 int i;
929 FcChar8 **new;
930 FcChar8 *s;
931
932 if (!attr)
933 return 0;
934 slen = 0;
935 for (i = 0; attr[i]; i++)
936 slen += strlen ((char *) attr[i]) + 1;
937 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
938 if (!new)
939 return 0;
940 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
941 s = (FcChar8 *) (new + (i + 1));
942 for (i = 0; attr[i]; i++)
943 {
944 new[i] = s;
945 strcpy ((char *) s, (char *) attr[i]);
946 s += strlen ((char *) s) + 1;
947 }
948 new[i] = 0;
949 return new;
950 }
951
952 static FcBool
953 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
954 {
955 FcPStack *new = malloc (sizeof (FcPStack));
956
957 if (!new)
958 return FcFalse;
959 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
960 new->prev = parse->pstack;
961 new->element = element;
962 if (attr)
963 {
964 new->attr = FcConfigSaveAttr (attr);
965 if (!new->attr)
966 FcConfigMessage (parse, FcSevereError, "out of memory");
967 }
968 else
969 new->attr = 0;
970 FcStrBufInit (&new->str, 0, 0);
971 parse->pstack = new;
972 return FcTrue;
973 }
974
975 static FcBool
976 FcPStackPop (FcConfigParse *parse)
977 {
978 FcPStack *old;
979
980 if (!parse->pstack)
981 {
982 FcConfigMessage (parse, FcSevereError, "mismatching element");
983 return FcFalse;
984 }
985 FcVStackClear (parse);
986 old = parse->pstack;
987 parse->pstack = old->prev;
988 FcStrBufDestroy (&old->str);
989 if (old->attr)
990 {
991 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
992 free (old->attr);
993 }
994 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
995 free (old);
996 return FcTrue;
997 }
998
999 static FcBool
1000 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1001 {
1002 parse->pstack = 0;
1003 parse->vstack = 0;
1004 parse->error = FcFalse;
1005 parse->name = name;
1006 parse->config = config;
1007 parse->parser = parser;
1008 return FcTrue;
1009 }
1010
1011 static void
1012 FcConfigCleanup (FcConfigParse *parse)
1013 {
1014 while (parse->pstack)
1015 FcPStackPop (parse);
1016 }
1017
1018 static const FcChar8 *
1019 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1020 {
1021 FcChar8 **attrs;
1022 if (!parse->pstack)
1023 return 0;
1024
1025 attrs = parse->pstack->attr;
1026 if (!attrs)
1027 return 0;
1028
1029 while (*attrs)
1030 {
1031 if (!strcmp ((char *) *attrs, attr))
1032 return attrs[1];
1033 attrs += 2;
1034 }
1035 return 0;
1036 }
1037
1038 static void
1039 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1040 {
1041 FcConfigParse *parse = userData;
1042 FcElement element;
1043
1044 element = FcElementMap (name);
1045 if (element == FcElementUnknown)
1046 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1047
1048 if (!FcPStackPush (parse, element, attr))
1049 {
1050 FcConfigMessage (parse, FcSevereError, "out of memory");
1051 return;
1052 }
1053 return;
1054 }
1055
1056 static void
1057 FcParseBlank (FcConfigParse *parse)
1058 {
1059 int n = FcVStackElements (parse);
1060 while (n-- > 0)
1061 {
1062 FcVStack *v = FcVStackFetch (parse, n);
1063 if (v->tag != FcVStackInteger)
1064 FcConfigMessage (parse, FcSevereError, "non-integer blank");
1065 else
1066 {
1067 if (!parse->config->blanks)
1068 {
1069 parse->config->blanks = FcBlanksCreate ();
1070 if (!parse->config->blanks)
1071 {
1072 FcConfigMessage (parse, FcSevereError, "out of memory");
1073 break;
1074 }
1075 }
1076 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1077 {
1078 FcConfigMessage (parse, FcSevereError, "out of memory");
1079 break;
1080 }
1081 }
1082 }
1083 }
1084
1085 static void
1086 FcParseRescan (FcConfigParse *parse)
1087 {
1088 int n = FcVStackElements (parse);
1089 while (n-- > 0)
1090 {
1091 FcVStack *v = FcVStackFetch (parse, n);
1092 if (v->tag != FcVStackInteger)
1093 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1094 else
1095 parse->config->rescanInterval = v->u.integer;
1096 }
1097 }
1098
1099 static void
1100 FcParseInt (FcConfigParse *parse)
1101 {
1102 FcChar8 *s, *end;
1103 int l;
1104
1105 if (!parse->pstack)
1106 return;
1107 s = FcStrBufDone (&parse->pstack->str);
1108 if (!s)
1109 {
1110 FcConfigMessage (parse, FcSevereError, "out of memory");
1111 return;
1112 }
1113 end = 0;
1114 l = (int) strtol ((char *) s, (char **)&end, 0);
1115 if (end != s + strlen ((char *) s))
1116 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1117 else
1118 FcVStackPushInteger (parse, l);
1119 FcStrFree (s);
1120 }
1121
1122 /*
1123 * idea copied from glib g_ascii_strtod with
1124 * permission of the author (Alexander Larsson)
1125 */
1126
1127 #include <locale.h>
1128
1129 static double
1130 FcStrtod (char *s, char **end)
1131 {
1132 struct lconv *locale_data;
1133 char *dot;
1134 double v;
1135
1136 /*
1137 * Have to swap the decimal point to match the current locale
1138 * if that locale doesn't use 0x2e
1139 */
1140 if ((dot = strchr (s, 0x2e)) &&
1141 (locale_data = localeconv ()) &&
1142 (locale_data->decimal_point[0] != 0x2e ||
1143 locale_data->decimal_point[1] != 0))
1144 {
1145 char buf[128];
1146 int slen = strlen (s);
1147 int dlen = strlen (locale_data->decimal_point);
1148
1149 if (slen + dlen > (int) sizeof (buf))
1150 {
1151 if (end)
1152 *end = s;
1153 v = 0;
1154 }
1155 else
1156 {
1157 char *buf_end;
1158 /* mantissa */
1159 strncpy (buf, s, dot - s);
1160 /* decimal point */
1161 strcpy (buf + (dot - s), locale_data->decimal_point);
1162 /* rest of number */
1163 strcpy (buf + (dot - s) + dlen, dot + 1);
1164 buf_end = 0;
1165 v = strtod (buf, &buf_end);
1166 if (buf_end) {
1167 buf_end = s + (buf_end - buf);
1168 if (buf_end > dot)
1169 buf_end -= dlen - 1;
1170 }
1171 if (end)
1172 *end = buf_end;
1173 }
1174 }
1175 else
1176 v = strtod (s, end);
1177 return v;
1178 }
1179
1180 static void
1181 FcParseDouble (FcConfigParse *parse)
1182 {
1183 FcChar8 *s, *end;
1184 double d;
1185
1186 if (!parse->pstack)
1187 return;
1188 s = FcStrBufDone (&parse->pstack->str);
1189 if (!s)
1190 {
1191 FcConfigMessage (parse, FcSevereError, "out of memory");
1192 return;
1193 }
1194 end = 0;
1195 d = FcStrtod ((char *) s, (char **)&end);
1196 if (end != s + strlen ((char *) s))
1197 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1198 else
1199 FcVStackPushDouble (parse, d);
1200 FcStrFree (s);
1201 }
1202
1203 static void
1204 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1205 {
1206 FcChar8 *s;
1207
1208 if (!parse->pstack)
1209 return;
1210 s = FcStrBufDone (&parse->pstack->str);
1211 if (!s)
1212 {
1213 FcConfigMessage (parse, FcSevereError, "out of memory");
1214 return;
1215 }
1216 if (!FcVStackPushString (parse, tag, s))
1217 FcStrFree (s);
1218 }
1219
1220 static void
1221 FcParseMatrix (FcConfigParse *parse)
1222 {
1223 FcVStack *vstack;
1224 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1225 FcMatrix m;
1226
1227 while ((vstack = FcVStackPop (parse)))
1228 {
1229 double v;
1230 switch (vstack->tag) {
1231 case FcVStackInteger:
1232 v = vstack->u.integer;
1233 break;
1234 case FcVStackDouble:
1235 v = vstack->u._double;
1236 break;
1237 default:
1238 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1239 v = 1.0;
1240 break;
1241 }
1242 switch (matrix_state) {
1243 case m_xx: m.xx = v; break;
1244 case m_xy: m.xy = v; break;
1245 case m_yx: m.yx = v; break;
1246 case m_yy: m.yy = v; break;
1247 default: break;
1248 }
1249 FcVStackDestroy (vstack);
1250 matrix_state--;
1251 }
1252 if (matrix_state != m_done)
1253 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1254 else
1255 FcVStackPushMatrix (parse, &m);
1256 }
1257
1258 static FcBool
1259 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1260 {
1261 FcBool result = FcFalse;
1262
1263 if (!FcNameBool (bool, &result))
1264 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1265 bool);
1266 return result;
1267 }
1268
1269 static void
1270 FcParseBool (FcConfigParse *parse)
1271 {
1272 FcChar8 *s;
1273
1274 if (!parse->pstack)
1275 return;
1276 s = FcStrBufDone (&parse->pstack->str);
1277 if (!s)
1278 {
1279 FcConfigMessage (parse, FcSevereError, "out of memory");
1280 return;
1281 }
1282 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1283 FcStrFree (s);
1284 }
1285
1286 static void
1287 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1288 {
1289 FcVStack *vstack;
1290 FcExpr *left, *expr = 0, *new;
1291
1292 while ((vstack = FcVStackPop (parse)))
1293 {
1294 if (vstack->tag != FcVStackFamily)
1295 {
1296 FcConfigMessage (parse, FcSevereWarning, "non-family");
1297 FcVStackDestroy (vstack);
1298 continue;
1299 }
1300 left = vstack->u.expr;
1301 vstack->tag = FcVStackNone;
1302 FcVStackDestroy (vstack);
1303 if (expr)
1304 {
1305 new = FcExprCreateOp (left, FcOpComma, expr);
1306 if (!new)
1307 {
1308 FcConfigMessage (parse, FcSevereError, "out of memory");
1309 FcExprDestroy (left);
1310 FcExprDestroy (expr);
1311 break;
1312 }
1313 expr = new;
1314 }
1315 else
1316 expr = left;
1317 }
1318 if (expr)
1319 {
1320 if (!FcVStackPushExpr (parse, tag, expr))
1321 {
1322 FcConfigMessage (parse, FcSevereError, "out of memory");
1323 if (expr)
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 FcConfigSaveField ("family"),
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 FcConfigSaveField ("family"),
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 FcConfigSaveField ("family"),
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 break;
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, "default"))
1673 kind = FcMatchDefault;
1674 else
1675 {
1676 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1677 return;
1678 }
1679 }
1680 qual_string = FcConfigGetAttribute (parse, "qual");
1681 if (!qual_string)
1682 qual = FcQualAny;
1683 else
1684 {
1685 if (!strcmp ((char *) qual_string, "any"))
1686 qual = FcQualAny;
1687 else if (!strcmp ((char *) qual_string, "all"))
1688 qual = FcQualAll;
1689 else if (!strcmp ((char *) qual_string, "first"))
1690 qual = FcQualFirst;
1691 else if (!strcmp ((char *) qual_string, "not_first"))
1692 qual = FcQualNotFirst;
1693 else
1694 {
1695 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1696 return;
1697 }
1698 }
1699 name = FcConfigGetAttribute (parse, "name");
1700 if (!name)
1701 {
1702 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1703 return;
1704 }
1705 compare_string = FcConfigGetAttribute (parse, "compare");
1706 if (!compare_string)
1707 compare = FcOpEqual;
1708 else
1709 {
1710 compare = FcConfigLexCompare (compare_string);
1711 if (compare == FcOpInvalid)
1712 {
1713 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1714 return;
1715 }
1716 }
1717 expr = FcPopBinary (parse, FcOpComma);
1718 if (!expr)
1719 {
1720 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1721 return;
1722 }
1723 test = FcTestCreate (parse, kind, qual, name, compare, expr);
1724 if (!test)
1725 {
1726 FcConfigMessage (parse, FcSevereError, "out of memory");
1727 return;
1728 }
1729 FcVStackPushTest (parse, test);
1730 }
1731
1732 static const FcOpMap fcModeOps[] = {
1733 { "assign", FcOpAssign },
1734 { "assign_replace", FcOpAssignReplace },
1735 { "prepend", FcOpPrepend },
1736 { "prepend_first", FcOpPrependFirst },
1737 { "append", FcOpAppend },
1738 { "append_last", FcOpAppendLast },
1739 };
1740
1741 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1742
1743 static FcOp
1744 FcConfigLexMode (const FcChar8 *mode)
1745 {
1746 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1747 }
1748
1749 static void
1750 FcParseEdit (FcConfigParse *parse)
1751 {
1752 const FcChar8 *name;
1753 const FcChar8 *mode_string;
1754 const FcChar8 *binding_string;
1755 FcOp mode;
1756 FcValueBinding binding;
1757 FcExpr *expr;
1758 FcEdit *edit;
1759
1760 name = FcConfigGetAttribute (parse, "name");
1761 if (!name)
1762 {
1763 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1764 return;
1765 }
1766 mode_string = FcConfigGetAttribute (parse, "mode");
1767 if (!mode_string)
1768 mode = FcOpAssign;
1769 else
1770 {
1771 mode = FcConfigLexMode (mode_string);
1772 if (mode == FcOpInvalid)
1773 {
1774 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1775 return;
1776 }
1777 }
1778 binding_string = FcConfigGetAttribute (parse, "binding");
1779 if (!binding_string)
1780 binding = FcValueBindingWeak;
1781 else
1782 {
1783 if (!strcmp ((char *) binding_string, "weak"))
1784 binding = FcValueBindingWeak;
1785 else if (!strcmp ((char *) binding_string, "strong"))
1786 binding = FcValueBindingStrong;
1787 else if (!strcmp ((char *) binding_string, "same"))
1788 binding = FcValueBindingSame;
1789 else
1790 {
1791 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1792 return;
1793 }
1794 }
1795 expr = FcPopBinary (parse, FcOpComma);
1796 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
1797 if (!edit)
1798 {
1799 FcConfigMessage (parse, FcSevereError, "out of memory");
1800 FcExprDestroy (expr);
1801 return;
1802 }
1803 if (!FcVStackPushEdit (parse, edit))
1804 FcEditDestroy (edit);
1805 }
1806
1807 static void
1808 FcParseMatch (FcConfigParse *parse)
1809 {
1810 const FcChar8 *kind_name;
1811 FcMatchKind kind;
1812 FcTest *test = 0;
1813 FcEdit *edit = 0;
1814 FcVStack *vstack;
1815
1816 kind_name = FcConfigGetAttribute (parse, "target");
1817 if (!kind_name)
1818 kind = FcMatchPattern;
1819 else
1820 {
1821 if (!strcmp ((char *) kind_name, "pattern"))
1822 kind = FcMatchPattern;
1823 else if (!strcmp ((char *) kind_name, "font"))
1824 kind = FcMatchFont;
1825 else
1826 {
1827 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1828 return;
1829 }
1830 }
1831 while ((vstack = FcVStackPop (parse)))
1832 {
1833 switch (vstack->tag) {
1834 case FcVStackTest:
1835 vstack->u.test->next = test;
1836 test = vstack->u.test;
1837 vstack->tag = FcVStackNone;
1838 break;
1839 case FcVStackEdit:
1840 vstack->u.edit->next = edit;
1841 edit = vstack->u.edit;
1842 vstack->tag = FcVStackNone;
1843 break;
1844 default:
1845 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1846 break;
1847 }
1848 FcVStackDestroy (vstack);
1849 }
1850 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1851 FcConfigMessage (parse, FcSevereError, "out of memory");
1852 }
1853
1854 static void
1855 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1856 {
1857 FcVStack *vstack;
1858
1859 while ((vstack = FcVStackPop (parse)))
1860 {
1861 switch (vstack->tag) {
1862 case FcVStackGlob:
1863 if (!FcConfigGlobAdd (parse->config,
1864 vstack->u.string,
1865 element == FcElementAcceptfont))
1866 {
1867 FcConfigMessage (parse, FcSevereError, "out of memory");
1868 }
1869 break;
1870 case FcVStackPattern:
1871 if (!FcConfigPatternsAdd (parse->config,
1872 vstack->u.pattern,
1873 element == FcElementAcceptfont))
1874 {
1875 FcConfigMessage (parse, FcSevereError, "out of memory");
1876 }
1877 else
1878 vstack->tag = FcVStackNone;
1879 break;
1880 default:
1881 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1882 break;
1883 }
1884 FcVStackDestroy (vstack);
1885 }
1886 }
1887
1888
1889 static FcValue
1890 FcPopValue (FcConfigParse *parse)
1891 {
1892 FcVStack *vstack = FcVStackPop (parse);
1893 FcValue value;
1894
1895 value.type = FcTypeVoid;
1896
1897 if (!vstack)
1898 return value;
1899
1900 switch (vstack->tag) {
1901 case FcVStackString:
1902 value.u.s = FcStrCopy (vstack->u.string);
1903 if (value.u.s)
1904 value.type = FcTypeString;
1905 break;
1906 case FcVStackConstant:
1907 if (FcNameConstant (vstack->u.string, &value.u.i))
1908 value.type = FcTypeInteger;
1909 break;
1910 case FcVStackInteger:
1911 value.u.i = vstack->u.integer;
1912 value.type = FcTypeInteger;
1913 break;
1914 case FcVStackDouble:
1915 value.u.d = vstack->u._double;
1916 value.type = FcTypeInteger;
1917 break;
1918 case FcVStackMatrix:
1919 value.u.m = FcMatrixCopy (vstack->u.matrix);
1920 if (value.u.m)
1921 value.type = FcTypeMatrix;
1922 break;
1923 case FcVStackBool:
1924 value.u.b = vstack->u.bool;
1925 value.type = FcTypeBool;
1926 break;
1927 default:
1928 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1929 vstack->tag);
1930 break;
1931 }
1932 FcVStackDestroy (vstack);
1933
1934 return value;
1935 }
1936
1937 static void
1938 FcParsePatelt (FcConfigParse *parse)
1939 {
1940 FcValue value;
1941 FcPattern *pattern = FcPatternCreate ();
1942 const char *name;
1943
1944 if (!pattern)
1945 {
1946 FcConfigMessage (parse, FcSevereError, "out of memory");
1947 return;
1948 }
1949
1950 name = (char *) FcConfigGetAttribute (parse, "name");
1951 if (!name)
1952 {
1953 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1954 return;
1955 }
1956
1957 for (;;)
1958 {
1959 value = FcPopValue (parse);
1960 if (value.type == FcTypeVoid)
1961 break;
1962 if (!FcPatternAdd (pattern, name, value, FcTrue))
1963 {
1964 FcConfigMessage (parse, FcSevereError, "out of memory");
1965 break;
1966 }
1967 }
1968
1969 FcVStackPushPattern (parse, FcPatternFreeze(pattern));
1970 FcPatternDestroy (pattern);
1971 }
1972
1973 static void
1974 FcParsePattern (FcConfigParse *parse)
1975 {
1976 FcVStack *vstack;
1977 FcPattern *pattern = FcPatternCreate ();
1978
1979 if (!pattern)
1980 {
1981 FcConfigMessage (parse, FcSevereError, "out of memory");
1982 return;
1983 }
1984
1985 while ((vstack = FcVStackPop (parse)))
1986 {
1987 switch (vstack->tag) {
1988 case FcVStackPattern:
1989 if (!FcPatternAppend (pattern, vstack->u.pattern))
1990 {
1991 FcConfigMessage (parse, FcSevereError, "out of memory");
1992 return;
1993 }
1994 break;
1995 default:
1996 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1997 break;
1998 }
1999 FcVStackDestroy (vstack);
2000 }
2001
2002 FcVStackPushPattern (parse, pattern);
2003 }
2004
2005 static void
2006 FcEndElement(void *userData, const XML_Char *name)
2007 {
2008 FcConfigParse *parse = userData;
2009 FcChar8 *data;
2010
2011 if (!parse->pstack)
2012 return;
2013 switch (parse->pstack->element) {
2014 case FcElementNone:
2015 break;
2016 case FcElementFontconfig:
2017 break;
2018 case FcElementDir:
2019 data = FcStrBufDone (&parse->pstack->str);
2020 if (!data)
2021 {
2022 FcConfigMessage (parse, FcSevereError, "out of memory");
2023 break;
2024 }
2025 #ifdef _WIN32
2026 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2027 {
2028 int rc;
2029 FcStrFree (data);
2030 data = malloc (1000);
2031 if (!data)
2032 {
2033 FcConfigMessage (parse, FcSevereError, "out of memory");
2034 break;
2035 }
2036 FcMemAlloc (FC_MEM_STRING, 1000);
2037 rc = GetWindowsDirectory (data, 800);
2038 if (rc == 0 || rc > 800)
2039 {
2040 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2041 FcStrFree (data);
2042 break;
2043 }
2044 if (data [strlen (data) - 1] != '\\')
2045 strcat (data, "\\");
2046 strcat (data, "fonts");
2047 }
2048 #endif
2049 if (!FcStrUsesHome (data) || FcConfigHome ())
2050 {
2051 if (!FcConfigAddDir (parse->config, data))
2052 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2053 }
2054 FcStrFree (data);
2055 break;
2056 case FcElementCache:
2057 data = FcStrBufDone (&parse->pstack->str);
2058 if (!data)
2059 {
2060 FcConfigMessage (parse, FcSevereError, "out of memory");
2061 break;
2062 }
2063 if (!FcStrUsesHome (data) || FcConfigHome ())
2064 {
2065 if (!FcConfigSetCache (parse->config, data))
2066 FcConfigMessage (parse, FcSevereError, "out of memory");
2067 }
2068 FcStrFree (data);
2069 break;
2070 case FcElementInclude:
2071 FcParseInclude (parse);
2072 break;
2073 case FcElementConfig:
2074 break;
2075 case FcElementMatch:
2076 FcParseMatch (parse);
2077 break;
2078 case FcElementAlias:
2079 FcParseAlias (parse);
2080 break;
2081
2082 case FcElementBlank:
2083 FcParseBlank (parse);
2084 break;
2085 case FcElementRescan:
2086 FcParseRescan (parse);
2087 break;
2088
2089 case FcElementPrefer:
2090 FcParseFamilies (parse, FcVStackPrefer);
2091 break;
2092 case FcElementAccept:
2093 FcParseFamilies (parse, FcVStackAccept);
2094 break;
2095 case FcElementDefault:
2096 FcParseFamilies (parse, FcVStackDefault);
2097 break;
2098 case FcElementFamily:
2099 FcParseFamily (parse);
2100 break;
2101
2102 case FcElementTest:
2103 FcParseTest (parse);
2104 break;
2105 case FcElementEdit:
2106 FcParseEdit (parse);
2107 break;
2108
2109 case FcElementInt:
2110 FcParseInt (parse);
2111 break;
2112 case FcElementDouble:
2113 FcParseDouble (parse);
2114 break;
2115 case FcElementString:
2116 FcParseString (parse, FcVStackString);
2117 break;
2118 case FcElementMatrix:
2119 FcParseMatrix (parse);
2120 break;
2121 case FcElementBool:
2122 FcParseBool (parse);
2123 break;
2124 case FcElementCharset:
2125 /* FcParseCharset (parse); */
2126 break;
2127 case FcElementSelectfont:
2128 break;
2129 case FcElementAcceptfont:
2130 case FcElementRejectfont:
2131 FcParseAcceptRejectFont (parse, parse->pstack->element);
2132 break;
2133 case FcElementGlob:
2134 FcParseString (parse, FcVStackGlob);
2135 break;
2136 case FcElementPattern:
2137 FcParsePattern (parse);
2138 break;
2139 case FcElementPatelt:
2140 FcParsePatelt (parse);
2141 break;
2142 case FcElementName:
2143 FcParseString (parse, FcVStackField);
2144 break;
2145 case FcElementConst:
2146 FcParseString (parse, FcVStackConstant);
2147 break;
2148 case FcElementOr:
2149 FcParseBinary (parse, FcOpOr);
2150 break;
2151 case FcElementAnd:
2152 FcParseBinary (parse, FcOpAnd);
2153 break;
2154 case FcElementEq:
2155 FcParseBinary (parse, FcOpEqual);
2156 break;
2157 case FcElementNotEq:
2158 FcParseBinary (parse, FcOpNotEqual);
2159 break;
2160 case FcElementLess:
2161 FcParseBinary (parse, FcOpLess);
2162 break;
2163 case FcElementLessEq:
2164 FcParseBinary (parse, FcOpLessEqual);
2165 break;
2166 case FcElementMore:
2167 FcParseBinary (parse, FcOpMore);
2168 break;
2169 case FcElementMoreEq:
2170 FcParseBinary (parse, FcOpMoreEqual);
2171 break;
2172 case FcElementContains:
2173 FcParseBinary (parse, FcOpContains);
2174 break;
2175 case FcElementNotContains:
2176 FcParseBinary (parse, FcOpNotContains);
2177 break;
2178 case FcElementPlus:
2179 FcParseBinary (parse, FcOpPlus);
2180 break;
2181 case FcElementMinus:
2182 FcParseBinary (parse, FcOpMinus);
2183 break;
2184 case FcElementTimes:
2185 FcParseBinary (parse, FcOpTimes);
2186 break;
2187 case FcElementDivide:
2188 FcParseBinary (parse, FcOpDivide);
2189 break;
2190 case FcElementNot:
2191 FcParseUnary (parse, FcOpNot);
2192 break;
2193 case FcElementIf:
2194 FcParseBinary (parse, FcOpQuest);
2195 break;
2196 case FcElementFloor:
2197 FcParseUnary (parse, FcOpFloor);
2198 break;
2199 case FcElementCeil:
2200 FcParseUnary (parse, FcOpCeil);
2201 break;
2202 case FcElementRound:
2203 FcParseUnary (parse, FcOpRound);
2204 break;
2205 case FcElementTrunc:
2206 FcParseUnary (parse, FcOpTrunc);
2207 break;
2208 case FcElementUnknown:
2209 break;
2210 }
2211 (void) FcPStackPop (parse);
2212 }
2213
2214 static void
2215 FcCharacterData (void *userData, const XML_Char *s, int len)
2216 {
2217 FcConfigParse *parse = userData;
2218
2219 if (!parse->pstack)
2220 return;
2221 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2222 FcConfigMessage (parse, FcSevereError, "out of memory");
2223 }
2224
2225 static void
2226 FcStartDoctypeDecl (void *userData,
2227 const XML_Char *doctypeName,
2228 const XML_Char *sysid,
2229 const XML_Char *pubid,
2230 int has_internal_subset)
2231 {
2232 FcConfigParse *parse = userData;
2233
2234 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2235 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2236 }
2237
2238 #if ENABLE_LIBXML2
2239
2240 static void
2241 FcInternalSubsetDecl (void *userData,
2242 const XML_Char *doctypeName,
2243 const XML_Char *sysid,
2244 const XML_Char *pubid)
2245 {
2246 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2247 }
2248
2249 static void
2250 FcExternalSubsetDecl (void *userData,
2251 const XML_Char *doctypeName,
2252 const XML_Char *sysid,
2253 const XML_Char *pubid)
2254 {
2255 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2256 }
2257
2258 #else /* ENABLE_LIBXML2 */
2259
2260 static void
2261 FcEndDoctypeDecl (void *userData)
2262 {
2263 }
2264
2265 #endif /* ENABLE_LIBXML2 */
2266
2267 static FcBool
2268 FcConfigParseAndLoadDir (FcConfig *config,
2269 const FcChar8 *name,
2270 const FcChar8 *dir,
2271 FcBool complain)
2272 {
2273 DIR *d;
2274 struct dirent *e;
2275 FcBool ret = FcTrue;
2276 FcChar8 *file;
2277 FcChar8 *base;
2278 FcStrSet *files;
2279
2280 d = opendir ((char *) dir);
2281 if (!d)
2282 {
2283 if (complain)
2284 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2285 name);
2286 ret = FcFalse;
2287 goto bail0;
2288 }
2289 /* freed below */
2290 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2291 if (!file)
2292 {
2293 ret = FcFalse;
2294 goto bail1;
2295 }
2296
2297 strcpy ((char *) file, (char *) dir);
2298 strcat ((char *) file, "/");
2299 base = file + strlen ((char *) file);
2300
2301 files = FcStrSetCreate ();
2302 if (!files)
2303 {
2304 ret = FcFalse;
2305 goto bail2;
2306 }
2307
2308 if (FcDebug () & FC_DBG_CONFIG)
2309 printf ("\tScanning config dir %s\n", dir);
2310
2311 while (ret && (e = readdir (d)))
2312 {
2313 int d_len;
2314 #define TAIL ".conf"
2315 #define TAIL_LEN 5
2316 /*
2317 * Add all files of the form [0-9]*.conf
2318 */
2319 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2320 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2321 d_len > TAIL_LEN &&
2322 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2323 {
2324 strcpy ((char *) base, (char *) e->d_name);
2325 if (!FcStrSetAdd (files, file))
2326 {
2327 ret = FcFalse;
2328 goto bail3;
2329 }
2330 }
2331 }
2332 if (ret)
2333 {
2334 int i;
2335 qsort (files->strs, files->num, sizeof (FcChar8 *),
2336 (int (*)(const void *, const void *)) FcStrCmp);
2337 for (i = 0; ret && i < files->num; i++)
2338 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2339 }
2340 bail3:
2341 FcStrSetDestroy (files);
2342 bail2:
2343 free (file);
2344 bail1:
2345 closedir (d);
2346 bail0:
2347 return ret || !complain;
2348 }
2349
2350 FcBool
2351 FcConfigParseAndLoad (FcConfig *config,
2352 const FcChar8 *name,
2353 FcBool complain)
2354 {
2355
2356 XML_Parser p;
2357 FcChar8 *filename;
2358 int fd;
2359 int len;
2360 FcConfigParse parse;
2361 FcBool error = FcTrue;
2362
2363 #if ENABLE_LIBXML2
2364 xmlSAXHandler sax;
2365 char buf[BUFSIZ];
2366 #else
2367 void *buf;
2368 #endif
2369
2370 filename = FcConfigFilename (name);
2371 if (!filename)
2372 goto bail0;
2373
2374 if (FcStrSetMember (config->configFiles, filename))
2375 {
2376 FcStrFree (filename);
2377 return FcTrue;
2378 }
2379
2380 if (!FcStrSetAdd (config->configFiles, filename))
2381 {
2382 FcStrFree (filename);
2383 goto bail0;
2384 }
2385
2386 if (FcFileIsDir (filename))
2387 {
2388 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2389 FcStrFree (filename);
2390 return ret;
2391 }
2392
2393 if (FcDebug () & FC_DBG_CONFIG)
2394 printf ("\tLoading config file %s\n", filename);
2395
2396 fd = open ((char *) filename, O_RDONLY);
2397 if (fd == -1) {
2398 FcStrFree (filename);
2399 goto bail0;
2400 }
2401
2402 #if ENABLE_LIBXML2
2403 memset(&sax, 0, sizeof(sax));
2404
2405 sax.internalSubset = FcInternalSubsetDecl;
2406 sax.externalSubset = FcExternalSubsetDecl;
2407 sax.startElement = FcStartElement;
2408 sax.endElement = FcEndElement;
2409 sax.characters = FcCharacterData;
2410
2411 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2412 #else
2413 p = XML_ParserCreate ("UTF-8");
2414 #endif
2415 FcStrFree (filename);
2416
2417 if (!p)
2418 goto bail1;
2419
2420 if (!FcConfigInit (&parse, name, config, p))
2421 goto bail2;
2422
2423 #if !ENABLE_LIBXML2
2424
2425 XML_SetUserData (p, &parse);
2426
2427 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2428 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2429 XML_SetCharacterDataHandler (p, FcCharacterData);
2430
2431 #endif /* ENABLE_LIBXML2 */
2432
2433 do {
2434 #if !ENABLE_LIBXML2
2435 buf = XML_GetBuffer (p, BUFSIZ);
2436 if (!buf)
2437 {
2438 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2439 goto bail3;
2440 }
2441 #endif
2442 len = read (fd, buf, BUFSIZ);
2443 if (len < 0)
2444 {
2445 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2446 goto bail3;
2447 }
2448
2449 #if ENABLE_LIBXML2
2450 if (xmlParseChunk (p, buf, len, len == 0))
2451 #else
2452 if (!XML_ParseBuffer (p, len, len == 0))
2453 #endif
2454 {
2455 FcConfigMessage (&parse, FcSevereError, "%s",
2456 XML_ErrorString (XML_GetErrorCode (p)));
2457 goto bail3;
2458 }
2459 } while (len != 0);
2460 error = parse.error;
2461 bail3:
2462 FcConfigCleanup (&parse);
2463 bail2:
2464 XML_ParserFree (p);
2465 bail1:
2466 close (fd);
2467 fd = -1;
2468 bail0:
2469 if (error && complain)
2470 {
2471 if (name)
2472 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2473 else
2474 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2475 return FcFalse;
2476 }
2477 return FcTrue;
2478 }