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