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