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