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