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