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