]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Fixed a bug "FcStrtod" in handling some cases with two-byte decimal
[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);
980 if (buf_end > dot)
981 buf_end -= dlen - 1;
982 }
983 if (end)
984 *end = buf_end;
985 }
986 }
987 else
988 v = strtod (s, end);
989 return v;
990 }
991
992 static void
993 FcParseDouble (FcConfigParse *parse)
994 {
995 FcChar8 *s, *end;
996 double d;
997
998 if (!parse->pstack)
999 return;
1000 s = FcStrBufDone (&parse->pstack->str);
1001 if (!s)
1002 {
1003 FcConfigMessage (parse, FcSevereError, "out of memory");
1004 return;
1005 }
1006 end = 0;
1007 d = FcStrtod ((char *) s, (char **)&end);
1008 if (end != s + strlen ((char *) s))
1009 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1010 else
1011 FcVStackPushDouble (parse, d);
1012 FcStrFree (s);
1013 }
1014
1015 static void
1016 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1017 {
1018 FcChar8 *s;
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 if (!FcVStackPushString (parse, tag, s))
1029 FcStrFree (s);
1030 }
1031
1032 static void
1033 FcParseMatrix (FcConfigParse *parse)
1034 {
1035 FcVStack *vstack;
1036 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1037 FcMatrix m;
1038
1039 while ((vstack = FcVStackPop (parse)))
1040 {
1041 double v;
1042 switch (vstack->tag) {
1043 case FcVStackInteger:
1044 v = vstack->u.integer;
1045 break;
1046 case FcVStackDouble:
1047 v = vstack->u._double;
1048 break;
1049 default:
1050 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1051 v = 1.0;
1052 break;
1053 }
1054 switch (matrix_state) {
1055 case m_xx: m.xx = v; break;
1056 case m_xy: m.xy = v; break;
1057 case m_yx: m.yx = v; break;
1058 case m_yy: m.yy = v; break;
1059 default: break;
1060 }
1061 FcVStackDestroy (vstack);
1062 matrix_state--;
1063 }
1064 if (matrix_state != m_done)
1065 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1066 else
1067 FcVStackPushMatrix (parse, &m);
1068 }
1069
1070 static FcBool
1071 FcConfigLexBool (const FcChar8 *bool)
1072 {
1073 if (*bool == 't' || *bool == 'T')
1074 return FcTrue;
1075 if (*bool == 'y' || *bool == 'Y')
1076 return FcTrue;
1077 if (*bool == '1')
1078 return FcTrue;
1079 return FcFalse;
1080 }
1081
1082 static void
1083 FcParseBool (FcConfigParse *parse)
1084 {
1085 FcChar8 *s;
1086
1087 if (!parse->pstack)
1088 return;
1089 s = FcStrBufDone (&parse->pstack->str);
1090 if (!s)
1091 {
1092 FcConfigMessage (parse, FcSevereError, "out of memory");
1093 return;
1094 }
1095 FcVStackPushBool (parse, FcConfigLexBool (s));
1096 FcStrFree (s);
1097 }
1098
1099 static void
1100 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1101 {
1102 FcVStack *vstack;
1103 FcExpr *left, *expr = 0, *new;
1104
1105 while ((vstack = FcVStackPop (parse)))
1106 {
1107 if (vstack->tag != FcVStackFamily)
1108 {
1109 FcConfigMessage (parse, FcSevereWarning, "non-family");
1110 FcVStackDestroy (vstack);
1111 continue;
1112 }
1113 left = vstack->u.expr;
1114 vstack->tag = FcVStackNone;
1115 FcVStackDestroy (vstack);
1116 if (expr)
1117 {
1118 new = FcExprCreateOp (left, FcOpComma, expr);
1119 if (!new)
1120 {
1121 FcConfigMessage (parse, FcSevereError, "out of memory");
1122 FcExprDestroy (left);
1123 FcExprDestroy (expr);
1124 break;
1125 }
1126 expr = new;
1127 }
1128 else
1129 expr = left;
1130 }
1131 if (expr)
1132 {
1133 if (!FcVStackPushExpr (parse, tag, expr))
1134 {
1135 FcConfigMessage (parse, FcSevereError, "out of memory");
1136 if (expr)
1137 FcExprDestroy (expr);
1138 }
1139 }
1140 }
1141
1142 static void
1143 FcParseFamily (FcConfigParse *parse)
1144 {
1145 FcChar8 *s;
1146 FcExpr *expr;
1147
1148 if (!parse->pstack)
1149 return;
1150 s = FcStrBufDone (&parse->pstack->str);
1151 if (!s)
1152 {
1153 FcConfigMessage (parse, FcSevereError, "out of memory");
1154 return;
1155 }
1156 expr = FcExprCreateString (s);
1157 FcStrFree (s);
1158 if (expr)
1159 FcVStackPushExpr (parse, FcVStackFamily, expr);
1160 }
1161
1162 static void
1163 FcParseAlias (FcConfigParse *parse)
1164 {
1165 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1166 FcEdit *edit = 0, *next;
1167 FcVStack *vstack;
1168 FcTest *test;
1169
1170 while ((vstack = FcVStackPop (parse)))
1171 {
1172 switch (vstack->tag) {
1173 case FcVStackFamily:
1174 if (family)
1175 {
1176 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1177 if (!new)
1178 FcConfigMessage (parse, FcSevereError, "out of memory");
1179 else
1180 family = new;
1181 }
1182 else
1183 new = vstack->u.expr;
1184 if (new)
1185 {
1186 family = new;
1187 vstack->tag = FcVStackNone;
1188 }
1189 break;
1190 case FcVStackPrefer:
1191 if (prefer)
1192 FcExprDestroy (prefer);
1193 prefer = vstack->u.expr;
1194 vstack->tag = FcVStackNone;
1195 break;
1196 case FcVStackAccept:
1197 if (accept)
1198 FcExprDestroy (accept);
1199 accept = vstack->u.expr;
1200 vstack->tag = FcVStackNone;
1201 break;
1202 case FcVStackDefault:
1203 if (def)
1204 FcExprDestroy (def);
1205 def = vstack->u.expr;
1206 vstack->tag = FcVStackNone;
1207 break;
1208 default:
1209 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1210 break;
1211 }
1212 FcVStackDestroy (vstack);
1213 }
1214 if (!family)
1215 {
1216 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1217 if (prefer)
1218 FcExprDestroy (prefer);
1219 if (accept)
1220 FcExprDestroy (accept);
1221 if (def)
1222 FcExprDestroy (def);
1223 return;
1224 }
1225 if (prefer)
1226 {
1227 edit = FcEditCreate (FcConfigSaveField ("family"),
1228 FcOpPrepend,
1229 prefer,
1230 FcValueBindingWeak);
1231 if (edit)
1232 edit->next = 0;
1233 else
1234 FcExprDestroy (prefer);
1235 }
1236 if (accept)
1237 {
1238 next = edit;
1239 edit = FcEditCreate (FcConfigSaveField ("family"),
1240 FcOpAppend,
1241 accept,
1242 FcValueBindingWeak);
1243 if (edit)
1244 edit->next = next;
1245 else
1246 FcExprDestroy (accept);
1247 }
1248 if (def)
1249 {
1250 next = edit;
1251 edit = FcEditCreate (FcConfigSaveField ("family"),
1252 FcOpAppendLast,
1253 def,
1254 FcValueBindingWeak);
1255 if (edit)
1256 edit->next = next;
1257 else
1258 FcExprDestroy (def);
1259 }
1260 if (edit)
1261 {
1262 test = FcTestCreate (FcMatchPattern,
1263 FcQualAny,
1264 (FcChar8 *) FC_FAMILY,
1265 FcOpEqual,
1266 family);
1267 if (test)
1268 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1269 FcTestDestroy (test);
1270 }
1271 else
1272 FcExprDestroy (family);
1273 }
1274
1275 static FcExpr *
1276 FcPopExpr (FcConfigParse *parse)
1277 {
1278 FcVStack *vstack = FcVStackPop (parse);
1279 FcExpr *expr = 0;
1280 if (!vstack)
1281 return 0;
1282 switch (vstack->tag) {
1283 case FcVStackNone:
1284 break;
1285 case FcVStackString:
1286 case FcVStackFamily:
1287 expr = FcExprCreateString (vstack->u.string);
1288 break;
1289 case FcVStackField:
1290 expr = FcExprCreateField ((char *) vstack->u.string);
1291 break;
1292 case FcVStackConstant:
1293 expr = FcExprCreateConst (vstack->u.string);
1294 break;
1295 case FcVStackGlob:
1296 /* XXX: What's the correct action here? (CDW) */
1297 break;
1298 case FcVStackPrefer:
1299 case FcVStackAccept:
1300 case FcVStackDefault:
1301 expr = vstack->u.expr;
1302 vstack->tag = FcVStackNone;
1303 break;
1304 case FcVStackInteger:
1305 expr = FcExprCreateInteger (vstack->u.integer);
1306 break;
1307 case FcVStackDouble:
1308 expr = FcExprCreateDouble (vstack->u._double);
1309 break;
1310 case FcVStackMatrix:
1311 expr = FcExprCreateMatrix (vstack->u.matrix);
1312 break;
1313 case FcVStackBool:
1314 expr = FcExprCreateBool (vstack->u.bool);
1315 break;
1316 case FcVStackTest:
1317 break;
1318 case FcVStackExpr:
1319 expr = vstack->u.expr;
1320 vstack->tag = FcVStackNone;
1321 break;
1322 case FcVStackEdit:
1323 break;
1324 }
1325 FcVStackDestroy (vstack);
1326 return expr;
1327 }
1328
1329 /*
1330 * This builds a tree of binary operations. Note
1331 * that every operator is defined so that if only
1332 * a single operand is contained, the value of the
1333 * whole expression is the value of the operand.
1334 *
1335 * This code reduces in that case to returning that
1336 * operand.
1337 */
1338 static FcExpr *
1339 FcPopBinary (FcConfigParse *parse, FcOp op)
1340 {
1341 FcExpr *left, *expr = 0, *new;
1342
1343 while ((left = FcPopExpr (parse)))
1344 {
1345 if (expr)
1346 {
1347 new = FcExprCreateOp (left, op, expr);
1348 if (!new)
1349 {
1350 FcConfigMessage (parse, FcSevereError, "out of memory");
1351 FcExprDestroy (left);
1352 FcExprDestroy (expr);
1353 break;
1354 }
1355 expr = new;
1356 }
1357 else
1358 expr = left;
1359 }
1360 return expr;
1361 }
1362
1363 static void
1364 FcParseBinary (FcConfigParse *parse, FcOp op)
1365 {
1366 FcExpr *expr = FcPopBinary (parse, op);
1367 if (expr)
1368 FcVStackPushExpr (parse, FcVStackExpr, expr);
1369 }
1370
1371 /*
1372 * This builds a a unary operator, it consumes only
1373 * a single operand
1374 */
1375
1376 static FcExpr *
1377 FcPopUnary (FcConfigParse *parse, FcOp op)
1378 {
1379 FcExpr *operand, *new = 0;
1380
1381 if ((operand = FcPopExpr (parse)))
1382 {
1383 new = FcExprCreateOp (operand, op, 0);
1384 if (!new)
1385 {
1386 FcExprDestroy (operand);
1387 FcConfigMessage (parse, FcSevereError, "out of memory");
1388 }
1389 }
1390 return new;
1391 }
1392
1393 static void
1394 FcParseUnary (FcConfigParse *parse, FcOp op)
1395 {
1396 FcExpr *expr = FcPopUnary (parse, op);
1397 if (expr)
1398 FcVStackPushExpr (parse, FcVStackExpr, expr);
1399 }
1400
1401 static void
1402 FcParseInclude (FcConfigParse *parse)
1403 {
1404 FcChar8 *s;
1405 const FcChar8 *i;
1406 FcBool ignore_missing = FcFalse;
1407
1408 s = FcStrBufDone (&parse->pstack->str);
1409 if (!s)
1410 {
1411 FcConfigMessage (parse, FcSevereError, "out of memory");
1412 return;
1413 }
1414 i = FcConfigGetAttribute (parse, "ignore_missing");
1415 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1416 ignore_missing = FcTrue;
1417 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1418 parse->error = FcTrue;
1419 FcStrFree (s);
1420 }
1421
1422 typedef struct _FcOpMap {
1423 char *name;
1424 FcOp op;
1425 } FcOpMap;
1426
1427 static FcOp
1428 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1429 {
1430 int i;
1431
1432 for (i = 0; i < nmap; i++)
1433 if (!strcmp ((char *) op, map[i].name))
1434 return map[i].op;
1435 return FcOpInvalid;
1436 }
1437
1438 static const FcOpMap fcCompareOps[] = {
1439 { "eq", FcOpEqual },
1440 { "not_eq", FcOpNotEqual },
1441 { "less", FcOpLess },
1442 { "less_eq", FcOpLessEqual },
1443 { "more", FcOpMore },
1444 { "more_eq", FcOpMoreEqual },
1445 { "contains", FcOpContains },
1446 { "not_contains", FcOpNotContains }
1447 };
1448
1449 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1450
1451 static FcOp
1452 FcConfigLexCompare (const FcChar8 *compare)
1453 {
1454 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1455 }
1456
1457
1458 static void
1459 FcParseTest (FcConfigParse *parse)
1460 {
1461 const FcChar8 *kind_string;
1462 FcMatchKind kind;
1463 const FcChar8 *qual_string;
1464 FcQual qual;
1465 const FcChar8 *name;
1466 const FcChar8 *compare_string;
1467 FcOp compare;
1468 FcExpr *expr;
1469 FcTest *test;
1470
1471 kind_string = FcConfigGetAttribute (parse, "target");
1472 if (!kind_string)
1473 kind = FcMatchDefault;
1474 else
1475 {
1476 if (!strcmp ((char *) kind_string, "pattern"))
1477 kind = FcMatchPattern;
1478 else if (!strcmp ((char *) kind_string, "font"))
1479 kind = FcMatchFont;
1480 else if (!strcmp ((char *) kind_string, "default"))
1481 kind = FcMatchDefault;
1482 else
1483 {
1484 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1485 return;
1486 }
1487 }
1488 qual_string = FcConfigGetAttribute (parse, "qual");
1489 if (!qual_string)
1490 qual = FcQualAny;
1491 else
1492 {
1493 if (!strcmp ((char *) qual_string, "any"))
1494 qual = FcQualAny;
1495 else if (!strcmp ((char *) qual_string, "all"))
1496 qual = FcQualAll;
1497 else if (!strcmp ((char *) qual_string, "first"))
1498 qual = FcQualFirst;
1499 else if (!strcmp ((char *) qual_string, "not_first"))
1500 qual = FcQualNotFirst;
1501 else
1502 {
1503 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1504 return;
1505 }
1506 }
1507 name = FcConfigGetAttribute (parse, "name");
1508 if (!name)
1509 {
1510 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1511 return;
1512 }
1513 compare_string = FcConfigGetAttribute (parse, "compare");
1514 if (!compare_string)
1515 compare = FcOpEqual;
1516 else
1517 {
1518 compare = FcConfigLexCompare (compare_string);
1519 if (compare == FcOpInvalid)
1520 {
1521 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1522 return;
1523 }
1524 }
1525 expr = FcPopBinary (parse, FcOpComma);
1526 if (!expr)
1527 {
1528 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1529 return;
1530 }
1531 test = FcTestCreate (kind, qual, name, compare, expr);
1532 if (!test)
1533 {
1534 FcConfigMessage (parse, FcSevereError, "out of memory");
1535 return;
1536 }
1537 FcVStackPushTest (parse, test);
1538 }
1539
1540 static const FcOpMap fcModeOps[] = {
1541 { "assign", FcOpAssign },
1542 { "assign_replace", FcOpAssignReplace },
1543 { "prepend", FcOpPrepend },
1544 { "prepend_first", FcOpPrependFirst },
1545 { "append", FcOpAppend },
1546 { "append_last", FcOpAppendLast },
1547 };
1548
1549 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1550
1551 static FcOp
1552 FcConfigLexMode (const FcChar8 *mode)
1553 {
1554 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1555 }
1556
1557 static void
1558 FcParseEdit (FcConfigParse *parse)
1559 {
1560 const FcChar8 *name;
1561 const FcChar8 *mode_string;
1562 const FcChar8 *binding_string;
1563 FcOp mode;
1564 FcValueBinding binding;
1565 FcExpr *expr;
1566 FcEdit *edit;
1567
1568 name = FcConfigGetAttribute (parse, "name");
1569 if (!name)
1570 {
1571 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1572 return;
1573 }
1574 mode_string = FcConfigGetAttribute (parse, "mode");
1575 if (!mode_string)
1576 mode = FcOpAssign;
1577 else
1578 {
1579 mode = FcConfigLexMode (mode_string);
1580 if (mode == FcOpInvalid)
1581 {
1582 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1583 return;
1584 }
1585 }
1586 binding_string = FcConfigGetAttribute (parse, "binding");
1587 if (!binding_string)
1588 binding = FcValueBindingWeak;
1589 else
1590 {
1591 if (!strcmp ((char *) binding_string, "weak"))
1592 binding = FcValueBindingWeak;
1593 else if (!strcmp ((char *) binding_string, "strong"))
1594 binding = FcValueBindingStrong;
1595 else if (!strcmp ((char *) binding_string, "same"))
1596 binding = FcValueBindingSame;
1597 else
1598 {
1599 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1600 return;
1601 }
1602 }
1603 expr = FcPopBinary (parse, FcOpComma);
1604 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
1605 if (!edit)
1606 {
1607 FcConfigMessage (parse, FcSevereError, "out of memory");
1608 FcExprDestroy (expr);
1609 return;
1610 }
1611 if (!FcVStackPushEdit (parse, edit))
1612 FcEditDestroy (edit);
1613 }
1614
1615 static void
1616 FcParseMatch (FcConfigParse *parse)
1617 {
1618 const FcChar8 *kind_name;
1619 FcMatchKind kind;
1620 FcTest *test = 0;
1621 FcEdit *edit = 0;
1622 FcVStack *vstack;
1623
1624 kind_name = FcConfigGetAttribute (parse, "target");
1625 if (!kind_name)
1626 kind = FcMatchPattern;
1627 else
1628 {
1629 if (!strcmp ((char *) kind_name, "pattern"))
1630 kind = FcMatchPattern;
1631 else if (!strcmp ((char *) kind_name, "font"))
1632 kind = FcMatchFont;
1633 else
1634 {
1635 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1636 return;
1637 }
1638 }
1639 while ((vstack = FcVStackPop (parse)))
1640 {
1641 switch (vstack->tag) {
1642 case FcVStackTest:
1643 vstack->u.test->next = test;
1644 test = vstack->u.test;
1645 vstack->tag = FcVStackNone;
1646 break;
1647 case FcVStackEdit:
1648 vstack->u.edit->next = edit;
1649 edit = vstack->u.edit;
1650 vstack->tag = FcVStackNone;
1651 break;
1652 default:
1653 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1654 break;
1655 }
1656 FcVStackDestroy (vstack);
1657 }
1658 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1659 FcConfigMessage (parse, FcSevereError, "out of memory");
1660 }
1661
1662 static void
1663 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1664 {
1665 FcVStack *vstack;
1666
1667 while ((vstack = FcVStackPop (parse)))
1668 {
1669 switch (vstack->tag) {
1670 case FcVStackGlob:
1671 if (!FcConfigGlobAdd (parse->config,
1672 vstack->u.string,
1673 element == FcElementAcceptfont))
1674 {
1675 FcConfigMessage (parse, FcSevereError, "out of memory");
1676 }
1677 break;
1678 default:
1679 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1680 break;
1681 }
1682 FcVStackDestroy (vstack);
1683 }
1684 }
1685
1686 static void
1687 FcEndElement(void *userData, const XML_Char *name)
1688 {
1689 FcConfigParse *parse = userData;
1690 FcChar8 *data;
1691
1692 if (!parse->pstack)
1693 return;
1694 switch (parse->pstack->element) {
1695 case FcElementNone:
1696 break;
1697 case FcElementFontconfig:
1698 break;
1699 case FcElementDir:
1700 data = FcStrBufDone (&parse->pstack->str);
1701 if (!data)
1702 {
1703 FcConfigMessage (parse, FcSevereError, "out of memory");
1704 break;
1705 }
1706 #ifdef _WIN32
1707 if (strcmp (data, "WINDOWSFONTDIR") == 0)
1708 {
1709 int rc;
1710 FcStrFree (data);
1711 data = malloc (1000);
1712 if (!data)
1713 {
1714 FcConfigMessage (parse, FcSevereError, "out of memory");
1715 break;
1716 }
1717 FcMemAlloc (FC_MEM_STRING, 1000);
1718 rc = GetWindowsDirectory (data, 800);
1719 if (rc == 0 || rc > 800)
1720 {
1721 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
1722 FcStrFree (data);
1723 break;
1724 }
1725 if (data [strlen (data) - 1] != '\\')
1726 strcat (data, "\\");
1727 strcat (data, "fonts");
1728 }
1729 #endif
1730 if (!FcStrUsesHome (data) || FcConfigHome ())
1731 {
1732 if (!FcConfigAddDir (parse->config, data))
1733 FcConfigMessage (parse, FcSevereError, "out of memory");
1734 }
1735 FcStrFree (data);
1736 break;
1737 case FcElementCache:
1738 data = FcStrBufDone (&parse->pstack->str);
1739 if (!data)
1740 {
1741 FcConfigMessage (parse, FcSevereError, "out of memory");
1742 break;
1743 }
1744 if (!FcStrUsesHome (data) || FcConfigHome ())
1745 {
1746 if (!FcConfigSetCache (parse->config, data))
1747 FcConfigMessage (parse, FcSevereError, "out of memory");
1748 }
1749 FcStrFree (data);
1750 break;
1751 case FcElementInclude:
1752 FcParseInclude (parse);
1753 break;
1754 case FcElementConfig:
1755 break;
1756 case FcElementMatch:
1757 FcParseMatch (parse);
1758 break;
1759 case FcElementAlias:
1760 FcParseAlias (parse);
1761 break;
1762
1763 case FcElementBlank:
1764 FcParseBlank (parse);
1765 break;
1766 case FcElementRescan:
1767 FcParseRescan (parse);
1768 break;
1769
1770 case FcElementPrefer:
1771 FcParseFamilies (parse, FcVStackPrefer);
1772 break;
1773 case FcElementAccept:
1774 FcParseFamilies (parse, FcVStackAccept);
1775 break;
1776 case FcElementDefault:
1777 FcParseFamilies (parse, FcVStackDefault);
1778 break;
1779 case FcElementFamily:
1780 FcParseFamily (parse);
1781 break;
1782
1783 case FcElementTest:
1784 FcParseTest (parse);
1785 break;
1786 case FcElementEdit:
1787 FcParseEdit (parse);
1788 break;
1789
1790 case FcElementInt:
1791 FcParseInt (parse);
1792 break;
1793 case FcElementDouble:
1794 FcParseDouble (parse);
1795 break;
1796 case FcElementString:
1797 FcParseString (parse, FcVStackString);
1798 break;
1799 case FcElementMatrix:
1800 FcParseMatrix (parse);
1801 break;
1802 case FcElementBool:
1803 FcParseBool (parse);
1804 break;
1805 case FcElementCharset:
1806 /* FcParseCharset (parse); */
1807 break;
1808 case FcElementSelectfont:
1809 break;
1810 case FcElementAcceptfont:
1811 case FcElementRejectfont:
1812 FcParseAcceptRejectFont (parse, parse->pstack->element);
1813 break;
1814 case FcElementGlob:
1815 FcParseString (parse, FcVStackGlob);
1816 break;
1817 case FcElementName:
1818 FcParseString (parse, FcVStackField);
1819 break;
1820 case FcElementConst:
1821 FcParseString (parse, FcVStackConstant);
1822 break;
1823 case FcElementOr:
1824 FcParseBinary (parse, FcOpOr);
1825 break;
1826 case FcElementAnd:
1827 FcParseBinary (parse, FcOpAnd);
1828 break;
1829 case FcElementEq:
1830 FcParseBinary (parse, FcOpEqual);
1831 break;
1832 case FcElementNotEq:
1833 FcParseBinary (parse, FcOpNotEqual);
1834 break;
1835 case FcElementLess:
1836 FcParseBinary (parse, FcOpLess);
1837 break;
1838 case FcElementLessEq:
1839 FcParseBinary (parse, FcOpLessEqual);
1840 break;
1841 case FcElementMore:
1842 FcParseBinary (parse, FcOpMore);
1843 break;
1844 case FcElementMoreEq:
1845 FcParseBinary (parse, FcOpMoreEqual);
1846 break;
1847 case FcElementContains:
1848 FcParseBinary (parse, FcOpContains);
1849 break;
1850 case FcElementNotContains:
1851 FcParseBinary (parse, FcOpNotContains);
1852 break;
1853 case FcElementPlus:
1854 FcParseBinary (parse, FcOpPlus);
1855 break;
1856 case FcElementMinus:
1857 FcParseBinary (parse, FcOpMinus);
1858 break;
1859 case FcElementTimes:
1860 FcParseBinary (parse, FcOpTimes);
1861 break;
1862 case FcElementDivide:
1863 FcParseBinary (parse, FcOpDivide);
1864 break;
1865 case FcElementNot:
1866 FcParseUnary (parse, FcOpNot);
1867 break;
1868 case FcElementIf:
1869 FcParseBinary (parse, FcOpQuest);
1870 break;
1871 case FcElementFloor:
1872 FcParseUnary (parse, FcOpFloor);
1873 break;
1874 case FcElementCeil:
1875 FcParseUnary (parse, FcOpCeil);
1876 break;
1877 case FcElementRound:
1878 FcParseUnary (parse, FcOpRound);
1879 break;
1880 case FcElementTrunc:
1881 FcParseUnary (parse, FcOpTrunc);
1882 break;
1883 case FcElementUnknown:
1884 break;
1885 }
1886 (void) FcPStackPop (parse);
1887 }
1888
1889 static void
1890 FcCharacterData (void *userData, const XML_Char *s, int len)
1891 {
1892 FcConfigParse *parse = userData;
1893
1894 if (!parse->pstack)
1895 return;
1896 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1897 FcConfigMessage (parse, FcSevereError, "out of memory");
1898 }
1899
1900 static void
1901 FcStartDoctypeDecl (void *userData,
1902 const XML_Char *doctypeName,
1903 const XML_Char *sysid,
1904 const XML_Char *pubid,
1905 int has_internal_subset)
1906 {
1907 FcConfigParse *parse = userData;
1908
1909 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1910 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1911 }
1912
1913 static void
1914 FcEndDoctypeDecl (void *userData)
1915 {
1916 }
1917
1918 FcBool
1919 FcConfigParseAndLoad (FcConfig *config,
1920 const FcChar8 *name,
1921 FcBool complain)
1922 {
1923
1924 XML_Parser p;
1925 FcChar8 *filename;
1926 FILE *f;
1927 int len;
1928 void *buf;
1929 FcConfigParse parse;
1930 FcBool error = FcTrue;
1931
1932 filename = FcConfigFilename (name);
1933 if (!filename)
1934 goto bail0;
1935
1936 if (!FcStrSetAdd (config->configFiles, filename))
1937 {
1938 FcStrFree (filename);
1939 goto bail0;
1940 }
1941
1942 f = fopen ((char *) filename, "r");
1943 FcStrFree (filename);
1944 if (!f)
1945 goto bail0;
1946
1947 p = XML_ParserCreate ("UTF-8");
1948 if (!p)
1949 goto bail1;
1950
1951 if (!FcConfigInit (&parse, name, config, p))
1952 goto bail2;
1953
1954 XML_SetUserData (p, &parse);
1955
1956 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1957 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1958 XML_SetCharacterDataHandler (p, FcCharacterData);
1959
1960 do {
1961 buf = XML_GetBuffer (p, BUFSIZ);
1962 if (!buf)
1963 {
1964 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1965 goto bail3;
1966 }
1967 len = fread (buf, 1, BUFSIZ, f);
1968 if (len < 0)
1969 {
1970 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1971 goto bail3;
1972 }
1973 if (!XML_ParseBuffer (p, len, len == 0))
1974 {
1975 FcConfigMessage (&parse, FcSevereError, "%s",
1976 XML_ErrorString (XML_GetErrorCode (p)));
1977 goto bail3;
1978 }
1979 } while (len != 0);
1980 error = parse.error;
1981 bail3:
1982 FcConfigCleanup (&parse);
1983 bail2:
1984 XML_ParserFree (p);
1985 bail1:
1986 fclose (f);
1987 bail0:
1988 if (error && complain)
1989 {
1990 if (name)
1991 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1992 else
1993 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1994 return FcFalse;
1995 }
1996 return FcTrue;
1997 }