]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Workaround for stat() brokenness in Microsoft's C library (bug 8526)
[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 #ifdef _WIN32
2094 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2095 {
2096 int rc;
2097 FcStrFree (data);
2098 data = malloc (1000);
2099 if (!data)
2100 {
2101 FcConfigMessage (parse, FcSevereError, "out of memory");
2102 break;
2103 }
2104 FcMemAlloc (FC_MEM_STRING, 1000);
2105 rc = GetTempPath (800, data);
2106 if (rc == 0 || rc > 800)
2107 {
2108 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2109 FcStrFree (data);
2110 break;
2111 }
2112 if (data [strlen (data) - 1] != '\\')
2113 strcat (data, "\\");
2114 strcat (data, "fontconfig\\cache");
2115 }
2116 #endif
2117 if (!FcStrUsesHome (data) || FcConfigHome ())
2118 {
2119 if (!FcConfigAddCacheDir (parse->config, data))
2120 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2121 }
2122 FcStrFree (data);
2123 break;
2124
2125 case FcElementCache:
2126 data = FcStrBufDone (&parse->pstack->str);
2127 if (!data)
2128 {
2129 FcConfigMessage (parse, FcSevereError, "out of memory");
2130 break;
2131 }
2132 /* discard this data; no longer used */
2133 FcStrFree (data);
2134 break;
2135 case FcElementInclude:
2136 FcParseInclude (parse);
2137 break;
2138 case FcElementConfig:
2139 break;
2140 case FcElementMatch:
2141 FcParseMatch (parse);
2142 break;
2143 case FcElementAlias:
2144 FcParseAlias (parse);
2145 break;
2146
2147 case FcElementBlank:
2148 FcParseBlank (parse);
2149 break;
2150 case FcElementRescan:
2151 FcParseRescan (parse);
2152 break;
2153
2154 case FcElementPrefer:
2155 FcParseFamilies (parse, FcVStackPrefer);
2156 break;
2157 case FcElementAccept:
2158 FcParseFamilies (parse, FcVStackAccept);
2159 break;
2160 case FcElementDefault:
2161 FcParseFamilies (parse, FcVStackDefault);
2162 break;
2163 case FcElementFamily:
2164 FcParseFamily (parse);
2165 break;
2166
2167 case FcElementTest:
2168 FcParseTest (parse);
2169 break;
2170 case FcElementEdit:
2171 FcParseEdit (parse);
2172 break;
2173
2174 case FcElementInt:
2175 FcParseInt (parse);
2176 break;
2177 case FcElementDouble:
2178 FcParseDouble (parse);
2179 break;
2180 case FcElementString:
2181 FcParseString (parse, FcVStackString);
2182 break;
2183 case FcElementMatrix:
2184 FcParseMatrix (parse);
2185 break;
2186 case FcElementBool:
2187 FcParseBool (parse);
2188 break;
2189 case FcElementCharset:
2190 /* FcParseCharset (parse); */
2191 break;
2192 case FcElementSelectfont:
2193 break;
2194 case FcElementAcceptfont:
2195 case FcElementRejectfont:
2196 FcParseAcceptRejectFont (parse, parse->pstack->element);
2197 break;
2198 case FcElementGlob:
2199 FcParseString (parse, FcVStackGlob);
2200 break;
2201 case FcElementPattern:
2202 FcParsePattern (parse);
2203 break;
2204 case FcElementPatelt:
2205 FcParsePatelt (parse);
2206 break;
2207 case FcElementName:
2208 FcParseString (parse, FcVStackField);
2209 break;
2210 case FcElementConst:
2211 FcParseString (parse, FcVStackConstant);
2212 break;
2213 case FcElementOr:
2214 FcParseBinary (parse, FcOpOr);
2215 break;
2216 case FcElementAnd:
2217 FcParseBinary (parse, FcOpAnd);
2218 break;
2219 case FcElementEq:
2220 FcParseBinary (parse, FcOpEqual);
2221 break;
2222 case FcElementNotEq:
2223 FcParseBinary (parse, FcOpNotEqual);
2224 break;
2225 case FcElementLess:
2226 FcParseBinary (parse, FcOpLess);
2227 break;
2228 case FcElementLessEq:
2229 FcParseBinary (parse, FcOpLessEqual);
2230 break;
2231 case FcElementMore:
2232 FcParseBinary (parse, FcOpMore);
2233 break;
2234 case FcElementMoreEq:
2235 FcParseBinary (parse, FcOpMoreEqual);
2236 break;
2237 case FcElementContains:
2238 FcParseBinary (parse, FcOpContains);
2239 break;
2240 case FcElementNotContains:
2241 FcParseBinary (parse, FcOpNotContains);
2242 break;
2243 case FcElementPlus:
2244 FcParseBinary (parse, FcOpPlus);
2245 break;
2246 case FcElementMinus:
2247 FcParseBinary (parse, FcOpMinus);
2248 break;
2249 case FcElementTimes:
2250 FcParseBinary (parse, FcOpTimes);
2251 break;
2252 case FcElementDivide:
2253 FcParseBinary (parse, FcOpDivide);
2254 break;
2255 case FcElementNot:
2256 FcParseUnary (parse, FcOpNot);
2257 break;
2258 case FcElementIf:
2259 FcParseBinary (parse, FcOpQuest);
2260 break;
2261 case FcElementFloor:
2262 FcParseUnary (parse, FcOpFloor);
2263 break;
2264 case FcElementCeil:
2265 FcParseUnary (parse, FcOpCeil);
2266 break;
2267 case FcElementRound:
2268 FcParseUnary (parse, FcOpRound);
2269 break;
2270 case FcElementTrunc:
2271 FcParseUnary (parse, FcOpTrunc);
2272 break;
2273 case FcElementUnknown:
2274 break;
2275 }
2276 (void) FcPStackPop (parse);
2277 }
2278
2279 static void
2280 FcCharacterData (void *userData, const XML_Char *s, int len)
2281 {
2282 FcConfigParse *parse = userData;
2283
2284 if (!parse->pstack)
2285 return;
2286 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2287 FcConfigMessage (parse, FcSevereError, "out of memory");
2288 }
2289
2290 static void
2291 FcStartDoctypeDecl (void *userData,
2292 const XML_Char *doctypeName,
2293 const XML_Char *sysid,
2294 const XML_Char *pubid,
2295 int has_internal_subset)
2296 {
2297 FcConfigParse *parse = userData;
2298
2299 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2300 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2301 }
2302
2303 #ifdef ENABLE_LIBXML2
2304
2305 static void
2306 FcInternalSubsetDecl (void *userData,
2307 const XML_Char *doctypeName,
2308 const XML_Char *sysid,
2309 const XML_Char *pubid)
2310 {
2311 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2312 }
2313
2314 static void
2315 FcExternalSubsetDecl (void *userData,
2316 const XML_Char *doctypeName,
2317 const XML_Char *sysid,
2318 const XML_Char *pubid)
2319 {
2320 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2321 }
2322
2323 #else /* ENABLE_LIBXML2 */
2324
2325 static void
2326 FcEndDoctypeDecl (void *userData)
2327 {
2328 }
2329
2330 #endif /* ENABLE_LIBXML2 */
2331
2332 static int
2333 FcSortCmpStr (const void *a, const void *b)
2334 {
2335 const FcChar8 *as = *((FcChar8 **) a);
2336 const FcChar8 *bs = *((FcChar8 **) b);
2337 return FcStrCmp (as, bs);
2338 }
2339
2340 static FcBool
2341 FcConfigParseAndLoadDir (FcConfig *config,
2342 const FcChar8 *name,
2343 const FcChar8 *dir,
2344 FcBool complain)
2345 {
2346 DIR *d;
2347 struct dirent *e;
2348 FcBool ret = FcTrue;
2349 FcChar8 *file;
2350 FcChar8 *base;
2351 FcStrSet *files;
2352
2353 d = opendir ((char *) dir);
2354 if (!d)
2355 {
2356 if (complain)
2357 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2358 name);
2359 ret = FcFalse;
2360 goto bail0;
2361 }
2362 /* freed below */
2363 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2364 if (!file)
2365 {
2366 ret = FcFalse;
2367 goto bail1;
2368 }
2369
2370 strcpy ((char *) file, (char *) dir);
2371 strcat ((char *) file, "/");
2372 base = file + strlen ((char *) file);
2373
2374 files = FcStrSetCreate ();
2375 if (!files)
2376 {
2377 ret = FcFalse;
2378 goto bail2;
2379 }
2380
2381 if (FcDebug () & FC_DBG_CONFIG)
2382 printf ("\tScanning config dir %s\n", dir);
2383
2384 while (ret && (e = readdir (d)))
2385 {
2386 int d_len;
2387 #define TAIL ".conf"
2388 #define TAIL_LEN 5
2389 /*
2390 * Add all files of the form [0-9]*.conf
2391 */
2392 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2393 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2394 d_len > TAIL_LEN &&
2395 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2396 {
2397 strcpy ((char *) base, (char *) e->d_name);
2398 if (!FcStrSetAdd (files, file))
2399 {
2400 ret = FcFalse;
2401 goto bail3;
2402 }
2403 }
2404 }
2405 if (ret)
2406 {
2407 int i;
2408 qsort (files->strs, files->num, sizeof (FcChar8 *),
2409 (int (*)(const void *, const void *)) FcSortCmpStr);
2410 for (i = 0; ret && i < files->num; i++)
2411 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2412 }
2413 bail3:
2414 FcStrSetDestroy (files);
2415 bail2:
2416 free (file);
2417 bail1:
2418 closedir (d);
2419 bail0:
2420 return ret || !complain;
2421 }
2422
2423 FcBool
2424 FcConfigParseAndLoad (FcConfig *config,
2425 const FcChar8 *name,
2426 FcBool complain)
2427 {
2428
2429 XML_Parser p;
2430 FcChar8 *filename;
2431 int fd;
2432 int len;
2433 FcConfigParse parse;
2434 FcBool error = FcTrue;
2435
2436 #ifdef ENABLE_LIBXML2
2437 xmlSAXHandler sax;
2438 char buf[BUFSIZ];
2439 #else
2440 void *buf;
2441 #endif
2442
2443 filename = FcConfigFilename (name);
2444 if (!filename)
2445 goto bail0;
2446
2447 if (FcStrSetMember (config->configFiles, filename))
2448 {
2449 FcStrFree (filename);
2450 return FcTrue;
2451 }
2452
2453 if (!FcStrSetAdd (config->configFiles, filename))
2454 {
2455 FcStrFree (filename);
2456 goto bail0;
2457 }
2458
2459 if (FcFileIsDir (filename))
2460 {
2461 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2462 FcStrFree (filename);
2463 return ret;
2464 }
2465
2466 if (FcDebug () & FC_DBG_CONFIG)
2467 printf ("\tLoading config file %s\n", filename);
2468
2469 fd = open ((char *) filename, O_RDONLY);
2470 if (fd == -1) {
2471 FcStrFree (filename);
2472 goto bail0;
2473 }
2474
2475 #ifdef ENABLE_LIBXML2
2476 memset(&sax, 0, sizeof(sax));
2477
2478 sax.internalSubset = FcInternalSubsetDecl;
2479 sax.externalSubset = FcExternalSubsetDecl;
2480 sax.startElement = FcStartElement;
2481 sax.endElement = FcEndElement;
2482 sax.characters = FcCharacterData;
2483
2484 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2485 #else
2486 p = XML_ParserCreate ("UTF-8");
2487 #endif
2488 FcStrFree (filename);
2489
2490 if (!p)
2491 goto bail1;
2492
2493 if (!FcConfigInit (&parse, name, config, p))
2494 goto bail2;
2495
2496 #ifndef ENABLE_LIBXML2
2497
2498 XML_SetUserData (p, &parse);
2499
2500 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2501 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2502 XML_SetCharacterDataHandler (p, FcCharacterData);
2503
2504 #endif /* ENABLE_LIBXML2 */
2505
2506 do {
2507 #ifndef ENABLE_LIBXML2
2508 buf = XML_GetBuffer (p, BUFSIZ);
2509 if (!buf)
2510 {
2511 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2512 goto bail3;
2513 }
2514 #endif
2515 len = read (fd, buf, BUFSIZ);
2516 if (len < 0)
2517 {
2518 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2519 goto bail3;
2520 }
2521
2522 #ifdef ENABLE_LIBXML2
2523 if (xmlParseChunk (p, buf, len, len == 0))
2524 #else
2525 if (!XML_ParseBuffer (p, len, len == 0))
2526 #endif
2527 {
2528 FcConfigMessage (&parse, FcSevereError, "%s",
2529 XML_ErrorString (XML_GetErrorCode (p)));
2530 goto bail3;
2531 }
2532 } while (len != 0);
2533 error = parse.error;
2534 bail3:
2535 FcConfigCleanup (&parse);
2536 bail2:
2537 XML_ParserFree (p);
2538 bail1:
2539 close (fd);
2540 fd = -1;
2541 bail0:
2542 if (error && complain)
2543 {
2544 if (name)
2545 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2546 else
2547 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2548 return FcFalse;
2549 }
2550 return FcTrue;
2551 }
2552 #define __fcxml__
2553 #include "fcaliastail.h"
2554 #undef __fcxml__