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