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