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