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