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