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