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