]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Add the range support in blank element
[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 FcChar32 i;
1097 while (n-- > 0)
1098 {
1099 FcVStack *v = FcVStackFetch (parse, n);
1100 if (!parse->config->blanks)
1101 {
1102 parse->config->blanks = FcBlanksCreate ();
1103 if (!parse->config->blanks)
1104 goto bail;
1105 }
1106 switch (v->tag) {
1107 case FcVStackInteger:
1108 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1109 goto bail;
1110 break;
1111 case FcVStackRange:
1112 for (i = v->u.range.begin; i <= v->u.range.end; i++)
1113 {
1114 if (!FcBlanksAdd (parse->config->blanks, i))
1115 goto bail;
1116 }
1117 break;
1118 default:
1119 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1120 break;
1121 }
1122 }
1123 return;
1124 bail:
1125 FcConfigMessage (parse, FcSevereError, "out of memory");
1126 }
1127
1128 static void
1129 FcParseRescan (FcConfigParse *parse)
1130 {
1131 int n = FcVStackElements (parse);
1132 while (n-- > 0)
1133 {
1134 FcVStack *v = FcVStackFetch (parse, n);
1135 if (v->tag != FcVStackInteger)
1136 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1137 else
1138 parse->config->rescanInterval = v->u.integer;
1139 }
1140 }
1141
1142 static void
1143 FcParseInt (FcConfigParse *parse)
1144 {
1145 FcChar8 *s, *end;
1146 int l;
1147
1148 if (!parse->pstack)
1149 return;
1150 s = FcStrBufDoneStatic (&parse->pstack->str);
1151 if (!s)
1152 {
1153 FcConfigMessage (parse, FcSevereError, "out of memory");
1154 return;
1155 }
1156 end = 0;
1157 l = (int) strtol ((char *) s, (char **)&end, 0);
1158 if (end != s + strlen ((char *) s))
1159 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1160 else
1161 FcVStackPushInteger (parse, l);
1162 FcStrBufDestroy (&parse->pstack->str);
1163 }
1164
1165 /*
1166 * idea copied from glib g_ascii_strtod with
1167 * permission of the author (Alexander Larsson)
1168 */
1169
1170 #include <locale.h>
1171
1172 static double
1173 FcStrtod (char *s, char **end)
1174 {
1175 struct lconv *locale_data;
1176 char *dot;
1177 double v;
1178
1179 /*
1180 * Have to swap the decimal point to match the current locale
1181 * if that locale doesn't use 0x2e
1182 */
1183 if ((dot = strchr (s, 0x2e)) &&
1184 (locale_data = localeconv ()) &&
1185 (locale_data->decimal_point[0] != 0x2e ||
1186 locale_data->decimal_point[1] != 0))
1187 {
1188 char buf[128];
1189 int slen = strlen (s);
1190 int dlen = strlen (locale_data->decimal_point);
1191
1192 if (slen + dlen > (int) sizeof (buf))
1193 {
1194 if (end)
1195 *end = s;
1196 v = 0;
1197 }
1198 else
1199 {
1200 char *buf_end;
1201 /* mantissa */
1202 strncpy (buf, s, dot - s);
1203 /* decimal point */
1204 strcpy (buf + (dot - s), locale_data->decimal_point);
1205 /* rest of number */
1206 strcpy (buf + (dot - s) + dlen, dot + 1);
1207 buf_end = 0;
1208 v = strtod (buf, &buf_end);
1209 if (buf_end) {
1210 buf_end = s + (buf_end - buf);
1211 if (buf_end > dot)
1212 buf_end -= dlen - 1;
1213 }
1214 if (end)
1215 *end = buf_end;
1216 }
1217 }
1218 else
1219 v = strtod (s, end);
1220 return v;
1221 }
1222
1223 static void
1224 FcParseDouble (FcConfigParse *parse)
1225 {
1226 FcChar8 *s, *end;
1227 double d;
1228
1229 if (!parse->pstack)
1230 return;
1231 s = FcStrBufDoneStatic (&parse->pstack->str);
1232 if (!s)
1233 {
1234 FcConfigMessage (parse, FcSevereError, "out of memory");
1235 return;
1236 }
1237 end = 0;
1238 d = FcStrtod ((char *) s, (char **)&end);
1239 if (end != s + strlen ((char *) s))
1240 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1241 else
1242 FcVStackPushDouble (parse, d);
1243 FcStrBufDestroy (&parse->pstack->str);
1244 }
1245
1246 static void
1247 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1248 {
1249 FcChar8 *s;
1250
1251 if (!parse->pstack)
1252 return;
1253 s = FcStrBufDone (&parse->pstack->str);
1254 if (!s)
1255 {
1256 FcConfigMessage (parse, FcSevereError, "out of memory");
1257 return;
1258 }
1259 if (!FcVStackPushString (parse, tag, s))
1260 FcStrFree (s);
1261 }
1262
1263 static void
1264 FcParseMatrix (FcConfigParse *parse)
1265 {
1266 FcVStack *vstack;
1267 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1268 FcMatrix m;
1269
1270 while ((vstack = FcVStackPeek (parse)))
1271 {
1272 double v;
1273 switch (vstack->tag) {
1274 case FcVStackInteger:
1275 v = vstack->u.integer;
1276 break;
1277 case FcVStackDouble:
1278 v = vstack->u._double;
1279 break;
1280 default:
1281 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1282 v = 1.0;
1283 break;
1284 }
1285 switch (matrix_state) {
1286 case m_xx: m.xx = v; break;
1287 case m_xy: m.xy = v; break;
1288 case m_yx: m.yx = v; break;
1289 case m_yy: m.yy = v; break;
1290 default: break;
1291 }
1292 FcVStackPopAndDestroy (parse);
1293 matrix_state--;
1294 }
1295 if (matrix_state != m_done)
1296 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1297 else
1298 FcVStackPushMatrix (parse, &m);
1299 }
1300
1301 static void
1302 FcParseRange (FcConfigParse *parse)
1303 {
1304 FcVStack *vstack;
1305 FcRange r;
1306 FcChar32 n;
1307 int count = 1;
1308
1309 while ((vstack = FcVStackPeek (parse)))
1310 {
1311 if (count < 0)
1312 {
1313 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1314 return;
1315 }
1316 switch (vstack->tag) {
1317 case FcVStackInteger:
1318 n = vstack->u.integer;
1319 break;
1320 default:
1321 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1322 break;
1323 }
1324 if (count == 1)
1325 r.end = n;
1326 else
1327 r.begin = n;
1328 count--;
1329 FcVStackPopAndDestroy (parse);
1330 }
1331 if (count < 0)
1332 {
1333 if (r.begin > r.end)
1334 {
1335 FcConfigMessage (parse, FcSevereError, "invalid range");
1336 return;
1337 }
1338 FcVStackPushRange (parse, &r);
1339 }
1340 else
1341 FcConfigMessage (parse, FcSevereError, "invalid range");
1342 }
1343
1344 static FcBool
1345 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1346 {
1347 FcBool result = FcFalse;
1348
1349 if (!FcNameBool (bool_, &result))
1350 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1351 bool_);
1352 return result;
1353 }
1354
1355 static void
1356 FcParseBool (FcConfigParse *parse)
1357 {
1358 FcChar8 *s;
1359
1360 if (!parse->pstack)
1361 return;
1362 s = FcStrBufDoneStatic (&parse->pstack->str);
1363 if (!s)
1364 {
1365 FcConfigMessage (parse, FcSevereError, "out of memory");
1366 return;
1367 }
1368 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1369 FcStrBufDestroy (&parse->pstack->str);
1370 }
1371
1372 static void
1373 FcParseCharSet (FcConfigParse *parse)
1374 {
1375 FcVStack *vstack;
1376 FcCharSet *charset = FcCharSetCreate ();
1377 FcChar32 i;
1378 int n = 0;
1379
1380 while ((vstack = FcVStackPeek (parse)))
1381 {
1382 switch (vstack->tag) {
1383 case FcVStackInteger:
1384 if (!FcCharSetAddChar (charset, vstack->u.integer))
1385 {
1386 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1387 }
1388 else
1389 n++;
1390 break;
1391 case FcVStackRange:
1392 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1393 {
1394 if (!FcCharSetAddChar (charset, i))
1395 {
1396 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1397 }
1398 else
1399 n++;
1400 }
1401 break;
1402 default:
1403 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1404 break;
1405 }
1406 FcVStackPopAndDestroy (parse);
1407 }
1408 if (n > 0)
1409 FcVStackPushCharSet (parse, charset);
1410 else
1411 FcCharSetDestroy (charset);
1412 }
1413
1414 static FcBool
1415 FcConfigLexBinding (FcConfigParse *parse,
1416 const FcChar8 *binding_string,
1417 FcValueBinding *binding_ret)
1418 {
1419 FcValueBinding binding;
1420
1421 if (!binding_string)
1422 binding = FcValueBindingWeak;
1423 else
1424 {
1425 if (!strcmp ((char *) binding_string, "weak"))
1426 binding = FcValueBindingWeak;
1427 else if (!strcmp ((char *) binding_string, "strong"))
1428 binding = FcValueBindingStrong;
1429 else if (!strcmp ((char *) binding_string, "same"))
1430 binding = FcValueBindingSame;
1431 else
1432 {
1433 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1434 return FcFalse;
1435 }
1436 }
1437 *binding_ret = binding;
1438 return FcTrue;
1439 }
1440
1441 static void
1442 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1443 {
1444 FcVStack *vstack;
1445 FcExpr *left, *expr = 0, *new;
1446
1447 while ((vstack = FcVStackPeek (parse)))
1448 {
1449 if (vstack->tag != FcVStackFamily)
1450 {
1451 FcConfigMessage (parse, FcSevereWarning, "non-family");
1452 FcVStackPopAndDestroy (parse);
1453 continue;
1454 }
1455 left = vstack->u.expr;
1456 vstack->tag = FcVStackNone;
1457 FcVStackPopAndDestroy (parse);
1458 if (expr)
1459 {
1460 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1461 if (!new)
1462 {
1463 FcConfigMessage (parse, FcSevereError, "out of memory");
1464 FcExprDestroy (left);
1465 FcExprDestroy (expr);
1466 break;
1467 }
1468 expr = new;
1469 }
1470 else
1471 expr = left;
1472 }
1473 if (expr)
1474 {
1475 if (!FcVStackPushExpr (parse, tag, expr))
1476 {
1477 FcConfigMessage (parse, FcSevereError, "out of memory");
1478 FcExprDestroy (expr);
1479 }
1480 }
1481 }
1482
1483 static void
1484 FcParseFamily (FcConfigParse *parse)
1485 {
1486 FcChar8 *s;
1487 FcExpr *expr;
1488
1489 if (!parse->pstack)
1490 return;
1491 s = FcStrBufDoneStatic (&parse->pstack->str);
1492 if (!s)
1493 {
1494 FcConfigMessage (parse, FcSevereError, "out of memory");
1495 return;
1496 }
1497 expr = FcExprCreateString (parse->config, s);
1498 FcStrBufDestroy (&parse->pstack->str);
1499 if (expr)
1500 FcVStackPushExpr (parse, FcVStackFamily, expr);
1501 }
1502
1503 static void
1504 FcParseAlias (FcConfigParse *parse)
1505 {
1506 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1507 FcEdit *edit = 0, *next;
1508 FcVStack *vstack;
1509 FcTest *test;
1510 FcValueBinding binding;
1511
1512 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1513 return;
1514 while ((vstack = FcVStackPeek (parse)))
1515 {
1516 switch (vstack->tag) {
1517 case FcVStackFamily:
1518 if (family)
1519 {
1520 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1521 if (!new)
1522 FcConfigMessage (parse, FcSevereError, "out of memory");
1523 else
1524 family = new;
1525 }
1526 else
1527 new = vstack->u.expr;
1528 if (new)
1529 {
1530 family = new;
1531 vstack->tag = FcVStackNone;
1532 }
1533 break;
1534 case FcVStackPrefer:
1535 if (prefer)
1536 FcExprDestroy (prefer);
1537 prefer = vstack->u.expr;
1538 vstack->tag = FcVStackNone;
1539 break;
1540 case FcVStackAccept:
1541 if (accept)
1542 FcExprDestroy (accept);
1543 accept = vstack->u.expr;
1544 vstack->tag = FcVStackNone;
1545 break;
1546 case FcVStackDefault:
1547 if (def)
1548 FcExprDestroy (def);
1549 def = vstack->u.expr;
1550 vstack->tag = FcVStackNone;
1551 break;
1552 default:
1553 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1554 break;
1555 }
1556 FcVStackPopAndDestroy (parse);
1557 }
1558 if (!family)
1559 {
1560 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1561 if (prefer)
1562 FcExprDestroy (prefer);
1563 if (accept)
1564 FcExprDestroy (accept);
1565 if (def)
1566 FcExprDestroy (def);
1567 return;
1568 }
1569 if (prefer)
1570 {
1571 edit = FcEditCreate (parse,
1572 FC_FAMILY_OBJECT,
1573 FcOpPrepend,
1574 prefer,
1575 binding);
1576 if (edit)
1577 edit->next = 0;
1578 else
1579 FcExprDestroy (prefer);
1580 }
1581 if (accept)
1582 {
1583 next = edit;
1584 edit = FcEditCreate (parse,
1585 FC_FAMILY_OBJECT,
1586 FcOpAppend,
1587 accept,
1588 binding);
1589 if (edit)
1590 edit->next = next;
1591 else
1592 FcExprDestroy (accept);
1593 }
1594 if (def)
1595 {
1596 next = edit;
1597 edit = FcEditCreate (parse,
1598 FC_FAMILY_OBJECT,
1599 FcOpAppendLast,
1600 def,
1601 binding);
1602 if (edit)
1603 edit->next = next;
1604 else
1605 FcExprDestroy (def);
1606 }
1607 if (edit)
1608 {
1609 test = FcTestCreate (parse, FcMatchPattern,
1610 FcQualAny,
1611 (FcChar8 *) FC_FAMILY,
1612 FcOpEqual,
1613 family);
1614 if (test)
1615 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1616 FcTestDestroy (test);
1617 }
1618 else
1619 FcExprDestroy (family);
1620 }
1621
1622 static FcExpr *
1623 FcPopExpr (FcConfigParse *parse)
1624 {
1625 FcVStack *vstack = FcVStackPeek (parse);
1626 FcExpr *expr = 0;
1627 if (!vstack)
1628 return 0;
1629 switch (vstack->tag) {
1630 case FcVStackNone:
1631 break;
1632 case FcVStackString:
1633 case FcVStackFamily:
1634 expr = FcExprCreateString (parse->config, vstack->u.string);
1635 break;
1636 case FcVStackField:
1637 expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
1638 break;
1639 case FcVStackConstant:
1640 expr = FcExprCreateConst (parse->config, vstack->u.string);
1641 break;
1642 case FcVStackGlob:
1643 /* XXX: What's the correct action here? (CDW) */
1644 break;
1645 case FcVStackPrefer:
1646 case FcVStackAccept:
1647 case FcVStackDefault:
1648 expr = vstack->u.expr;
1649 vstack->tag = FcVStackNone;
1650 break;
1651 case FcVStackInteger:
1652 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1653 break;
1654 case FcVStackDouble:
1655 expr = FcExprCreateDouble (parse->config, vstack->u._double);
1656 break;
1657 case FcVStackMatrix:
1658 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1659 break;
1660 case FcVStackRange:
1661 break;
1662 case FcVStackBool:
1663 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1664 break;
1665 case FcVStackCharSet:
1666 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1667 break;
1668 case FcVStackTest:
1669 break;
1670 case FcVStackExpr:
1671 expr = vstack->u.expr;
1672 vstack->tag = FcVStackNone;
1673 break;
1674 case FcVStackEdit:
1675 break;
1676 default:
1677 break;
1678 }
1679 FcVStackPopAndDestroy (parse);
1680 return expr;
1681 }
1682
1683 /*
1684 * This builds a tree of binary operations. Note
1685 * that every operator is defined so that if only
1686 * a single operand is contained, the value of the
1687 * whole expression is the value of the operand.
1688 *
1689 * This code reduces in that case to returning that
1690 * operand.
1691 */
1692 static FcExpr *
1693 FcPopBinary (FcConfigParse *parse, FcOp op)
1694 {
1695 FcExpr *left, *expr = 0, *new;
1696
1697 while ((left = FcPopExpr (parse)))
1698 {
1699 if (expr)
1700 {
1701 new = FcExprCreateOp (parse->config, left, op, expr);
1702 if (!new)
1703 {
1704 FcConfigMessage (parse, FcSevereError, "out of memory");
1705 FcExprDestroy (left);
1706 FcExprDestroy (expr);
1707 return 0;
1708 }
1709 expr = new;
1710 }
1711 else
1712 expr = left;
1713 }
1714 return expr;
1715 }
1716
1717 static void
1718 FcParseBinary (FcConfigParse *parse, FcOp op)
1719 {
1720 FcExpr *expr = FcPopBinary (parse, op);
1721 if (expr)
1722 FcVStackPushExpr (parse, FcVStackExpr, expr);
1723 }
1724
1725 /*
1726 * This builds a a unary operator, it consumes only
1727 * a single operand
1728 */
1729
1730 static FcExpr *
1731 FcPopUnary (FcConfigParse *parse, FcOp op)
1732 {
1733 FcExpr *operand, *new = 0;
1734
1735 if ((operand = FcPopExpr (parse)))
1736 {
1737 new = FcExprCreateOp (parse->config, operand, op, 0);
1738 if (!new)
1739 {
1740 FcExprDestroy (operand);
1741 FcConfigMessage (parse, FcSevereError, "out of memory");
1742 }
1743 }
1744 return new;
1745 }
1746
1747 static void
1748 FcParseUnary (FcConfigParse *parse, FcOp op)
1749 {
1750 FcExpr *expr = FcPopUnary (parse, op);
1751 if (expr)
1752 FcVStackPushExpr (parse, FcVStackExpr, expr);
1753 }
1754
1755 static void
1756 FcParseInclude (FcConfigParse *parse)
1757 {
1758 FcChar8 *s;
1759 const FcChar8 *i;
1760 FcBool ignore_missing = FcFalse;
1761
1762 s = FcStrBufDoneStatic (&parse->pstack->str);
1763 if (!s)
1764 {
1765 FcConfigMessage (parse, FcSevereError, "out of memory");
1766 return;
1767 }
1768 i = FcConfigGetAttribute (parse, "ignore_missing");
1769 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1770 ignore_missing = FcTrue;
1771 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1772 parse->error = FcTrue;
1773 FcStrBufDestroy (&parse->pstack->str);
1774 }
1775
1776 typedef struct _FcOpMap {
1777 char name[16];
1778 FcOp op;
1779 } FcOpMap;
1780
1781 static FcOp
1782 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1783 {
1784 int i;
1785
1786 for (i = 0; i < nmap; i++)
1787 if (!strcmp ((char *) op, map[i].name))
1788 return map[i].op;
1789 return FcOpInvalid;
1790 }
1791
1792 static const FcOpMap fcCompareOps[] = {
1793 { "eq", FcOpEqual },
1794 { "not_eq", FcOpNotEqual },
1795 { "less", FcOpLess },
1796 { "less_eq", FcOpLessEqual },
1797 { "more", FcOpMore },
1798 { "more_eq", FcOpMoreEqual },
1799 { "contains", FcOpContains },
1800 { "not_contains", FcOpNotContains }
1801 };
1802
1803 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1804
1805 static FcOp
1806 FcConfigLexCompare (const FcChar8 *compare)
1807 {
1808 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1809 }
1810
1811 static void
1812 FcParseTest (FcConfigParse *parse)
1813 {
1814 const FcChar8 *kind_string;
1815 FcMatchKind kind;
1816 const FcChar8 *qual_string;
1817 FcQual qual;
1818 const FcChar8 *name;
1819 const FcChar8 *compare_string;
1820 FcOp compare;
1821 FcExpr *expr;
1822 FcTest *test;
1823
1824 kind_string = FcConfigGetAttribute (parse, "target");
1825 if (!kind_string)
1826 kind = FcMatchDefault;
1827 else
1828 {
1829 if (!strcmp ((char *) kind_string, "pattern"))
1830 kind = FcMatchPattern;
1831 else if (!strcmp ((char *) kind_string, "font"))
1832 kind = FcMatchFont;
1833 else if (!strcmp ((char *) kind_string, "scan"))
1834 kind = FcMatchScan;
1835 else if (!strcmp ((char *) kind_string, "default"))
1836 kind = FcMatchDefault;
1837 else
1838 {
1839 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1840 return;
1841 }
1842 }
1843 qual_string = FcConfigGetAttribute (parse, "qual");
1844 if (!qual_string)
1845 qual = FcQualAny;
1846 else
1847 {
1848 if (!strcmp ((char *) qual_string, "any"))
1849 qual = FcQualAny;
1850 else if (!strcmp ((char *) qual_string, "all"))
1851 qual = FcQualAll;
1852 else if (!strcmp ((char *) qual_string, "first"))
1853 qual = FcQualFirst;
1854 else if (!strcmp ((char *) qual_string, "not_first"))
1855 qual = FcQualNotFirst;
1856 else
1857 {
1858 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1859 return;
1860 }
1861 }
1862 name = FcConfigGetAttribute (parse, "name");
1863 if (!name)
1864 {
1865 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1866 return;
1867 }
1868 compare_string = FcConfigGetAttribute (parse, "compare");
1869 if (!compare_string)
1870 compare = FcOpEqual;
1871 else
1872 {
1873 compare = FcConfigLexCompare (compare_string);
1874 if (compare == FcOpInvalid)
1875 {
1876 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1877 return;
1878 }
1879 }
1880 expr = FcPopBinary (parse, FcOpComma);
1881 if (!expr)
1882 {
1883 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1884 return;
1885 }
1886 test = FcTestCreate (parse, kind, qual, name, compare, expr);
1887 if (!test)
1888 {
1889 FcConfigMessage (parse, FcSevereError, "out of memory");
1890 return;
1891 }
1892 FcVStackPushTest (parse, test);
1893 }
1894
1895 static const FcOpMap fcModeOps[] = {
1896 { "assign", FcOpAssign },
1897 { "assign_replace", FcOpAssignReplace },
1898 { "prepend", FcOpPrepend },
1899 { "prepend_first", FcOpPrependFirst },
1900 { "append", FcOpAppend },
1901 { "append_last", FcOpAppendLast },
1902 };
1903
1904 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1905
1906 static FcOp
1907 FcConfigLexMode (const FcChar8 *mode)
1908 {
1909 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1910 }
1911
1912 static void
1913 FcParseEdit (FcConfigParse *parse)
1914 {
1915 const FcChar8 *name;
1916 const FcChar8 *mode_string;
1917 FcOp mode;
1918 FcValueBinding binding;
1919 FcExpr *expr;
1920 FcEdit *edit;
1921
1922 name = FcConfigGetAttribute (parse, "name");
1923 if (!name)
1924 {
1925 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1926 return;
1927 }
1928 mode_string = FcConfigGetAttribute (parse, "mode");
1929 if (!mode_string)
1930 mode = FcOpAssign;
1931 else
1932 {
1933 mode = FcConfigLexMode (mode_string);
1934 if (mode == FcOpInvalid)
1935 {
1936 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1937 return;
1938 }
1939 }
1940 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1941 return;
1942
1943 expr = FcPopBinary (parse, FcOpComma);
1944 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1945 mode, expr, binding);
1946 if (!edit)
1947 {
1948 FcConfigMessage (parse, FcSevereError, "out of memory");
1949 FcExprDestroy (expr);
1950 return;
1951 }
1952 if (!FcVStackPushEdit (parse, edit))
1953 FcEditDestroy (edit);
1954 }
1955
1956 static void
1957 FcParseMatch (FcConfigParse *parse)
1958 {
1959 const FcChar8 *kind_name;
1960 FcMatchKind kind;
1961 FcTest *test = 0;
1962 FcEdit *edit = 0;
1963 FcVStack *vstack;
1964
1965 kind_name = FcConfigGetAttribute (parse, "target");
1966 if (!kind_name)
1967 kind = FcMatchPattern;
1968 else
1969 {
1970 if (!strcmp ((char *) kind_name, "pattern"))
1971 kind = FcMatchPattern;
1972 else if (!strcmp ((char *) kind_name, "font"))
1973 kind = FcMatchFont;
1974 else if (!strcmp ((char *) kind_name, "scan"))
1975 kind = FcMatchScan;
1976 else
1977 {
1978 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1979 return;
1980 }
1981 }
1982 while ((vstack = FcVStackPeek (parse)))
1983 {
1984 switch (vstack->tag) {
1985 case FcVStackTest:
1986 vstack->u.test->next = test;
1987 test = vstack->u.test;
1988 vstack->tag = FcVStackNone;
1989 break;
1990 case FcVStackEdit:
1991 vstack->u.edit->next = edit;
1992 edit = vstack->u.edit;
1993 vstack->tag = FcVStackNone;
1994 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
1995 {
1996 FcConfigMessage (parse, FcSevereError,
1997 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
1998 FcObjectName(edit->object));
1999 }
2000 break;
2001 default:
2002 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2003 break;
2004 }
2005 FcVStackPopAndDestroy (parse);
2006 }
2007 if (!FcConfigAddEdit (parse->config, test, edit, kind))
2008 FcConfigMessage (parse, FcSevereError, "out of memory");
2009 }
2010
2011 static void
2012 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2013 {
2014 FcVStack *vstack;
2015
2016 while ((vstack = FcVStackPeek (parse)))
2017 {
2018 switch (vstack->tag) {
2019 case FcVStackGlob:
2020 if (!FcConfigGlobAdd (parse->config,
2021 vstack->u.string,
2022 element == FcElementAcceptfont))
2023 {
2024 FcConfigMessage (parse, FcSevereError, "out of memory");
2025 }
2026 break;
2027 case FcVStackPattern:
2028 if (!FcConfigPatternsAdd (parse->config,
2029 vstack->u.pattern,
2030 element == FcElementAcceptfont))
2031 {
2032 FcConfigMessage (parse, FcSevereError, "out of memory");
2033 }
2034 else
2035 vstack->tag = FcVStackNone;
2036 break;
2037 default:
2038 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2039 break;
2040 }
2041 FcVStackPopAndDestroy (parse);
2042 }
2043 }
2044
2045
2046 static FcValue
2047 FcPopValue (FcConfigParse *parse)
2048 {
2049 FcVStack *vstack = FcVStackPeek (parse);
2050 FcValue value;
2051
2052 value.type = FcTypeVoid;
2053
2054 if (!vstack)
2055 return value;
2056
2057 switch (vstack->tag) {
2058 case FcVStackString:
2059 value.u.s = FcStrStaticName (vstack->u.string);
2060 if (value.u.s)
2061 value.type = FcTypeString;
2062 break;
2063 case FcVStackConstant:
2064 if (FcNameConstant (vstack->u.string, &value.u.i))
2065 value.type = FcTypeInteger;
2066 break;
2067 case FcVStackInteger:
2068 value.u.i = vstack->u.integer;
2069 value.type = FcTypeInteger;
2070 break;
2071 case FcVStackDouble:
2072 value.u.d = vstack->u._double;
2073 value.type = FcTypeInteger;
2074 break;
2075 case FcVStackMatrix:
2076 value.u.m = FcMatrixCopy (vstack->u.matrix);
2077 if (value.u.m)
2078 value.type = FcTypeMatrix;
2079 break;
2080 case FcVStackBool:
2081 value.u.b = vstack->u.bool_;
2082 value.type = FcTypeBool;
2083 break;
2084 case FcVStackCharSet:
2085 value.u.c = FcCharSetCopy (vstack->u.charset);
2086 if (value.u.c)
2087 value.type = FcTypeCharSet;
2088 break;
2089 default:
2090 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2091 vstack->tag);
2092 break;
2093 }
2094 FcVStackPopAndDestroy (parse);
2095
2096 return value;
2097 }
2098
2099 static void
2100 FcParsePatelt (FcConfigParse *parse)
2101 {
2102 FcValue value;
2103 FcPattern *pattern = FcPatternCreate ();
2104 const char *name;
2105
2106 if (!pattern)
2107 {
2108 FcConfigMessage (parse, FcSevereError, "out of memory");
2109 return;
2110 }
2111
2112 name = (char *) FcConfigGetAttribute (parse, "name");
2113 if (!name)
2114 {
2115 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2116 FcPatternDestroy (pattern);
2117 return;
2118 }
2119
2120 for (;;)
2121 {
2122 value = FcPopValue (parse);
2123 if (value.type == FcTypeVoid)
2124 break;
2125 if (!FcPatternAdd (pattern, name, value, FcTrue))
2126 {
2127 FcConfigMessage (parse, FcSevereError, "out of memory");
2128 FcValueDestroy(value);
2129 break;
2130 }
2131 FcValueDestroy(value);
2132 }
2133
2134 FcVStackPushPattern (parse, pattern);
2135 }
2136
2137 static void
2138 FcParsePattern (FcConfigParse *parse)
2139 {
2140 FcVStack *vstack;
2141 FcPattern *pattern = FcPatternCreate ();
2142
2143 if (!pattern)
2144 {
2145 FcConfigMessage (parse, FcSevereError, "out of memory");
2146 return;
2147 }
2148
2149 while ((vstack = FcVStackPeek (parse)))
2150 {
2151 switch (vstack->tag) {
2152 case FcVStackPattern:
2153 if (!FcPatternAppend (pattern, vstack->u.pattern))
2154 {
2155 FcConfigMessage (parse, FcSevereError, "out of memory");
2156 FcPatternDestroy (pattern);
2157 return;
2158 }
2159 break;
2160 default:
2161 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2162 break;
2163 }
2164 FcVStackPopAndDestroy (parse);
2165 }
2166
2167 FcVStackPushPattern (parse, pattern);
2168 }
2169
2170 static void
2171 FcEndElement(void *userData, const XML_Char *name)
2172 {
2173 FcConfigParse *parse = userData;
2174 FcChar8 *data;
2175 #ifdef _WIN32
2176 FcChar8 buffer[1000];
2177 #endif
2178
2179 if (!parse->pstack)
2180 return;
2181 switch (parse->pstack->element) {
2182 case FcElementNone:
2183 break;
2184 case FcElementFontconfig:
2185 break;
2186 case FcElementDir:
2187 data = FcStrBufDoneStatic (&parse->pstack->str);
2188 if (!data)
2189 {
2190 FcConfigMessage (parse, FcSevereError, "out of memory");
2191 break;
2192 }
2193 #ifdef _WIN32
2194 if (strcmp (data, "CUSTOMFONTDIR") == 0)
2195 {
2196 char *p;
2197 data = buffer;
2198 if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
2199 {
2200 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2201 break;
2202 }
2203 /*
2204 * Must use the multi-byte aware function to search
2205 * for backslash because East Asian double-byte code
2206 * pages have characters with backslash as the second
2207 * byte.
2208 */
2209 p = _mbsrchr (data, '\\');
2210 if (p) *p = '\0';
2211 strcat (data, "\\fonts");
2212 }
2213 else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2214 {
2215 char *p;
2216 data = buffer;
2217 if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
2218 {
2219 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2220 break;
2221 }
2222 p = _mbsrchr (data, '\\');
2223 if (p) *p = '\0';
2224 strcat (data, "\\..\\share\\fonts");
2225 }
2226 else if (strcmp (data, "WINDOWSFONTDIR") == 0)
2227 {
2228 int rc;
2229 data = buffer;
2230 #if _WIN32_WINNT >= 0x0500
2231 rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
2232 #else
2233 rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
2234 #endif
2235 if (rc == 0 || rc > sizeof (buffer) - 20)
2236 {
2237 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2238 break;
2239 }
2240 if (data [strlen (data) - 1] != '\\')
2241 strcat (data, "\\");
2242 strcat (data, "fonts");
2243 }
2244 #endif
2245 if (strlen ((char *) data) == 0)
2246 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2247 else if (!FcStrUsesHome (data) || FcConfigHome ())
2248 {
2249 if (!FcConfigAddDir (parse->config, data))
2250 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2251 }
2252 FcStrBufDestroy (&parse->pstack->str);
2253 break;
2254 case FcElementCacheDir:
2255 data = FcStrBufDone (&parse->pstack->str);
2256 if (!data)
2257 {
2258 FcConfigMessage (parse, FcSevereError, "out of memory");
2259 break;
2260 }
2261 #ifdef _WIN32
2262 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2263 {
2264 int rc;
2265 FcStrFree (data);
2266 data = malloc (1000);
2267 if (!data)
2268 {
2269 FcConfigMessage (parse, FcSevereError, "out of memory");
2270 break;
2271 }
2272 FcMemAlloc (FC_MEM_STRING, 1000);
2273 rc = GetTempPath (800, data);
2274 if (rc == 0 || rc > 800)
2275 {
2276 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2277 FcStrFree (data);
2278 break;
2279 }
2280 if (data [strlen (data) - 1] != '\\')
2281 strcat (data, "\\");
2282 strcat (data, "fontconfig\\cache");
2283 }
2284 #endif
2285 if (!FcStrUsesHome (data) || FcConfigHome ())
2286 {
2287 if (!FcConfigAddCacheDir (parse->config, data))
2288 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2289 }
2290 FcStrFree (data);
2291 break;
2292
2293 case FcElementCache:
2294 data = FcStrBufDoneStatic (&parse->pstack->str);
2295 if (!data)
2296 {
2297 FcConfigMessage (parse, FcSevereError, "out of memory");
2298 break;
2299 }
2300 /* discard this data; no longer used */
2301 FcStrBufDestroy (&parse->pstack->str);
2302 break;
2303 case FcElementInclude:
2304 FcParseInclude (parse);
2305 break;
2306 case FcElementConfig:
2307 break;
2308 case FcElementMatch:
2309 FcParseMatch (parse);
2310 break;
2311 case FcElementAlias:
2312 FcParseAlias (parse);
2313 break;
2314
2315 case FcElementBlank:
2316 FcParseBlank (parse);
2317 break;
2318 case FcElementRescan:
2319 FcParseRescan (parse);
2320 break;
2321
2322 case FcElementPrefer:
2323 FcParseFamilies (parse, FcVStackPrefer);
2324 break;
2325 case FcElementAccept:
2326 FcParseFamilies (parse, FcVStackAccept);
2327 break;
2328 case FcElementDefault:
2329 FcParseFamilies (parse, FcVStackDefault);
2330 break;
2331 case FcElementFamily:
2332 FcParseFamily (parse);
2333 break;
2334
2335 case FcElementTest:
2336 FcParseTest (parse);
2337 break;
2338 case FcElementEdit:
2339 FcParseEdit (parse);
2340 break;
2341
2342 case FcElementInt:
2343 FcParseInt (parse);
2344 break;
2345 case FcElementDouble:
2346 FcParseDouble (parse);
2347 break;
2348 case FcElementString:
2349 FcParseString (parse, FcVStackString);
2350 break;
2351 case FcElementMatrix:
2352 FcParseMatrix (parse);
2353 break;
2354 case FcElementRange:
2355 FcParseRange (parse);
2356 break;
2357 case FcElementBool:
2358 FcParseBool (parse);
2359 break;
2360 case FcElementCharSet:
2361 FcParseCharSet (parse);
2362 break;
2363 case FcElementSelectfont:
2364 break;
2365 case FcElementAcceptfont:
2366 case FcElementRejectfont:
2367 FcParseAcceptRejectFont (parse, parse->pstack->element);
2368 break;
2369 case FcElementGlob:
2370 FcParseString (parse, FcVStackGlob);
2371 break;
2372 case FcElementPattern:
2373 FcParsePattern (parse);
2374 break;
2375 case FcElementPatelt:
2376 FcParsePatelt (parse);
2377 break;
2378 case FcElementName:
2379 FcParseString (parse, FcVStackField);
2380 break;
2381 case FcElementConst:
2382 FcParseString (parse, FcVStackConstant);
2383 break;
2384 case FcElementOr:
2385 FcParseBinary (parse, FcOpOr);
2386 break;
2387 case FcElementAnd:
2388 FcParseBinary (parse, FcOpAnd);
2389 break;
2390 case FcElementEq:
2391 FcParseBinary (parse, FcOpEqual);
2392 break;
2393 case FcElementNotEq:
2394 FcParseBinary (parse, FcOpNotEqual);
2395 break;
2396 case FcElementLess:
2397 FcParseBinary (parse, FcOpLess);
2398 break;
2399 case FcElementLessEq:
2400 FcParseBinary (parse, FcOpLessEqual);
2401 break;
2402 case FcElementMore:
2403 FcParseBinary (parse, FcOpMore);
2404 break;
2405 case FcElementMoreEq:
2406 FcParseBinary (parse, FcOpMoreEqual);
2407 break;
2408 case FcElementContains:
2409 FcParseBinary (parse, FcOpContains);
2410 break;
2411 case FcElementNotContains:
2412 FcParseBinary (parse, FcOpNotContains);
2413 break;
2414 case FcElementPlus:
2415 FcParseBinary (parse, FcOpPlus);
2416 break;
2417 case FcElementMinus:
2418 FcParseBinary (parse, FcOpMinus);
2419 break;
2420 case FcElementTimes:
2421 FcParseBinary (parse, FcOpTimes);
2422 break;
2423 case FcElementDivide:
2424 FcParseBinary (parse, FcOpDivide);
2425 break;
2426 case FcElementNot:
2427 FcParseUnary (parse, FcOpNot);
2428 break;
2429 case FcElementIf:
2430 FcParseBinary (parse, FcOpQuest);
2431 break;
2432 case FcElementFloor:
2433 FcParseUnary (parse, FcOpFloor);
2434 break;
2435 case FcElementCeil:
2436 FcParseUnary (parse, FcOpCeil);
2437 break;
2438 case FcElementRound:
2439 FcParseUnary (parse, FcOpRound);
2440 break;
2441 case FcElementTrunc:
2442 FcParseUnary (parse, FcOpTrunc);
2443 break;
2444 case FcElementUnknown:
2445 break;
2446 }
2447 (void) FcPStackPop (parse);
2448 }
2449
2450 static void
2451 FcCharacterData (void *userData, const XML_Char *s, int len)
2452 {
2453 FcConfigParse *parse = userData;
2454
2455 if (!parse->pstack)
2456 return;
2457 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2458 FcConfigMessage (parse, FcSevereError, "out of memory");
2459 }
2460
2461 static void
2462 FcStartDoctypeDecl (void *userData,
2463 const XML_Char *doctypeName,
2464 const XML_Char *sysid,
2465 const XML_Char *pubid,
2466 int has_internal_subset)
2467 {
2468 FcConfigParse *parse = userData;
2469
2470 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2471 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2472 }
2473
2474 #ifdef ENABLE_LIBXML2
2475
2476 static void
2477 FcInternalSubsetDecl (void *userData,
2478 const XML_Char *doctypeName,
2479 const XML_Char *sysid,
2480 const XML_Char *pubid)
2481 {
2482 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2483 }
2484
2485 static void
2486 FcExternalSubsetDecl (void *userData,
2487 const XML_Char *doctypeName,
2488 const XML_Char *sysid,
2489 const XML_Char *pubid)
2490 {
2491 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2492 }
2493
2494 #else /* ENABLE_LIBXML2 */
2495
2496 static void
2497 FcEndDoctypeDecl (void *userData)
2498 {
2499 }
2500
2501 #endif /* ENABLE_LIBXML2 */
2502
2503 static int
2504 FcSortCmpStr (const void *a, const void *b)
2505 {
2506 const FcChar8 *as = *((FcChar8 **) a);
2507 const FcChar8 *bs = *((FcChar8 **) b);
2508 return FcStrCmp (as, bs);
2509 }
2510
2511 static FcBool
2512 FcConfigParseAndLoadDir (FcConfig *config,
2513 const FcChar8 *name,
2514 const FcChar8 *dir,
2515 FcBool complain)
2516 {
2517 DIR *d;
2518 struct dirent *e;
2519 FcBool ret = FcTrue;
2520 FcChar8 *file;
2521 FcChar8 *base;
2522 FcStrSet *files;
2523
2524 d = opendir ((char *) dir);
2525 if (!d)
2526 {
2527 if (complain)
2528 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2529 name);
2530 ret = FcFalse;
2531 goto bail0;
2532 }
2533 /* freed below */
2534 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2535 if (!file)
2536 {
2537 ret = FcFalse;
2538 goto bail1;
2539 }
2540
2541 strcpy ((char *) file, (char *) dir);
2542 strcat ((char *) file, "/");
2543 base = file + strlen ((char *) file);
2544
2545 files = FcStrSetCreate ();
2546 if (!files)
2547 {
2548 ret = FcFalse;
2549 goto bail2;
2550 }
2551
2552 if (FcDebug () & FC_DBG_CONFIG)
2553 printf ("\tScanning config dir %s\n", dir);
2554
2555 while (ret && (e = readdir (d)))
2556 {
2557 int d_len;
2558 #define TAIL ".conf"
2559 #define TAIL_LEN 5
2560 /*
2561 * Add all files of the form [0-9]*.conf
2562 */
2563 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2564 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2565 d_len > TAIL_LEN &&
2566 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2567 {
2568 strcpy ((char *) base, (char *) e->d_name);
2569 if (!FcStrSetAdd (files, file))
2570 {
2571 ret = FcFalse;
2572 goto bail3;
2573 }
2574 }
2575 }
2576 if (ret)
2577 {
2578 int i;
2579 qsort (files->strs, files->num, sizeof (FcChar8 *),
2580 (int (*)(const void *, const void *)) FcSortCmpStr);
2581 for (i = 0; ret && i < files->num; i++)
2582 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2583 }
2584 bail3:
2585 FcStrSetDestroy (files);
2586 bail2:
2587 free (file);
2588 bail1:
2589 closedir (d);
2590 bail0:
2591 return ret || !complain;
2592 }
2593
2594 FcBool
2595 FcConfigParseAndLoad (FcConfig *config,
2596 const FcChar8 *name,
2597 FcBool complain)
2598 {
2599
2600 XML_Parser p;
2601 FcChar8 *filename;
2602 int fd;
2603 int len;
2604 FcConfigParse parse;
2605 FcBool error = FcTrue;
2606
2607 #ifdef ENABLE_LIBXML2
2608 xmlSAXHandler sax;
2609 char buf[BUFSIZ];
2610 #else
2611 void *buf;
2612 #endif
2613
2614 filename = FcConfigFilename (name);
2615 if (!filename)
2616 goto bail0;
2617
2618 if (FcStrSetMember (config->configFiles, filename))
2619 {
2620 FcStrFree (filename);
2621 return FcTrue;
2622 }
2623
2624 if (!FcStrSetAdd (config->configFiles, filename))
2625 {
2626 FcStrFree (filename);
2627 goto bail0;
2628 }
2629
2630 if (FcFileIsDir (filename))
2631 {
2632 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2633 FcStrFree (filename);
2634 return ret;
2635 }
2636
2637 if (FcDebug () & FC_DBG_CONFIG)
2638 printf ("\tLoading config file %s\n", filename);
2639
2640 fd = open ((char *) filename, O_RDONLY);
2641 if (fd == -1) {
2642 FcStrFree (filename);
2643 goto bail0;
2644 }
2645
2646 #ifdef ENABLE_LIBXML2
2647 memset(&sax, 0, sizeof(sax));
2648
2649 sax.internalSubset = FcInternalSubsetDecl;
2650 sax.externalSubset = FcExternalSubsetDecl;
2651 sax.startElement = FcStartElement;
2652 sax.endElement = FcEndElement;
2653 sax.characters = FcCharacterData;
2654
2655 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2656 #else
2657 p = XML_ParserCreate ("UTF-8");
2658 #endif
2659 FcStrFree (filename);
2660
2661 if (!p)
2662 goto bail1;
2663
2664 if (!FcConfigInit (&parse, name, config, p))
2665 goto bail2;
2666
2667 #ifndef ENABLE_LIBXML2
2668
2669 XML_SetUserData (p, &parse);
2670
2671 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2672 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2673 XML_SetCharacterDataHandler (p, FcCharacterData);
2674
2675 #endif /* ENABLE_LIBXML2 */
2676
2677 do {
2678 #ifndef ENABLE_LIBXML2
2679 buf = XML_GetBuffer (p, BUFSIZ);
2680 if (!buf)
2681 {
2682 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2683 goto bail3;
2684 }
2685 #endif
2686 len = read (fd, buf, BUFSIZ);
2687 if (len < 0)
2688 {
2689 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2690 goto bail3;
2691 }
2692
2693 #ifdef ENABLE_LIBXML2
2694 if (xmlParseChunk (p, buf, len, len == 0))
2695 #else
2696 if (!XML_ParseBuffer (p, len, len == 0))
2697 #endif
2698 {
2699 FcConfigMessage (&parse, FcSevereError, "%s",
2700 XML_ErrorString (XML_GetErrorCode (p)));
2701 goto bail3;
2702 }
2703 } while (len != 0);
2704 error = parse.error;
2705 bail3:
2706 FcConfigCleanup (&parse);
2707 bail2:
2708 XML_ParserFree (p);
2709 bail1:
2710 close (fd);
2711 fd = -1;
2712 bail0:
2713 if (error && complain)
2714 {
2715 if (name)
2716 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2717 else
2718 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2719 return FcFalse;
2720 }
2721 return FcTrue;
2722 }
2723 #define __fcxml__
2724 #include "fcaliastail.h"
2725 #undef __fcxml__