]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Fix MinGW compilation
[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 _WIN32_WINNT 0x0500
57 #define STRICT
58 #include <windows.h>
59 #undef STRICT
60 #endif
61
62 static void
63 FcExprDestroy (FcExpr *e);
64
65 void
66 FcTestDestroy (FcTest *test)
67 {
68 if (test->next)
69 FcTestDestroy (test->next);
70 FcExprDestroy (test->expr);
71 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
72 free (test);
73 }
74
75 static FcExpr *
76 FcExprCreateInteger (FcConfig *config, int i)
77 {
78 FcExpr *e = FcConfigAllocExpr (config);
79 if (e)
80 {
81 e->op = FcOpInteger;
82 e->u.ival = i;
83 }
84 return e;
85 }
86
87 static FcExpr *
88 FcExprCreateDouble (FcConfig *config, double d)
89 {
90 FcExpr *e = FcConfigAllocExpr (config);
91 if (e)
92 {
93 e->op = FcOpDouble;
94 e->u.dval = d;
95 }
96 return e;
97 }
98
99 static FcExpr *
100 FcExprCreateString (FcConfig *config, const FcChar8 *s)
101 {
102 FcExpr *e = FcConfigAllocExpr (config);
103 if (e)
104 {
105 e->op = FcOpString;
106 e->u.sval = FcStrStaticName (s);
107 }
108 return e;
109 }
110
111 static FcExpr *
112 FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
113 {
114 FcExpr *e = FcConfigAllocExpr (config);
115 if (e)
116 {
117 e->op = FcOpMatrix;
118 e->u.mval = FcMatrixCopy (m);
119 }
120 return e;
121 }
122
123 static FcExpr *
124 FcExprCreateBool (FcConfig *config, FcBool b)
125 {
126 FcExpr *e = FcConfigAllocExpr (config);
127 if (e)
128 {
129 e->op = FcOpBool;
130 e->u.bval = b;
131 }
132 return e;
133 }
134
135 static FcExpr *
136 FcExprCreateNil (FcConfig *config)
137 {
138 FcExpr *e = FcConfigAllocExpr (config);
139 if (e)
140 {
141 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
142 e->op = FcOpNil;
143 }
144 return e;
145 }
146
147 static FcExpr *
148 FcExprCreateField (FcConfig *config, const char *field)
149 {
150 FcExpr *e = FcConfigAllocExpr (config);
151 if (e)
152 {
153 e->op = FcOpField;
154 e->u.object = FcObjectFromName (field);
155 }
156 return e;
157 }
158
159 static FcExpr *
160 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
161 {
162 FcExpr *e = FcConfigAllocExpr (config);
163 if (e)
164 {
165 e->op = FcOpConst;
166 e->u.constant = FcStrStaticName (constant);
167 }
168 return e;
169 }
170
171 static FcExpr *
172 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
173 {
174 FcExpr *e = FcConfigAllocExpr (config);
175 if (e)
176 {
177 e->op = op;
178 e->u.tree.left = left;
179 e->u.tree.right = right;
180 }
181 return e;
182 }
183
184 static void
185 FcExprDestroy (FcExpr *e)
186 {
187 if (!e)
188 return;
189 switch (e->op) {
190 case FcOpInteger:
191 break;
192 case FcOpDouble:
193 break;
194 case FcOpString:
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 break;
208 case FcOpAssign:
209 case FcOpAssignReplace:
210 case FcOpPrepend:
211 case FcOpPrependFirst:
212 case FcOpAppend:
213 case FcOpAppendLast:
214 break;
215 case FcOpOr:
216 case FcOpAnd:
217 case FcOpEqual:
218 case FcOpNotEqual:
219 case FcOpLess:
220 case FcOpLessEqual:
221 case FcOpMore:
222 case FcOpMoreEqual:
223 case FcOpContains:
224 case FcOpListing:
225 case FcOpNotContains:
226 case FcOpPlus:
227 case FcOpMinus:
228 case FcOpTimes:
229 case FcOpDivide:
230 case FcOpQuest:
231 case FcOpComma:
232 FcExprDestroy (e->u.tree.right);
233 /* fall through */
234 case FcOpNot:
235 case FcOpFloor:
236 case FcOpCeil:
237 case FcOpRound:
238 case FcOpTrunc:
239 FcExprDestroy (e->u.tree.left);
240 break;
241 case FcOpNil:
242 case FcOpInvalid:
243 break;
244 }
245
246 e->op = FcOpNil;
247 }
248
249 void
250 FcEditDestroy (FcEdit *e)
251 {
252 if (e->next)
253 FcEditDestroy (e->next);
254 if (e->expr)
255 FcExprDestroy (e->expr);
256 free (e);
257 }
258
259 typedef enum _FcElement {
260 FcElementNone,
261 FcElementFontconfig,
262 FcElementDir,
263 FcElementCacheDir,
264 FcElementCache,
265 FcElementInclude,
266 FcElementConfig,
267 FcElementMatch,
268 FcElementAlias,
269
270 FcElementBlank,
271 FcElementRescan,
272
273 FcElementPrefer,
274 FcElementAccept,
275 FcElementDefault,
276 FcElementFamily,
277
278 FcElementSelectfont,
279 FcElementAcceptfont,
280 FcElementRejectfont,
281 FcElementGlob,
282 FcElementPattern,
283 FcElementPatelt,
284
285 FcElementTest,
286 FcElementEdit,
287 FcElementInt,
288 FcElementDouble,
289 FcElementString,
290 FcElementMatrix,
291 FcElementBool,
292 FcElementCharset,
293 FcElementName,
294 FcElementConst,
295 FcElementOr,
296 FcElementAnd,
297 FcElementEq,
298 FcElementNotEq,
299 FcElementLess,
300 FcElementLessEq,
301 FcElementMore,
302 FcElementMoreEq,
303 FcElementContains,
304 FcElementNotContains,
305 FcElementPlus,
306 FcElementMinus,
307 FcElementTimes,
308 FcElementDivide,
309 FcElementNot,
310 FcElementIf,
311 FcElementFloor,
312 FcElementCeil,
313 FcElementRound,
314 FcElementTrunc,
315 FcElementUnknown
316 } FcElement;
317
318 static const struct {
319 const char name[16];
320 FcElement element;
321 } fcElementMap[] = {
322 { "fontconfig", FcElementFontconfig },
323 { "dir", FcElementDir },
324 { "cachedir", FcElementCacheDir },
325 { "cache", FcElementCache },
326 { "include", FcElementInclude },
327 { "config", FcElementConfig },
328 { "match", FcElementMatch },
329 { "alias", FcElementAlias },
330
331 { "blank", FcElementBlank },
332 { "rescan", FcElementRescan },
333
334 { "prefer", FcElementPrefer },
335 { "accept", FcElementAccept },
336 { "default", FcElementDefault },
337 { "family", FcElementFamily },
338
339 { "selectfont", FcElementSelectfont },
340 { "acceptfont", FcElementAcceptfont },
341 { "rejectfont", FcElementRejectfont },
342 { "glob", FcElementGlob },
343 { "pattern", FcElementPattern },
344 { "patelt", FcElementPatelt },
345
346 { "test", FcElementTest },
347 { "edit", FcElementEdit },
348 { "int", FcElementInt },
349 { "double", FcElementDouble },
350 { "string", FcElementString },
351 { "matrix", FcElementMatrix },
352 { "bool", FcElementBool },
353 { "charset", FcElementCharset },
354 { "name", FcElementName },
355 { "const", FcElementConst },
356 { "or", FcElementOr },
357 { "and", FcElementAnd },
358 { "eq", FcElementEq },
359 { "not_eq", FcElementNotEq },
360 { "less", FcElementLess },
361 { "less_eq", FcElementLessEq },
362 { "more", FcElementMore },
363 { "more_eq", FcElementMoreEq },
364 { "contains", FcElementContains },
365 { "not_contains", FcElementNotContains },
366 { "plus", FcElementPlus },
367 { "minus", FcElementMinus },
368 { "times", FcElementTimes },
369 { "divide", FcElementDivide },
370 { "not", FcElementNot },
371 { "if", FcElementIf },
372 { "floor", FcElementFloor },
373 { "ceil", FcElementCeil },
374 { "round", FcElementRound },
375 { "trunc", FcElementTrunc },
376 };
377 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
378
379 static FcElement
380 FcElementMap (const XML_Char *name)
381 {
382
383 int i;
384 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
385 if (!strcmp ((char *) name, fcElementMap[i].name))
386 return fcElementMap[i].element;
387 return FcElementUnknown;
388 }
389
390 typedef struct _FcPStack {
391 struct _FcPStack *prev;
392 FcElement element;
393 FcChar8 **attr;
394 FcStrBuf str;
395 FcChar8 *attr_buf_static[16];
396 } FcPStack;
397
398 typedef enum _FcVStackTag {
399 FcVStackNone,
400
401 FcVStackString,
402 FcVStackFamily,
403 FcVStackField,
404 FcVStackConstant,
405 FcVStackGlob,
406 FcVStackPattern,
407
408 FcVStackPrefer,
409 FcVStackAccept,
410 FcVStackDefault,
411
412 FcVStackInteger,
413 FcVStackDouble,
414 FcVStackMatrix,
415 FcVStackBool,
416
417 FcVStackTest,
418 FcVStackExpr,
419 FcVStackEdit
420 } FcVStackTag;
421
422 typedef struct _FcVStack {
423 struct _FcVStack *prev;
424 FcPStack *pstack; /* related parse element */
425 FcVStackTag tag;
426 union {
427 FcChar8 *string;
428
429 int integer;
430 double _double;
431 FcMatrix *matrix;
432 FcBool bool_;
433
434 FcTest *test;
435 FcQual qual;
436 FcOp op;
437 FcExpr *expr;
438 FcEdit *edit;
439
440 FcPattern *pattern;
441 } u;
442 } FcVStack;
443
444 typedef struct _FcConfigParse {
445 FcPStack *pstack;
446 FcVStack *vstack;
447 FcBool error;
448 const FcChar8 *name;
449 FcConfig *config;
450 XML_Parser parser;
451 int pstack_static_used;
452 FcPStack pstack_static[8];
453 int vstack_static_used;
454 FcVStack vstack_static[64];
455 } FcConfigParse;
456
457 typedef enum _FcConfigSeverity {
458 FcSevereInfo, FcSevereWarning, FcSevereError
459 } FcConfigSeverity;
460
461 static void
462 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
463 {
464 const char *s = "unknown";
465 va_list args;
466
467 va_start (args, fmt);
468
469 switch (severe) {
470 case FcSevereInfo: s = "info"; break;
471 case FcSevereWarning: s = "warning"; break;
472 case FcSevereError: s = "error"; break;
473 }
474 if (parse)
475 {
476 if (parse->name)
477 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
478 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
479 else
480 fprintf (stderr, "Fontconfig %s: line %d: ", s,
481 (int)XML_GetCurrentLineNumber (parse->parser));
482 if (severe >= FcSevereError)
483 parse->error = FcTrue;
484 }
485 else
486 fprintf (stderr, "Fontconfig %s: ", s);
487 vfprintf (stderr, fmt, args);
488 fprintf (stderr, "\n");
489 va_end (args);
490 }
491
492
493 static const char *
494 FcTypeName (FcType type)
495 {
496 switch (type) {
497 case FcTypeVoid:
498 return "void";
499 case FcTypeInteger:
500 case FcTypeDouble:
501 return "number";
502 case FcTypeString:
503 return "string";
504 case FcTypeBool:
505 return "bool";
506 case FcTypeMatrix:
507 return "matrix";
508 case FcTypeCharSet:
509 return "charset";
510 case FcTypeFTFace:
511 return "FT_Face";
512 case FcTypeLangSet:
513 return "langset";
514 default:
515 return "unknown";
516 }
517 }
518
519 static void
520 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
521 {
522 if (value == FcTypeInteger)
523 value = FcTypeDouble;
524 if (type == FcTypeInteger)
525 type = FcTypeDouble;
526 if (value != type)
527 {
528 if ((value == FcTypeLangSet && type == FcTypeString) ||
529 (value == FcTypeString && type == FcTypeLangSet))
530 return;
531 if (type == (FcType) -1)
532 return;
533 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
534 FcTypeName (value), FcTypeName (type));
535 }
536 }
537
538 static void
539 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
540 {
541 const FcObjectType *o;
542 const FcConstant *c;
543
544 /* If parsing the expression failed, some nodes may be NULL */
545 if (!expr)
546 return;
547
548 switch (expr->op) {
549 case FcOpInteger:
550 case FcOpDouble:
551 FcTypecheckValue (parse, FcTypeDouble, type);
552 break;
553 case FcOpString:
554 FcTypecheckValue (parse, FcTypeString, type);
555 break;
556 case FcOpMatrix:
557 FcTypecheckValue (parse, FcTypeMatrix, type);
558 break;
559 case FcOpBool:
560 FcTypecheckValue (parse, FcTypeBool, type);
561 break;
562 case FcOpCharSet:
563 FcTypecheckValue (parse, FcTypeCharSet, type);
564 break;
565 case FcOpNil:
566 break;
567 case FcOpField:
568 o = FcNameGetObjectType (FcObjectName (expr->u.object));
569 if (o)
570 FcTypecheckValue (parse, o->type, type);
571 break;
572 case FcOpConst:
573 c = FcNameGetConstant (expr->u.constant);
574 if (c)
575 {
576 o = FcNameGetObjectType (c->object);
577 if (o)
578 FcTypecheckValue (parse, o->type, type);
579 }
580 else
581 FcConfigMessage (parse, FcSevereWarning,
582 "invalid constant used : %s",
583 expr->u.constant);
584 break;
585 case FcOpQuest:
586 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
587 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
588 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
589 break;
590 case FcOpAssign:
591 case FcOpAssignReplace:
592 break;
593 case FcOpEqual:
594 case FcOpNotEqual:
595 case FcOpLess:
596 case FcOpLessEqual:
597 case FcOpMore:
598 case FcOpMoreEqual:
599 case FcOpContains:
600 case FcOpNotContains:
601 case FcOpListing:
602 FcTypecheckValue (parse, FcTypeBool, type);
603 break;
604 case FcOpComma:
605 case FcOpOr:
606 case FcOpAnd:
607 case FcOpPlus:
608 case FcOpMinus:
609 case FcOpTimes:
610 case FcOpDivide:
611 FcTypecheckExpr (parse, expr->u.tree.left, type);
612 FcTypecheckExpr (parse, expr->u.tree.right, type);
613 break;
614 case FcOpNot:
615 FcTypecheckValue (parse, FcTypeBool, type);
616 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
617 break;
618 case FcOpFloor:
619 case FcOpCeil:
620 case FcOpRound:
621 case FcOpTrunc:
622 FcTypecheckValue (parse, FcTypeDouble, type);
623 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
624 break;
625 default:
626 break;
627 }
628 }
629
630 static FcTest *
631 FcTestCreate (FcConfigParse *parse,
632 FcMatchKind kind,
633 FcQual qual,
634 const FcChar8 *field,
635 FcOp compare,
636 FcExpr *expr)
637 {
638 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
639
640 if (test)
641 {
642 const FcObjectType *o;
643
644 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
645 test->next = 0;
646 test->kind = kind;
647 test->qual = qual;
648 test->object = FcObjectFromName ((const char *) field);
649 test->op = compare;
650 test->expr = expr;
651 o = FcNameGetObjectType (FcObjectName (test->object));
652 if (o)
653 FcTypecheckExpr (parse, expr, o->type);
654 }
655 return test;
656 }
657
658 static FcEdit *
659 FcEditCreate (FcConfigParse *parse,
660 FcObject object,
661 FcOp op,
662 FcExpr *expr,
663 FcValueBinding binding)
664 {
665 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
666
667 if (e)
668 {
669 const FcObjectType *o;
670
671 e->next = 0;
672 e->object = object;
673 e->op = op;
674 e->expr = expr;
675 e->binding = binding;
676 o = FcNameGetObjectType (FcObjectName (e->object));
677 if (o)
678 FcTypecheckExpr (parse, expr, o->type);
679 }
680 return e;
681 }
682
683 static FcVStack *
684 FcVStackCreateAndPush (FcConfigParse *parse)
685 {
686 FcVStack *new;
687
688 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
689 new = &parse->vstack_static[parse->vstack_static_used++];
690 else
691 {
692 new = malloc (sizeof (FcVStack));
693 if (!new)
694 return 0;
695 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
696 }
697 new->tag = FcVStackNone;
698 new->prev = 0;
699
700 new->prev = parse->vstack;
701 new->pstack = parse->pstack ? parse->pstack->prev : 0;
702 parse->vstack = new;
703
704 return new;
705 }
706
707 static FcBool
708 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
709 {
710 FcVStack *vstack = FcVStackCreateAndPush (parse);
711 if (!vstack)
712 return FcFalse;
713 vstack->u.string = string;
714 vstack->tag = tag;
715 return FcTrue;
716 }
717
718 static FcBool
719 FcVStackPushInteger (FcConfigParse *parse, int integer)
720 {
721 FcVStack *vstack = FcVStackCreateAndPush (parse);
722 if (!vstack)
723 return FcFalse;
724 vstack->u.integer = integer;
725 vstack->tag = FcVStackInteger;
726 return FcTrue;
727 }
728
729 static FcBool
730 FcVStackPushDouble (FcConfigParse *parse, double _double)
731 {
732 FcVStack *vstack = FcVStackCreateAndPush (parse);
733 if (!vstack)
734 return FcFalse;
735 vstack->u._double = _double;
736 vstack->tag = FcVStackDouble;
737 return FcTrue;
738 }
739
740 static FcBool
741 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
742 {
743 FcVStack *vstack;
744 matrix = FcMatrixCopy (matrix);
745 if (!matrix)
746 return FcFalse;
747 vstack = FcVStackCreateAndPush (parse);
748 if (!vstack)
749 return FcFalse;
750 vstack->u.matrix = matrix;
751 vstack->tag = FcVStackMatrix;
752 return FcTrue;
753 }
754
755 static FcBool
756 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
757 {
758 FcVStack *vstack = FcVStackCreateAndPush (parse);
759 if (!vstack)
760 return FcFalse;
761 vstack->u.bool_ = bool_;
762 vstack->tag = FcVStackBool;
763 return FcTrue;
764 }
765
766 static FcBool
767 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
768 {
769 FcVStack *vstack = FcVStackCreateAndPush (parse);
770 if (!vstack)
771 return FcFalse;
772 vstack->u.test = test;
773 vstack->tag = FcVStackTest;
774 return FcTrue;
775 }
776
777 static FcBool
778 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
779 {
780 FcVStack *vstack = FcVStackCreateAndPush (parse);
781 if (!vstack)
782 return FcFalse;
783 vstack->u.expr = expr;
784 vstack->tag = tag;
785 return FcTrue;
786 }
787
788 static FcBool
789 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
790 {
791 FcVStack *vstack = FcVStackCreateAndPush (parse);
792 if (!vstack)
793 return FcFalse;
794 vstack->u.edit = edit;
795 vstack->tag = FcVStackEdit;
796 return FcTrue;
797 }
798
799 static FcBool
800 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
801 {
802 FcVStack *vstack = FcVStackCreateAndPush (parse);
803 if (!vstack)
804 return FcFalse;
805 vstack->u.pattern = pattern;
806 vstack->tag = FcVStackPattern;
807 return FcTrue;
808 }
809
810 static FcVStack *
811 FcVStackFetch (FcConfigParse *parse, int off)
812 {
813 FcVStack *vstack;
814
815 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
816 return vstack;
817 }
818
819 static FcVStack *
820 FcVStackPeek (FcConfigParse *parse)
821 {
822 FcVStack *vstack = parse->vstack;
823
824 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
825 }
826
827 static void
828 FcVStackPopAndDestroy (FcConfigParse *parse)
829 {
830 FcVStack *vstack = parse->vstack;
831
832 if (!vstack || vstack->pstack != parse->pstack)
833 return;
834
835 parse->vstack = vstack->prev;
836
837 switch (vstack->tag) {
838 case FcVStackNone:
839 break;
840 case FcVStackFamily:
841 break;
842 case FcVStackString:
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 = FcStrStaticName (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 = GetSystemWindowsDirectory (data, 800);
2104 if (rc == 0 || rc > 800)
2105 {
2106 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory 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, "GetTempPath 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__