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