Bug Summary

File:src/fcxml.c
Location:line 2982, column 5
Description:Value stored to 'fd' is never read

Annotated Source Code

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