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