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