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