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