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