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