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