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