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