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