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