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