Bug Summary

File:src/fcxml.c
Location:line 1889, column 14
Description:Access to field 'next' results in a dereference of a null pointer (loaded from variable 'r')

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