]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
[fcstr,fcxml] Don't copy FcStrBuf contents when we would free it soon
[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 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
943 if (!new)
944 return 0;
945 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
946 s = (FcChar8 *) (new + (i + 1));
947 for (i = 0; attr[i]; i++)
948 {
949 new[i] = s;
950 strcpy ((char *) s, (char *) attr[i]);
951 s += strlen ((char *) s) + 1;
952 }
953 new[i] = 0;
954 return new;
955 }
956
957 static FcBool
958 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
959 {
960 FcPStack *new = malloc (sizeof (FcPStack));
961
962 if (!new)
963 return FcFalse;
964 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
965 new->prev = parse->pstack;
966 new->element = element;
967 if (attr)
968 {
969 new->attr = FcConfigSaveAttr (attr);
970 if (!new->attr)
971 {
972 FcConfigMessage (parse, FcSevereError, "out of memory");
973 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
974 free (new);
975 return FcFalse;
976 }
977 }
978 else
979 new->attr = 0;
980 FcStrBufInit (&new->str, 0, 0);
981 parse->pstack = new;
982 return FcTrue;
983 }
984
985 static FcBool
986 FcPStackPop (FcConfigParse *parse)
987 {
988 FcPStack *old;
989
990 if (!parse->pstack)
991 {
992 FcConfigMessage (parse, FcSevereError, "mismatching element");
993 return FcFalse;
994 }
995 FcVStackClear (parse);
996 old = parse->pstack;
997 parse->pstack = old->prev;
998 FcStrBufDestroy (&old->str);
999 if (old->attr)
1000 {
1001 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
1002 free (old->attr);
1003 }
1004 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
1005 free (old);
1006 return FcTrue;
1007 }
1008
1009 static FcBool
1010 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1011 {
1012 parse->pstack = 0;
1013 parse->vstack = 0;
1014 parse->error = FcFalse;
1015 parse->name = name;
1016 parse->config = config;
1017 parse->parser = parser;
1018 return FcTrue;
1019 }
1020
1021 static void
1022 FcConfigCleanup (FcConfigParse *parse)
1023 {
1024 while (parse->pstack)
1025 FcPStackPop (parse);
1026 }
1027
1028 static const FcChar8 *
1029 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1030 {
1031 FcChar8 **attrs;
1032 if (!parse->pstack)
1033 return 0;
1034
1035 attrs = parse->pstack->attr;
1036 if (!attrs)
1037 return 0;
1038
1039 while (*attrs)
1040 {
1041 if (!strcmp ((char *) *attrs, attr))
1042 return attrs[1];
1043 attrs += 2;
1044 }
1045 return 0;
1046 }
1047
1048 static void
1049 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1050 {
1051 FcConfigParse *parse = userData;
1052 FcElement element;
1053
1054 element = FcElementMap (name);
1055 if (element == FcElementUnknown)
1056 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1057
1058 if (!FcPStackPush (parse, element, attr))
1059 {
1060 FcConfigMessage (parse, FcSevereError, "out of memory");
1061 return;
1062 }
1063 return;
1064 }
1065
1066 static void
1067 FcParseBlank (FcConfigParse *parse)
1068 {
1069 int n = FcVStackElements (parse);
1070 while (n-- > 0)
1071 {
1072 FcVStack *v = FcVStackFetch (parse, n);
1073 if (v->tag != FcVStackInteger)
1074 FcConfigMessage (parse, FcSevereError, "non-integer blank");
1075 else
1076 {
1077 if (!parse->config->blanks)
1078 {
1079 parse->config->blanks = FcBlanksCreate ();
1080 if (!parse->config->blanks)
1081 {
1082 FcConfigMessage (parse, FcSevereError, "out of memory");
1083 break;
1084 }
1085 }
1086 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1087 {
1088 FcConfigMessage (parse, FcSevereError, "out of memory");
1089 break;
1090 }
1091 }
1092 }
1093 }
1094
1095 static void
1096 FcParseRescan (FcConfigParse *parse)
1097 {
1098 int n = FcVStackElements (parse);
1099 while (n-- > 0)
1100 {
1101 FcVStack *v = FcVStackFetch (parse, n);
1102 if (v->tag != FcVStackInteger)
1103 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1104 else
1105 parse->config->rescanInterval = v->u.integer;
1106 }
1107 }
1108
1109 static void
1110 FcParseInt (FcConfigParse *parse)
1111 {
1112 FcChar8 *s, *end;
1113 int l;
1114
1115 if (!parse->pstack)
1116 return;
1117 s = FcStrBufDoneStatic (&parse->pstack->str);
1118 if (!s)
1119 {
1120 FcConfigMessage (parse, FcSevereError, "out of memory");
1121 return;
1122 }
1123 end = 0;
1124 l = (int) strtol ((char *) s, (char **)&end, 0);
1125 if (end != s + strlen ((char *) s))
1126 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1127 else
1128 FcVStackPushInteger (parse, l);
1129 FcStrBufDestroy (&parse->pstack->str);
1130 }
1131
1132 /*
1133 * idea copied from glib g_ascii_strtod with
1134 * permission of the author (Alexander Larsson)
1135 */
1136
1137 #include <locale.h>
1138
1139 static double
1140 FcStrtod (char *s, char **end)
1141 {
1142 struct lconv *locale_data;
1143 char *dot;
1144 double v;
1145
1146 /*
1147 * Have to swap the decimal point to match the current locale
1148 * if that locale doesn't use 0x2e
1149 */
1150 if ((dot = strchr (s, 0x2e)) &&
1151 (locale_data = localeconv ()) &&
1152 (locale_data->decimal_point[0] != 0x2e ||
1153 locale_data->decimal_point[1] != 0))
1154 {
1155 char buf[128];
1156 int slen = strlen (s);
1157 int dlen = strlen (locale_data->decimal_point);
1158
1159 if (slen + dlen > (int) sizeof (buf))
1160 {
1161 if (end)
1162 *end = s;
1163 v = 0;
1164 }
1165 else
1166 {
1167 char *buf_end;
1168 /* mantissa */
1169 strncpy (buf, s, dot - s);
1170 /* decimal point */
1171 strcpy (buf + (dot - s), locale_data->decimal_point);
1172 /* rest of number */
1173 strcpy (buf + (dot - s) + dlen, dot + 1);
1174 buf_end = 0;
1175 v = strtod (buf, &buf_end);
1176 if (buf_end) {
1177 buf_end = s + (buf_end - buf);
1178 if (buf_end > dot)
1179 buf_end -= dlen - 1;
1180 }
1181 if (end)
1182 *end = buf_end;
1183 }
1184 }
1185 else
1186 v = strtod (s, end);
1187 return v;
1188 }
1189
1190 static void
1191 FcParseDouble (FcConfigParse *parse)
1192 {
1193 FcChar8 *s, *end;
1194 double d;
1195
1196 if (!parse->pstack)
1197 return;
1198 s = FcStrBufDoneStatic (&parse->pstack->str);
1199 if (!s)
1200 {
1201 FcConfigMessage (parse, FcSevereError, "out of memory");
1202 return;
1203 }
1204 end = 0;
1205 d = FcStrtod ((char *) s, (char **)&end);
1206 if (end != s + strlen ((char *) s))
1207 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1208 else
1209 FcVStackPushDouble (parse, d);
1210 FcStrBufDestroy (&parse->pstack->str);
1211 }
1212
1213 static void
1214 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1215 {
1216 FcChar8 *s;
1217
1218 if (!parse->pstack)
1219 return;
1220 s = FcStrBufDone (&parse->pstack->str);
1221 if (!s)
1222 {
1223 FcConfigMessage (parse, FcSevereError, "out of memory");
1224 return;
1225 }
1226 if (!FcVStackPushString (parse, tag, s))
1227 FcStrFree (s);
1228 }
1229
1230 static void
1231 FcParseMatrix (FcConfigParse *parse)
1232 {
1233 FcVStack *vstack;
1234 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1235 FcMatrix m;
1236
1237 while ((vstack = FcVStackPop (parse)))
1238 {
1239 double v;
1240 switch (vstack->tag) {
1241 case FcVStackInteger:
1242 v = vstack->u.integer;
1243 break;
1244 case FcVStackDouble:
1245 v = vstack->u._double;
1246 break;
1247 default:
1248 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1249 v = 1.0;
1250 break;
1251 }
1252 switch (matrix_state) {
1253 case m_xx: m.xx = v; break;
1254 case m_xy: m.xy = v; break;
1255 case m_yx: m.yx = v; break;
1256 case m_yy: m.yy = v; break;
1257 default: break;
1258 }
1259 FcVStackDestroy (vstack);
1260 matrix_state--;
1261 }
1262 if (matrix_state != m_done)
1263 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1264 else
1265 FcVStackPushMatrix (parse, &m);
1266 }
1267
1268 static FcBool
1269 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1270 {
1271 FcBool result = FcFalse;
1272
1273 if (!FcNameBool (bool_, &result))
1274 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1275 bool_);
1276 return result;
1277 }
1278
1279 static void
1280 FcParseBool (FcConfigParse *parse)
1281 {
1282 FcChar8 *s;
1283
1284 if (!parse->pstack)
1285 return;
1286 s = FcStrBufDoneStatic (&parse->pstack->str);
1287 if (!s)
1288 {
1289 FcConfigMessage (parse, FcSevereError, "out of memory");
1290 return;
1291 }
1292 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1293 FcStrBufDestroy (&parse->pstack->str);
1294 }
1295
1296 static FcBool
1297 FcConfigLexBinding (FcConfigParse *parse,
1298 const FcChar8 *binding_string,
1299 FcValueBinding *binding_ret)
1300 {
1301 FcValueBinding binding;
1302
1303 if (!binding_string)
1304 binding = FcValueBindingWeak;
1305 else
1306 {
1307 if (!strcmp ((char *) binding_string, "weak"))
1308 binding = FcValueBindingWeak;
1309 else if (!strcmp ((char *) binding_string, "strong"))
1310 binding = FcValueBindingStrong;
1311 else if (!strcmp ((char *) binding_string, "same"))
1312 binding = FcValueBindingSame;
1313 else
1314 {
1315 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1316 return FcFalse;
1317 }
1318 }
1319 *binding_ret = binding;
1320 return FcTrue;
1321 }
1322
1323 static void
1324 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1325 {
1326 FcVStack *vstack;
1327 FcExpr *left, *expr = 0, *new;
1328
1329 while ((vstack = FcVStackPop (parse)))
1330 {
1331 if (vstack->tag != FcVStackFamily)
1332 {
1333 FcConfigMessage (parse, FcSevereWarning, "non-family");
1334 FcVStackDestroy (vstack);
1335 continue;
1336 }
1337 left = vstack->u.expr;
1338 vstack->tag = FcVStackNone;
1339 FcVStackDestroy (vstack);
1340 if (expr)
1341 {
1342 new = FcExprCreateOp (left, FcOpComma, expr);
1343 if (!new)
1344 {
1345 FcConfigMessage (parse, FcSevereError, "out of memory");
1346 FcExprDestroy (left);
1347 FcExprDestroy (expr);
1348 break;
1349 }
1350 expr = new;
1351 }
1352 else
1353 expr = left;
1354 }
1355 if (expr)
1356 {
1357 if (!FcVStackPushExpr (parse, tag, expr))
1358 {
1359 FcConfigMessage (parse, FcSevereError, "out of memory");
1360 FcExprDestroy (expr);
1361 }
1362 }
1363 }
1364
1365 static void
1366 FcParseFamily (FcConfigParse *parse)
1367 {
1368 FcChar8 *s;
1369 FcExpr *expr;
1370
1371 if (!parse->pstack)
1372 return;
1373 s = FcStrBufDoneStatic (&parse->pstack->str);
1374 if (!s)
1375 {
1376 FcConfigMessage (parse, FcSevereError, "out of memory");
1377 return;
1378 }
1379 expr = FcExprCreateString (s);
1380 FcStrBufDestroy (&parse->pstack->str);
1381 if (expr)
1382 FcVStackPushExpr (parse, FcVStackFamily, expr);
1383 }
1384
1385 static void
1386 FcParseAlias (FcConfigParse *parse)
1387 {
1388 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1389 FcEdit *edit = 0, *next;
1390 FcVStack *vstack;
1391 FcTest *test;
1392 FcValueBinding binding;
1393
1394 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1395 return;
1396 while ((vstack = FcVStackPop (parse)))
1397 {
1398 switch (vstack->tag) {
1399 case FcVStackFamily:
1400 if (family)
1401 {
1402 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1403 if (!new)
1404 FcConfigMessage (parse, FcSevereError, "out of memory");
1405 else
1406 family = new;
1407 }
1408 else
1409 new = vstack->u.expr;
1410 if (new)
1411 {
1412 family = new;
1413 vstack->tag = FcVStackNone;
1414 }
1415 break;
1416 case FcVStackPrefer:
1417 if (prefer)
1418 FcExprDestroy (prefer);
1419 prefer = vstack->u.expr;
1420 vstack->tag = FcVStackNone;
1421 break;
1422 case FcVStackAccept:
1423 if (accept)
1424 FcExprDestroy (accept);
1425 accept = vstack->u.expr;
1426 vstack->tag = FcVStackNone;
1427 break;
1428 case FcVStackDefault:
1429 if (def)
1430 FcExprDestroy (def);
1431 def = vstack->u.expr;
1432 vstack->tag = FcVStackNone;
1433 break;
1434 default:
1435 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1436 break;
1437 }
1438 FcVStackDestroy (vstack);
1439 }
1440 if (!family)
1441 {
1442 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1443 if (prefer)
1444 FcExprDestroy (prefer);
1445 if (accept)
1446 FcExprDestroy (accept);
1447 if (def)
1448 FcExprDestroy (def);
1449 return;
1450 }
1451 if (prefer)
1452 {
1453 edit = FcEditCreate (parse,
1454 FC_FAMILY_OBJECT,
1455 FcOpPrepend,
1456 prefer,
1457 binding);
1458 if (edit)
1459 edit->next = 0;
1460 else
1461 FcExprDestroy (prefer);
1462 }
1463 if (accept)
1464 {
1465 next = edit;
1466 edit = FcEditCreate (parse,
1467 FC_FAMILY_OBJECT,
1468 FcOpAppend,
1469 accept,
1470 binding);
1471 if (edit)
1472 edit->next = next;
1473 else
1474 FcExprDestroy (accept);
1475 }
1476 if (def)
1477 {
1478 next = edit;
1479 edit = FcEditCreate (parse,
1480 FC_FAMILY_OBJECT,
1481 FcOpAppendLast,
1482 def,
1483 binding);
1484 if (edit)
1485 edit->next = next;
1486 else
1487 FcExprDestroy (def);
1488 }
1489 if (edit)
1490 {
1491 test = FcTestCreate (parse, FcMatchPattern,
1492 FcQualAny,
1493 (FcChar8 *) FC_FAMILY,
1494 FcOpEqual,
1495 family);
1496 if (test)
1497 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1498 FcTestDestroy (test);
1499 }
1500 else
1501 FcExprDestroy (family);
1502 }
1503
1504 static FcExpr *
1505 FcPopExpr (FcConfigParse *parse)
1506 {
1507 FcVStack *vstack = FcVStackPop (parse);
1508 FcExpr *expr = 0;
1509 if (!vstack)
1510 return 0;
1511 switch (vstack->tag) {
1512 case FcVStackNone:
1513 break;
1514 case FcVStackString:
1515 case FcVStackFamily:
1516 expr = FcExprCreateString (vstack->u.string);
1517 break;
1518 case FcVStackField:
1519 expr = FcExprCreateField ((char *) vstack->u.string);
1520 break;
1521 case FcVStackConstant:
1522 expr = FcExprCreateConst (vstack->u.string);
1523 break;
1524 case FcVStackGlob:
1525 /* XXX: What's the correct action here? (CDW) */
1526 break;
1527 case FcVStackPrefer:
1528 case FcVStackAccept:
1529 case FcVStackDefault:
1530 expr = vstack->u.expr;
1531 vstack->tag = FcVStackNone;
1532 break;
1533 case FcVStackInteger:
1534 expr = FcExprCreateInteger (vstack->u.integer);
1535 break;
1536 case FcVStackDouble:
1537 expr = FcExprCreateDouble (vstack->u._double);
1538 break;
1539 case FcVStackMatrix:
1540 expr = FcExprCreateMatrix (vstack->u.matrix);
1541 break;
1542 case FcVStackBool:
1543 expr = FcExprCreateBool (vstack->u.bool_);
1544 break;
1545 case FcVStackTest:
1546 break;
1547 case FcVStackExpr:
1548 expr = vstack->u.expr;
1549 vstack->tag = FcVStackNone;
1550 break;
1551 case FcVStackEdit:
1552 break;
1553 default:
1554 break;
1555 }
1556 FcVStackDestroy (vstack);
1557 return expr;
1558 }
1559
1560 /*
1561 * This builds a tree of binary operations. Note
1562 * that every operator is defined so that if only
1563 * a single operand is contained, the value of the
1564 * whole expression is the value of the operand.
1565 *
1566 * This code reduces in that case to returning that
1567 * operand.
1568 */
1569 static FcExpr *
1570 FcPopBinary (FcConfigParse *parse, FcOp op)
1571 {
1572 FcExpr *left, *expr = 0, *new;
1573
1574 while ((left = FcPopExpr (parse)))
1575 {
1576 if (expr)
1577 {
1578 new = FcExprCreateOp (left, op, expr);
1579 if (!new)
1580 {
1581 FcConfigMessage (parse, FcSevereError, "out of memory");
1582 FcExprDestroy (left);
1583 FcExprDestroy (expr);
1584 return 0;
1585 }
1586 expr = new;
1587 }
1588 else
1589 expr = left;
1590 }
1591 return expr;
1592 }
1593
1594 static void
1595 FcParseBinary (FcConfigParse *parse, FcOp op)
1596 {
1597 FcExpr *expr = FcPopBinary (parse, op);
1598 if (expr)
1599 FcVStackPushExpr (parse, FcVStackExpr, expr);
1600 }
1601
1602 /*
1603 * This builds a a unary operator, it consumes only
1604 * a single operand
1605 */
1606
1607 static FcExpr *
1608 FcPopUnary (FcConfigParse *parse, FcOp op)
1609 {
1610 FcExpr *operand, *new = 0;
1611
1612 if ((operand = FcPopExpr (parse)))
1613 {
1614 new = FcExprCreateOp (operand, op, 0);
1615 if (!new)
1616 {
1617 FcExprDestroy (operand);
1618 FcConfigMessage (parse, FcSevereError, "out of memory");
1619 }
1620 }
1621 return new;
1622 }
1623
1624 static void
1625 FcParseUnary (FcConfigParse *parse, FcOp op)
1626 {
1627 FcExpr *expr = FcPopUnary (parse, op);
1628 if (expr)
1629 FcVStackPushExpr (parse, FcVStackExpr, expr);
1630 }
1631
1632 static void
1633 FcParseInclude (FcConfigParse *parse)
1634 {
1635 FcChar8 *s;
1636 const FcChar8 *i;
1637 FcBool ignore_missing = FcFalse;
1638
1639 s = FcStrBufDoneStatic (&parse->pstack->str);
1640 if (!s)
1641 {
1642 FcConfigMessage (parse, FcSevereError, "out of memory");
1643 return;
1644 }
1645 i = FcConfigGetAttribute (parse, "ignore_missing");
1646 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1647 ignore_missing = FcTrue;
1648 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1649 parse->error = FcTrue;
1650 FcStrBufDestroy (&parse->pstack->str);
1651 }
1652
1653 typedef struct _FcOpMap {
1654 char name[16];
1655 FcOp op;
1656 } FcOpMap;
1657
1658 static FcOp
1659 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1660 {
1661 int i;
1662
1663 for (i = 0; i < nmap; i++)
1664 if (!strcmp ((char *) op, map[i].name))
1665 return map[i].op;
1666 return FcOpInvalid;
1667 }
1668
1669 static const FcOpMap fcCompareOps[] = {
1670 { "eq", FcOpEqual },
1671 { "not_eq", FcOpNotEqual },
1672 { "less", FcOpLess },
1673 { "less_eq", FcOpLessEqual },
1674 { "more", FcOpMore },
1675 { "more_eq", FcOpMoreEqual },
1676 { "contains", FcOpContains },
1677 { "not_contains", FcOpNotContains }
1678 };
1679
1680 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1681
1682 static FcOp
1683 FcConfigLexCompare (const FcChar8 *compare)
1684 {
1685 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1686 }
1687
1688 static void
1689 FcParseTest (FcConfigParse *parse)
1690 {
1691 const FcChar8 *kind_string;
1692 FcMatchKind kind;
1693 const FcChar8 *qual_string;
1694 FcQual qual;
1695 const FcChar8 *name;
1696 const FcChar8 *compare_string;
1697 FcOp compare;
1698 FcExpr *expr;
1699 FcTest *test;
1700
1701 kind_string = FcConfigGetAttribute (parse, "target");
1702 if (!kind_string)
1703 kind = FcMatchDefault;
1704 else
1705 {
1706 if (!strcmp ((char *) kind_string, "pattern"))
1707 kind = FcMatchPattern;
1708 else if (!strcmp ((char *) kind_string, "font"))
1709 kind = FcMatchFont;
1710 else if (!strcmp ((char *) kind_string, "scan"))
1711 kind = FcMatchScan;
1712 else if (!strcmp ((char *) kind_string, "default"))
1713 kind = FcMatchDefault;
1714 else
1715 {
1716 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1717 return;
1718 }
1719 }
1720 qual_string = FcConfigGetAttribute (parse, "qual");
1721 if (!qual_string)
1722 qual = FcQualAny;
1723 else
1724 {
1725 if (!strcmp ((char *) qual_string, "any"))
1726 qual = FcQualAny;
1727 else if (!strcmp ((char *) qual_string, "all"))
1728 qual = FcQualAll;
1729 else if (!strcmp ((char *) qual_string, "first"))
1730 qual = FcQualFirst;
1731 else if (!strcmp ((char *) qual_string, "not_first"))
1732 qual = FcQualNotFirst;
1733 else
1734 {
1735 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1736 return;
1737 }
1738 }
1739 name = FcConfigGetAttribute (parse, "name");
1740 if (!name)
1741 {
1742 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1743 return;
1744 }
1745 compare_string = FcConfigGetAttribute (parse, "compare");
1746 if (!compare_string)
1747 compare = FcOpEqual;
1748 else
1749 {
1750 compare = FcConfigLexCompare (compare_string);
1751 if (compare == FcOpInvalid)
1752 {
1753 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1754 return;
1755 }
1756 }
1757 expr = FcPopBinary (parse, FcOpComma);
1758 if (!expr)
1759 {
1760 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1761 return;
1762 }
1763 test = FcTestCreate (parse, kind, qual, name, compare, expr);
1764 if (!test)
1765 {
1766 FcConfigMessage (parse, FcSevereError, "out of memory");
1767 return;
1768 }
1769 FcVStackPushTest (parse, test);
1770 }
1771
1772 static const FcOpMap fcModeOps[] = {
1773 { "assign", FcOpAssign },
1774 { "assign_replace", FcOpAssignReplace },
1775 { "prepend", FcOpPrepend },
1776 { "prepend_first", FcOpPrependFirst },
1777 { "append", FcOpAppend },
1778 { "append_last", FcOpAppendLast },
1779 };
1780
1781 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1782
1783 static FcOp
1784 FcConfigLexMode (const FcChar8 *mode)
1785 {
1786 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1787 }
1788
1789 static void
1790 FcParseEdit (FcConfigParse *parse)
1791 {
1792 const FcChar8 *name;
1793 const FcChar8 *mode_string;
1794 FcOp mode;
1795 FcValueBinding binding;
1796 FcExpr *expr;
1797 FcEdit *edit;
1798
1799 name = FcConfigGetAttribute (parse, "name");
1800 if (!name)
1801 {
1802 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1803 return;
1804 }
1805 mode_string = FcConfigGetAttribute (parse, "mode");
1806 if (!mode_string)
1807 mode = FcOpAssign;
1808 else
1809 {
1810 mode = FcConfigLexMode (mode_string);
1811 if (mode == FcOpInvalid)
1812 {
1813 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1814 return;
1815 }
1816 }
1817 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1818 return;
1819
1820 expr = FcPopBinary (parse, FcOpComma);
1821 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1822 mode, expr, binding);
1823 if (!edit)
1824 {
1825 FcConfigMessage (parse, FcSevereError, "out of memory");
1826 FcExprDestroy (expr);
1827 return;
1828 }
1829 if (!FcVStackPushEdit (parse, edit))
1830 FcEditDestroy (edit);
1831 }
1832
1833 static void
1834 FcParseMatch (FcConfigParse *parse)
1835 {
1836 const FcChar8 *kind_name;
1837 FcMatchKind kind;
1838 FcTest *test = 0;
1839 FcEdit *edit = 0;
1840 FcVStack *vstack;
1841
1842 kind_name = FcConfigGetAttribute (parse, "target");
1843 if (!kind_name)
1844 kind = FcMatchPattern;
1845 else
1846 {
1847 if (!strcmp ((char *) kind_name, "pattern"))
1848 kind = FcMatchPattern;
1849 else if (!strcmp ((char *) kind_name, "font"))
1850 kind = FcMatchFont;
1851 else if (!strcmp ((char *) kind_name, "scan"))
1852 kind = FcMatchScan;
1853 else
1854 {
1855 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1856 return;
1857 }
1858 }
1859 while ((vstack = FcVStackPop (parse)))
1860 {
1861 switch (vstack->tag) {
1862 case FcVStackTest:
1863 vstack->u.test->next = test;
1864 test = vstack->u.test;
1865 vstack->tag = FcVStackNone;
1866 break;
1867 case FcVStackEdit:
1868 vstack->u.edit->next = edit;
1869 edit = vstack->u.edit;
1870 vstack->tag = FcVStackNone;
1871 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
1872 {
1873 FcConfigMessage (parse, FcSevereError,
1874 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
1875 FcObjectName(edit->object));
1876 }
1877 break;
1878 default:
1879 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1880 break;
1881 }
1882 FcVStackDestroy (vstack);
1883 }
1884 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1885 FcConfigMessage (parse, FcSevereError, "out of memory");
1886 }
1887
1888 static void
1889 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1890 {
1891 FcVStack *vstack;
1892
1893 while ((vstack = FcVStackPop (parse)))
1894 {
1895 switch (vstack->tag) {
1896 case FcVStackGlob:
1897 if (!FcConfigGlobAdd (parse->config,
1898 vstack->u.string,
1899 element == FcElementAcceptfont))
1900 {
1901 FcConfigMessage (parse, FcSevereError, "out of memory");
1902 }
1903 break;
1904 case FcVStackPattern:
1905 if (!FcConfigPatternsAdd (parse->config,
1906 vstack->u.pattern,
1907 element == FcElementAcceptfont))
1908 {
1909 FcConfigMessage (parse, FcSevereError, "out of memory");
1910 }
1911 else
1912 vstack->tag = FcVStackNone;
1913 break;
1914 default:
1915 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1916 break;
1917 }
1918 FcVStackDestroy (vstack);
1919 }
1920 }
1921
1922
1923 static FcValue
1924 FcPopValue (FcConfigParse *parse)
1925 {
1926 FcVStack *vstack = FcVStackPop (parse);
1927 FcValue value;
1928
1929 value.type = FcTypeVoid;
1930
1931 if (!vstack)
1932 return value;
1933
1934 switch (vstack->tag) {
1935 case FcVStackString:
1936 value.u.s = FcStrCopy (vstack->u.string);
1937 if (value.u.s)
1938 value.type = FcTypeString;
1939 break;
1940 case FcVStackConstant:
1941 if (FcNameConstant (vstack->u.string, &value.u.i))
1942 value.type = FcTypeInteger;
1943 break;
1944 case FcVStackInteger:
1945 value.u.i = vstack->u.integer;
1946 value.type = FcTypeInteger;
1947 break;
1948 case FcVStackDouble:
1949 value.u.d = vstack->u._double;
1950 value.type = FcTypeInteger;
1951 break;
1952 case FcVStackMatrix:
1953 value.u.m = FcMatrixCopy (vstack->u.matrix);
1954 if (value.u.m)
1955 value.type = FcTypeMatrix;
1956 break;
1957 case FcVStackBool:
1958 value.u.b = vstack->u.bool_;
1959 value.type = FcTypeBool;
1960 break;
1961 default:
1962 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1963 vstack->tag);
1964 break;
1965 }
1966 FcVStackDestroy (vstack);
1967
1968 return value;
1969 }
1970
1971 static void
1972 FcParsePatelt (FcConfigParse *parse)
1973 {
1974 FcValue value;
1975 FcPattern *pattern = FcPatternCreate ();
1976 const char *name;
1977
1978 if (!pattern)
1979 {
1980 FcConfigMessage (parse, FcSevereError, "out of memory");
1981 return;
1982 }
1983
1984 name = (char *) FcConfigGetAttribute (parse, "name");
1985 if (!name)
1986 {
1987 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1988 FcPatternDestroy (pattern);
1989 return;
1990 }
1991
1992 for (;;)
1993 {
1994 value = FcPopValue (parse);
1995 if (value.type == FcTypeVoid)
1996 break;
1997 if (!FcPatternAdd (pattern, name, value, FcTrue))
1998 {
1999 FcConfigMessage (parse, FcSevereError, "out of memory");
2000 FcValueDestroy(value);
2001 break;
2002 }
2003 FcValueDestroy(value);
2004 }
2005
2006 FcVStackPushPattern (parse, pattern);
2007 }
2008
2009 static void
2010 FcParsePattern (FcConfigParse *parse)
2011 {
2012 FcVStack *vstack;
2013 FcPattern *pattern = FcPatternCreate ();
2014
2015 if (!pattern)
2016 {
2017 FcConfigMessage (parse, FcSevereError, "out of memory");
2018 return;
2019 }
2020
2021 while ((vstack = FcVStackPop (parse)))
2022 {
2023 switch (vstack->tag) {
2024 case FcVStackPattern:
2025 if (!FcPatternAppend (pattern, vstack->u.pattern))
2026 {
2027 FcConfigMessage (parse, FcSevereError, "out of memory");
2028 FcPatternDestroy (pattern);
2029 return;
2030 }
2031 break;
2032 default:
2033 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2034 break;
2035 }
2036 FcVStackDestroy (vstack);
2037 }
2038
2039 FcVStackPushPattern (parse, pattern);
2040 }
2041
2042 static void
2043 FcEndElement(void *userData, const XML_Char *name)
2044 {
2045 FcConfigParse *parse = userData;
2046 FcChar8 *data;
2047
2048 if (!parse->pstack)
2049 return;
2050 switch (parse->pstack->element) {
2051 case FcElementNone:
2052 break;
2053 case FcElementFontconfig:
2054 break;
2055 case FcElementDir:
2056 data = FcStrBufDoneStatic (&parse->pstack->str);
2057 if (!data)
2058 {
2059 FcConfigMessage (parse, FcSevereError, "out of memory");
2060 break;
2061 }
2062 #ifdef _WIN32
2063 if (strcmp (data, "CUSTOMFONTDIR") == 0)
2064 {
2065 char *p;
2066 FcStrFree (data);
2067 data = malloc (1000);
2068 if (!data)
2069 {
2070 FcConfigMessage (parse, FcSevereError, "out of memory");
2071 break;
2072 }
2073 FcMemAlloc (FC_MEM_STRING, 1000);
2074 if(!GetModuleFileName(NULL, data, 1000))
2075 {
2076 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2077 FcStrFree (data);
2078 break;
2079 }
2080 p = strrchr (data, '\\');
2081 if (p) *p = '\0';
2082 strcat (data, "\\fonts");
2083 }
2084 else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2085 {
2086 char *p;
2087 FcStrFree (data);
2088 data = malloc (1000);
2089 if (!data)
2090 {
2091 FcConfigMessage (parse, FcSevereError, "out of memory");
2092 break;
2093 }
2094 FcMemAlloc (FC_MEM_STRING, 1000);
2095 if(!GetModuleFileName(NULL, data, 1000))
2096 {
2097 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2098 FcStrFree (data);
2099 break;
2100 }
2101 p = strrchr (data, '\\');
2102 if (p) *p = '\0';
2103 strcat (data, "\\..\\share\\fonts");
2104 }
2105 else if (strcmp (data, "WINDOWSFONTDIR") == 0)
2106 {
2107 int rc;
2108 FcStrFree (data);
2109 data = malloc (1000);
2110 if (!data)
2111 {
2112 FcConfigMessage (parse, FcSevereError, "out of memory");
2113 break;
2114 }
2115 FcMemAlloc (FC_MEM_STRING, 1000);
2116 rc = GetWindowsDirectory (data, 800);
2117 if (rc == 0 || rc > 800)
2118 {
2119 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2120 FcStrFree (data);
2121 break;
2122 }
2123 if (data [strlen (data) - 1] != '\\')
2124 strcat (data, "\\");
2125 strcat (data, "fonts");
2126 }
2127 #endif
2128 if (strlen ((char *) data) == 0)
2129 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2130 else if (!FcStrUsesHome (data) || FcConfigHome ())
2131 {
2132 if (!FcConfigAddDir (parse->config, data))
2133 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2134 }
2135 FcStrBufDestroy (&parse->pstack->str);
2136 break;
2137 case FcElementCacheDir:
2138 data = FcStrBufDone (&parse->pstack->str);
2139 if (!data)
2140 {
2141 FcConfigMessage (parse, FcSevereError, "out of memory");
2142 break;
2143 }
2144 #ifdef _WIN32
2145 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2146 {
2147 int rc;
2148 FcStrFree (data);
2149 data = malloc (1000);
2150 if (!data)
2151 {
2152 FcConfigMessage (parse, FcSevereError, "out of memory");
2153 break;
2154 }
2155 FcMemAlloc (FC_MEM_STRING, 1000);
2156 rc = GetTempPath (800, data);
2157 if (rc == 0 || rc > 800)
2158 {
2159 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2160 FcStrFree (data);
2161 break;
2162 }
2163 if (data [strlen (data) - 1] != '\\')
2164 strcat (data, "\\");
2165 strcat (data, "fontconfig\\cache");
2166 }
2167 #endif
2168 if (!FcStrUsesHome (data) || FcConfigHome ())
2169 {
2170 if (!FcConfigAddCacheDir (parse->config, data))
2171 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2172 }
2173 FcStrFree (data);
2174 break;
2175
2176 case FcElementCache:
2177 data = FcStrBufDoneStatic (&parse->pstack->str);
2178 if (!data)
2179 {
2180 FcConfigMessage (parse, FcSevereError, "out of memory");
2181 break;
2182 }
2183 /* discard this data; no longer used */
2184 FcStrBufDestroy (&parse->pstack->str);
2185 break;
2186 case FcElementInclude:
2187 FcParseInclude (parse);
2188 break;
2189 case FcElementConfig:
2190 break;
2191 case FcElementMatch:
2192 FcParseMatch (parse);
2193 break;
2194 case FcElementAlias:
2195 FcParseAlias (parse);
2196 break;
2197
2198 case FcElementBlank:
2199 FcParseBlank (parse);
2200 break;
2201 case FcElementRescan:
2202 FcParseRescan (parse);
2203 break;
2204
2205 case FcElementPrefer:
2206 FcParseFamilies (parse, FcVStackPrefer);
2207 break;
2208 case FcElementAccept:
2209 FcParseFamilies (parse, FcVStackAccept);
2210 break;
2211 case FcElementDefault:
2212 FcParseFamilies (parse, FcVStackDefault);
2213 break;
2214 case FcElementFamily:
2215 FcParseFamily (parse);
2216 break;
2217
2218 case FcElementTest:
2219 FcParseTest (parse);
2220 break;
2221 case FcElementEdit:
2222 FcParseEdit (parse);
2223 break;
2224
2225 case FcElementInt:
2226 FcParseInt (parse);
2227 break;
2228 case FcElementDouble:
2229 FcParseDouble (parse);
2230 break;
2231 case FcElementString:
2232 FcParseString (parse, FcVStackString);
2233 break;
2234 case FcElementMatrix:
2235 FcParseMatrix (parse);
2236 break;
2237 case FcElementBool:
2238 FcParseBool (parse);
2239 break;
2240 case FcElementCharset:
2241 /* FcParseCharset (parse); */
2242 break;
2243 case FcElementSelectfont:
2244 break;
2245 case FcElementAcceptfont:
2246 case FcElementRejectfont:
2247 FcParseAcceptRejectFont (parse, parse->pstack->element);
2248 break;
2249 case FcElementGlob:
2250 FcParseString (parse, FcVStackGlob);
2251 break;
2252 case FcElementPattern:
2253 FcParsePattern (parse);
2254 break;
2255 case FcElementPatelt:
2256 FcParsePatelt (parse);
2257 break;
2258 case FcElementName:
2259 FcParseString (parse, FcVStackField);
2260 break;
2261 case FcElementConst:
2262 FcParseString (parse, FcVStackConstant);
2263 break;
2264 case FcElementOr:
2265 FcParseBinary (parse, FcOpOr);
2266 break;
2267 case FcElementAnd:
2268 FcParseBinary (parse, FcOpAnd);
2269 break;
2270 case FcElementEq:
2271 FcParseBinary (parse, FcOpEqual);
2272 break;
2273 case FcElementNotEq:
2274 FcParseBinary (parse, FcOpNotEqual);
2275 break;
2276 case FcElementLess:
2277 FcParseBinary (parse, FcOpLess);
2278 break;
2279 case FcElementLessEq:
2280 FcParseBinary (parse, FcOpLessEqual);
2281 break;
2282 case FcElementMore:
2283 FcParseBinary (parse, FcOpMore);
2284 break;
2285 case FcElementMoreEq:
2286 FcParseBinary (parse, FcOpMoreEqual);
2287 break;
2288 case FcElementContains:
2289 FcParseBinary (parse, FcOpContains);
2290 break;
2291 case FcElementNotContains:
2292 FcParseBinary (parse, FcOpNotContains);
2293 break;
2294 case FcElementPlus:
2295 FcParseBinary (parse, FcOpPlus);
2296 break;
2297 case FcElementMinus:
2298 FcParseBinary (parse, FcOpMinus);
2299 break;
2300 case FcElementTimes:
2301 FcParseBinary (parse, FcOpTimes);
2302 break;
2303 case FcElementDivide:
2304 FcParseBinary (parse, FcOpDivide);
2305 break;
2306 case FcElementNot:
2307 FcParseUnary (parse, FcOpNot);
2308 break;
2309 case FcElementIf:
2310 FcParseBinary (parse, FcOpQuest);
2311 break;
2312 case FcElementFloor:
2313 FcParseUnary (parse, FcOpFloor);
2314 break;
2315 case FcElementCeil:
2316 FcParseUnary (parse, FcOpCeil);
2317 break;
2318 case FcElementRound:
2319 FcParseUnary (parse, FcOpRound);
2320 break;
2321 case FcElementTrunc:
2322 FcParseUnary (parse, FcOpTrunc);
2323 break;
2324 case FcElementUnknown:
2325 break;
2326 }
2327 (void) FcPStackPop (parse);
2328 }
2329
2330 static void
2331 FcCharacterData (void *userData, const XML_Char *s, int len)
2332 {
2333 FcConfigParse *parse = userData;
2334
2335 if (!parse->pstack)
2336 return;
2337 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2338 FcConfigMessage (parse, FcSevereError, "out of memory");
2339 }
2340
2341 static void
2342 FcStartDoctypeDecl (void *userData,
2343 const XML_Char *doctypeName,
2344 const XML_Char *sysid,
2345 const XML_Char *pubid,
2346 int has_internal_subset)
2347 {
2348 FcConfigParse *parse = userData;
2349
2350 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2351 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2352 }
2353
2354 #ifdef ENABLE_LIBXML2
2355
2356 static void
2357 FcInternalSubsetDecl (void *userData,
2358 const XML_Char *doctypeName,
2359 const XML_Char *sysid,
2360 const XML_Char *pubid)
2361 {
2362 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2363 }
2364
2365 static void
2366 FcExternalSubsetDecl (void *userData,
2367 const XML_Char *doctypeName,
2368 const XML_Char *sysid,
2369 const XML_Char *pubid)
2370 {
2371 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2372 }
2373
2374 #else /* ENABLE_LIBXML2 */
2375
2376 static void
2377 FcEndDoctypeDecl (void *userData)
2378 {
2379 }
2380
2381 #endif /* ENABLE_LIBXML2 */
2382
2383 static int
2384 FcSortCmpStr (const void *a, const void *b)
2385 {
2386 const FcChar8 *as = *((FcChar8 **) a);
2387 const FcChar8 *bs = *((FcChar8 **) b);
2388 return FcStrCmp (as, bs);
2389 }
2390
2391 static FcBool
2392 FcConfigParseAndLoadDir (FcConfig *config,
2393 const FcChar8 *name,
2394 const FcChar8 *dir,
2395 FcBool complain)
2396 {
2397 DIR *d;
2398 struct dirent *e;
2399 FcBool ret = FcTrue;
2400 FcChar8 *file;
2401 FcChar8 *base;
2402 FcStrSet *files;
2403
2404 d = opendir ((char *) dir);
2405 if (!d)
2406 {
2407 if (complain)
2408 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2409 name);
2410 ret = FcFalse;
2411 goto bail0;
2412 }
2413 /* freed below */
2414 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2415 if (!file)
2416 {
2417 ret = FcFalse;
2418 goto bail1;
2419 }
2420
2421 strcpy ((char *) file, (char *) dir);
2422 strcat ((char *) file, "/");
2423 base = file + strlen ((char *) file);
2424
2425 files = FcStrSetCreate ();
2426 if (!files)
2427 {
2428 ret = FcFalse;
2429 goto bail2;
2430 }
2431
2432 if (FcDebug () & FC_DBG_CONFIG)
2433 printf ("\tScanning config dir %s\n", dir);
2434
2435 while (ret && (e = readdir (d)))
2436 {
2437 int d_len;
2438 #define TAIL ".conf"
2439 #define TAIL_LEN 5
2440 /*
2441 * Add all files of the form [0-9]*.conf
2442 */
2443 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2444 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2445 d_len > TAIL_LEN &&
2446 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2447 {
2448 strcpy ((char *) base, (char *) e->d_name);
2449 if (!FcStrSetAdd (files, file))
2450 {
2451 ret = FcFalse;
2452 goto bail3;
2453 }
2454 }
2455 }
2456 if (ret)
2457 {
2458 int i;
2459 qsort (files->strs, files->num, sizeof (FcChar8 *),
2460 (int (*)(const void *, const void *)) FcSortCmpStr);
2461 for (i = 0; ret && i < files->num; i++)
2462 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2463 }
2464 bail3:
2465 FcStrSetDestroy (files);
2466 bail2:
2467 free (file);
2468 bail1:
2469 closedir (d);
2470 bail0:
2471 return ret || !complain;
2472 }
2473
2474 FcBool
2475 FcConfigParseAndLoad (FcConfig *config,
2476 const FcChar8 *name,
2477 FcBool complain)
2478 {
2479
2480 XML_Parser p;
2481 FcChar8 *filename;
2482 int fd;
2483 int len;
2484 FcConfigParse parse;
2485 FcBool error = FcTrue;
2486
2487 #ifdef ENABLE_LIBXML2
2488 xmlSAXHandler sax;
2489 char buf[BUFSIZ];
2490 #else
2491 void *buf;
2492 #endif
2493
2494 filename = FcConfigFilename (name);
2495 if (!filename)
2496 goto bail0;
2497
2498 if (FcStrSetMember (config->configFiles, filename))
2499 {
2500 FcStrFree (filename);
2501 return FcTrue;
2502 }
2503
2504 if (!FcStrSetAdd (config->configFiles, filename))
2505 {
2506 FcStrFree (filename);
2507 goto bail0;
2508 }
2509
2510 if (FcFileIsDir (filename))
2511 {
2512 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2513 FcStrFree (filename);
2514 return ret;
2515 }
2516
2517 if (FcDebug () & FC_DBG_CONFIG)
2518 printf ("\tLoading config file %s\n", filename);
2519
2520 fd = open ((char *) filename, O_RDONLY);
2521 if (fd == -1) {
2522 FcStrFree (filename);
2523 goto bail0;
2524 }
2525
2526 #ifdef ENABLE_LIBXML2
2527 memset(&sax, 0, sizeof(sax));
2528
2529 sax.internalSubset = FcInternalSubsetDecl;
2530 sax.externalSubset = FcExternalSubsetDecl;
2531 sax.startElement = FcStartElement;
2532 sax.endElement = FcEndElement;
2533 sax.characters = FcCharacterData;
2534
2535 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2536 #else
2537 p = XML_ParserCreate ("UTF-8");
2538 #endif
2539 FcStrFree (filename);
2540
2541 if (!p)
2542 goto bail1;
2543
2544 if (!FcConfigInit (&parse, name, config, p))
2545 goto bail2;
2546
2547 #ifndef ENABLE_LIBXML2
2548
2549 XML_SetUserData (p, &parse);
2550
2551 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2552 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2553 XML_SetCharacterDataHandler (p, FcCharacterData);
2554
2555 #endif /* ENABLE_LIBXML2 */
2556
2557 do {
2558 #ifndef ENABLE_LIBXML2
2559 buf = XML_GetBuffer (p, BUFSIZ);
2560 if (!buf)
2561 {
2562 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2563 goto bail3;
2564 }
2565 #endif
2566 len = read (fd, buf, BUFSIZ);
2567 if (len < 0)
2568 {
2569 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2570 goto bail3;
2571 }
2572
2573 #ifdef ENABLE_LIBXML2
2574 if (xmlParseChunk (p, buf, len, len == 0))
2575 #else
2576 if (!XML_ParseBuffer (p, len, len == 0))
2577 #endif
2578 {
2579 FcConfigMessage (&parse, FcSevereError, "%s",
2580 XML_ErrorString (XML_GetErrorCode (p)));
2581 goto bail3;
2582 }
2583 } while (len != 0);
2584 error = parse.error;
2585 bail3:
2586 FcConfigCleanup (&parse);
2587 bail2:
2588 XML_ParserFree (p);
2589 bail1:
2590 close (fd);
2591 fd = -1;
2592 bail0:
2593 if (error && complain)
2594 {
2595 if (name)
2596 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2597 else
2598 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2599 return FcFalse;
2600 }
2601 return FcTrue;
2602 }
2603 #define __fcxml__
2604 #include "fcaliastail.h"
2605 #undef __fcxml__