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