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