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			if (FcStrUsesHome(vstack->u.string) && FcConfigHome() == NULL)
2964				FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
2965			else
2966				FcConfigMessage (parse, FcSevereError, "out of memory");
2967	    }
2968	    else
2969	    {
2970		if (parse->scanOnly && vstack->u.string)
2971		{
2972		    FcStrFree (vstack->u.string);
2973		    vstack->tag = FcVStackNone;
2974		}
2975	    }
2976	    break;
2977	case FcVStackPattern:
2978	    if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2979							  vstack->u.pattern,
2980							  element == FcElementAcceptfont))
2981	    {
2982		FcConfigMessage (parse, FcSevereError, "out of memory");
2983	    }
2984	    else
2985	    {
2986		if (parse->scanOnly && vstack->u.pattern)
2987		    FcPatternDestroy (vstack->u.pattern);
2988		vstack->tag = FcVStackNone;
2989	    }
2990	    break;
2991	default:
2992	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2993	    break;
2994	}
2995	FcVStackPopAndDestroy (parse);
2996    }
2997}
2998
2999
3000static FcValue
3001FcPopValue (FcConfigParse *parse)
3002{
3003    FcVStack	*vstack = FcVStackPeek (parse);
3004    FcValue	value;
3005
3006    value.type = FcTypeVoid;
3007
3008    if (!vstack)
3009	return value;
3010
3011    switch ((int) vstack->tag) {
3012    case FcVStackString:
3013	value.u.s = FcStrdup (vstack->u.string);
3014	if (value.u.s)
3015	    value.type = FcTypeString;
3016	break;
3017    case FcVStackConstant:
3018	if (FcNameConstant (vstack->u.string, &value.u.i))
3019	    value.type = FcTypeInteger;
3020	break;
3021    case FcVStackInteger:
3022	value.u.i = vstack->u.integer;
3023	value.type = FcTypeInteger;
3024	break;
3025    case FcVStackDouble:
3026	value.u.d = vstack->u._double;
3027	value.type = FcTypeDouble;
3028	break;
3029    case FcVStackBool:
3030	value.u.b = vstack->u.bool_;
3031	value.type = FcTypeBool;
3032	break;
3033    case FcVStackCharSet:
3034	value.u.c = FcCharSetCopy (vstack->u.charset);
3035	if (value.u.c)
3036	    value.type = FcTypeCharSet;
3037	break;
3038    case FcVStackLangSet:
3039	value.u.l = FcLangSetCopy (vstack->u.langset);
3040	if (value.u.l)
3041	    value.type = FcTypeLangSet;
3042	break;
3043    case FcVStackRange:
3044	value.u.r = FcRangeCopy (vstack->u.range);
3045	if (value.u.r)
3046	    value.type = FcTypeRange;
3047	break;
3048    default:
3049	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
3050			 vstack->tag);
3051	break;
3052    }
3053    FcVStackPopAndDestroy (parse);
3054
3055    return value;
3056}
3057
3058static void
3059FcParsePatelt (FcConfigParse *parse)
3060{
3061    FcValue	value;
3062    FcPattern	*pattern = FcPatternCreate ();
3063    const char	*name;
3064
3065    if (!pattern)
3066    {
3067	FcConfigMessage (parse, FcSevereError, "out of memory");
3068	return;
3069    }
3070
3071    name = (char *) FcConfigGetAttribute (parse, "name");
3072    if (!name)
3073    {
3074	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
3075	FcPatternDestroy (pattern);
3076	return;
3077    }
3078
3079    for (;;)
3080    {
3081	value = FcPopValue (parse);
3082	if (value.type == FcTypeVoid)
3083	    break;
3084	if (!FcPatternAdd (pattern, name, value, FcTrue))
3085	{
3086	    FcConfigMessage (parse, FcSevereError, "out of memory");
3087            FcValueDestroy(value);
3088	    break;
3089	}
3090        FcValueDestroy(value);
3091    }
3092
3093    FcVStackPushPattern (parse, pattern);
3094}
3095
3096static void
3097FcParsePattern (FcConfigParse *parse)
3098{
3099    FcVStack	*vstack;
3100    FcPattern	*pattern = FcPatternCreate ();
3101
3102    if (!pattern)
3103    {
3104	FcConfigMessage (parse, FcSevereError, "out of memory");
3105	return;
3106    }
3107
3108    while ((vstack = FcVStackPeek (parse)))
3109    {
3110	switch ((int) vstack->tag) {
3111	case FcVStackPattern:
3112	    if (!FcPatternAppend (pattern, vstack->u.pattern))
3113	    {
3114		FcConfigMessage (parse, FcSevereError, "out of memory");
3115		FcPatternDestroy (pattern);
3116		return;
3117	    }
3118	    break;
3119	default:
3120	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
3121	    break;
3122	}
3123	FcVStackPopAndDestroy (parse);
3124    }
3125
3126    FcVStackPushPattern (parse, pattern);
3127}
3128
3129static void
3130FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
3131{
3132    FcConfigParse   *parse = userData;
3133    FcChar8	    *data;
3134
3135    if (!parse->pstack)
3136	return;
3137    switch (parse->pstack->element) {
3138    case FcElementNone:
3139	break;
3140    case FcElementFontconfig:
3141	break;
3142    case FcElementDir:
3143	FcParseDir (parse);
3144	break;
3145    case FcElementCacheDir:
3146	FcParseCacheDir (parse);
3147	break;
3148    case FcElementCache:
3149	data = FcStrBufDoneStatic (&parse->pstack->str);
3150	if (!data)
3151	{
3152	    FcConfigMessage (parse, FcSevereError, "out of memory");
3153	    break;
3154	}
3155	/* discard this data; no longer used */
3156	FcStrBufDestroy (&parse->pstack->str);
3157	break;
3158    case FcElementInclude:
3159	FcParseInclude (parse);
3160	break;
3161    case FcElementConfig:
3162	break;
3163    case FcElementMatch:
3164	FcParseMatch (parse);
3165	break;
3166    case FcElementAlias:
3167	FcParseAlias (parse);
3168	break;
3169    case FcElementDescription:
3170	FcParseDescription (parse);
3171	break;
3172    case FcElementRemapDir:
3173	FcParseRemapDir (parse);
3174	break;
3175    case FcElementResetDirs:
3176	FcParseResetDirs (parse);
3177	break;
3178
3179    case FcElementRescan:
3180	FcParseRescan (parse);
3181	break;
3182
3183    case FcElementPrefer:
3184	FcParseFamilies (parse, FcVStackPrefer);
3185	break;
3186    case FcElementAccept:
3187	FcParseFamilies (parse, FcVStackAccept);
3188	break;
3189    case FcElementDefault:
3190	FcParseFamilies (parse, FcVStackDefault);
3191	break;
3192    case FcElementFamily:
3193	FcParseFamily (parse);
3194	break;
3195
3196    case FcElementTest:
3197	FcParseTest (parse);
3198	break;
3199    case FcElementEdit:
3200	FcParseEdit (parse);
3201	break;
3202
3203    case FcElementInt:
3204	FcParseInt (parse);
3205	break;
3206    case FcElementDouble:
3207	FcParseDouble (parse);
3208	break;
3209    case FcElementString:
3210	FcParseString (parse, FcVStackString);
3211	break;
3212    case FcElementMatrix:
3213	FcParseMatrix (parse);
3214	break;
3215    case FcElementRange:
3216	FcParseRange (parse);
3217	break;
3218    case FcElementBool:
3219	FcParseBool (parse);
3220	break;
3221    case FcElementCharSet:
3222	FcParseCharSet (parse);
3223	break;
3224    case FcElementLangSet:
3225	FcParseLangSet (parse);
3226	break;
3227    case FcElementSelectfont:
3228	break;
3229    case FcElementAcceptfont:
3230    case FcElementRejectfont:
3231	FcParseAcceptRejectFont (parse, parse->pstack->element);
3232	break;
3233    case FcElementGlob:
3234	FcParseString (parse, FcVStackGlob);
3235	break;
3236    case FcElementPattern:
3237	FcParsePattern (parse);
3238	break;
3239    case FcElementPatelt:
3240	FcParsePatelt (parse);
3241	break;
3242    case FcElementName:
3243	FcParseName (parse);
3244	break;
3245    case FcElementConst:
3246	FcParseString (parse, FcVStackConstant);
3247	break;
3248    case FcElementOr:
3249	FcParseBinary (parse, FcOpOr);
3250	break;
3251    case FcElementAnd:
3252	FcParseBinary (parse, FcOpAnd);
3253	break;
3254    case FcElementEq:
3255	FcParseBinary (parse, FcOpEqual);
3256	break;
3257    case FcElementNotEq:
3258	FcParseBinary (parse, FcOpNotEqual);
3259	break;
3260    case FcElementLess:
3261	FcParseBinary (parse, FcOpLess);
3262	break;
3263    case FcElementLessEq:
3264	FcParseBinary (parse, FcOpLessEqual);
3265	break;
3266    case FcElementMore:
3267	FcParseBinary (parse, FcOpMore);
3268	break;
3269    case FcElementMoreEq:
3270	FcParseBinary (parse, FcOpMoreEqual);
3271	break;
3272    case FcElementContains:
3273	FcParseBinary (parse, FcOpContains);
3274	break;
3275    case FcElementNotContains:
3276	FcParseBinary (parse, FcOpNotContains);
3277	break;
3278    case FcElementPlus:
3279	FcParseBinary (parse, FcOpPlus);
3280	break;
3281    case FcElementMinus:
3282	FcParseBinary (parse, FcOpMinus);
3283	break;
3284    case FcElementTimes:
3285	FcParseBinary (parse, FcOpTimes);
3286	break;
3287    case FcElementDivide:
3288	FcParseBinary (parse, FcOpDivide);
3289	break;
3290    case FcElementNot:
3291	FcParseUnary (parse, FcOpNot);
3292	break;
3293    case FcElementIf:
3294	FcParseBinary (parse, FcOpQuest);
3295	break;
3296    case FcElementFloor:
3297	FcParseUnary (parse, FcOpFloor);
3298	break;
3299    case FcElementCeil:
3300	FcParseUnary (parse, FcOpCeil);
3301	break;
3302    case FcElementRound:
3303	FcParseUnary (parse, FcOpRound);
3304	break;
3305    case FcElementTrunc:
3306	FcParseUnary (parse, FcOpTrunc);
3307	break;
3308    case FcElementUnknown:
3309	break;
3310    }
3311    (void) FcPStackPop (parse);
3312}
3313
3314static void
3315FcCharacterData (void *userData, const XML_Char *s, int len)
3316{
3317    FcConfigParse   *parse = userData;
3318
3319    if (!parse->pstack)
3320	return;
3321    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
3322	FcConfigMessage (parse, FcSevereError, "out of memory");
3323}
3324
3325static void
3326FcStartDoctypeDecl (void	    *userData,
3327		    const XML_Char  *doctypeName,
3328		    const XML_Char  *sysid FC_UNUSED,
3329		    const XML_Char  *pubid FC_UNUSED,
3330		    int		    has_internal_subset FC_UNUSED)
3331{
3332    FcConfigParse   *parse = userData;
3333
3334    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
3335	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3336}
3337
3338#ifdef ENABLE_LIBXML2
3339
3340static void
3341FcInternalSubsetDecl (void            *userData,
3342		      const XML_Char  *doctypeName,
3343		      const XML_Char  *sysid,
3344		      const XML_Char  *pubid)
3345{
3346    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3347}
3348
3349static void
3350FcExternalSubsetDecl (void            *userData,
3351		      const XML_Char  *doctypeName,
3352		      const XML_Char  *sysid,
3353		      const XML_Char  *pubid)
3354{
3355    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3356}
3357
3358#else /* ENABLE_LIBXML2 */
3359
3360static void
3361FcEndDoctypeDecl (void *userData FC_UNUSED)
3362{
3363}
3364
3365#endif /* ENABLE_LIBXML2 */
3366
3367static int
3368FcSortCmpStr (const void *a, const void *b)
3369{
3370    const FcChar8    *as = *((FcChar8 **) a);
3371    const FcChar8    *bs = *((FcChar8 **) b);
3372    return FcStrCmp (as, bs);
3373}
3374
3375static FcBool
3376FcConfigParseAndLoadDir (FcConfig	*config,
3377			 const FcChar8	*name,
3378			 const FcChar8	*dir,
3379			 FcBool		complain,
3380			 FcBool		load)
3381{
3382    DIR		    *d;
3383    struct dirent   *e;
3384    FcBool	    ret = FcTrue;
3385    FcChar8	    *file;
3386    FcChar8	    *base;
3387    FcStrSet	    *files;
3388
3389    d = opendir ((char *) dir);
3390    if (!d)
3391    {
3392	if (complain)
3393	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3394			     name);
3395	ret = FcFalse;
3396	goto bail0;
3397    }
3398    /* freed below */
3399    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3400    if (!file)
3401    {
3402	ret = FcFalse;
3403	goto bail1;
3404    }
3405
3406    strcpy ((char *) file, (char *) dir);
3407    strcat ((char *) file, "/");
3408    base = file + strlen ((char *) file);
3409
3410    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3411    if (!files)
3412    {
3413	ret = FcFalse;
3414	goto bail2;
3415    }
3416
3417    if (FcDebug () & FC_DBG_CONFIG)
3418	printf ("\tScanning config dir %s\n", dir);
3419
3420    if (load)
3421	FcConfigAddConfigDir (config, dir);
3422
3423    while (ret && (e = readdir (d)))
3424    {
3425	int d_len;
3426#define TAIL	    ".conf"
3427#define TAIL_LEN    5
3428	/*
3429	 * Add all files of the form [0-9]*.conf
3430	 */
3431	d_len = strlen (e->d_name);
3432	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3433	    d_len > TAIL_LEN &&
3434	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3435	{
3436	    strcpy ((char *) base, (char *) e->d_name);
3437	    if (!FcStrSetAdd (files, file))
3438	    {
3439		ret = FcFalse;
3440		goto bail3;
3441	    }
3442	}
3443    }
3444    if (ret)
3445    {
3446	int i;
3447	qsort (files->strs, files->num, sizeof (FcChar8 *),
3448	       (int (*)(const void *, const void *)) FcSortCmpStr);
3449	for (i = 0; ret && i < files->num; i++)
3450	    ret = _FcConfigParse (config, files->strs[i], complain, load);
3451    }
3452bail3:
3453    FcStrSetDestroy (files);
3454bail2:
3455    free (file);
3456bail1:
3457    closedir (d);
3458bail0:
3459    return ret || !complain;
3460}
3461
3462static FcBool
3463FcConfigParseAndLoadFromMemoryInternal (FcConfig       *config,
3464					const FcChar8  *filename,
3465					const FcChar8  *buffer,
3466					FcBool         complain,
3467					FcBool         load)
3468{
3469
3470    XML_Parser	    p;
3471    size_t	    len;
3472    FcConfigParse   parse;
3473    FcBool	    error = FcTrue;
3474    FcMatchKind	    k;
3475    FcPtrListIter   liter;
3476
3477#ifdef ENABLE_LIBXML2
3478    xmlSAXHandler   sax;
3479#else
3480    void            *buf;
3481    const FcChar8   *s;
3482    size_t	    buflen;
3483#endif
3484
3485    if (!buffer)
3486	return FcFalse;
3487    len = strlen ((const char *) buffer);
3488    if (FcDebug () & FC_DBG_CONFIG)
3489	printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3490
3491#ifdef ENABLE_LIBXML2
3492    memset(&sax, 0, sizeof(sax));
3493
3494    sax.internalSubset = FcInternalSubsetDecl;
3495    sax.externalSubset = FcExternalSubsetDecl;
3496    sax.startElement = FcStartElement;
3497    sax.endElement = FcEndElement;
3498    sax.characters = FcCharacterData;
3499
3500    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3501#else
3502    p = XML_ParserCreate ("UTF-8");
3503#endif
3504
3505    if (!p)
3506	goto bail1;
3507
3508    if (!FcConfigParseInit (&parse, filename, config, p, load))
3509	goto bail2;
3510
3511#ifndef ENABLE_LIBXML2
3512
3513    XML_SetUserData (p, &parse);
3514
3515    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3516    XML_SetElementHandler (p, FcStartElement, FcEndElement);
3517    XML_SetCharacterDataHandler (p, FcCharacterData);
3518
3519#endif /* ENABLE_LIBXML2 */
3520
3521#ifndef ENABLE_LIBXML2
3522    s = buffer;
3523    do {
3524	buf = XML_GetBuffer (p, BUFSIZ);
3525	if (!buf)
3526	{
3527	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3528	    goto bail3;
3529	}
3530	if (len > BUFSIZ)
3531	{
3532	    buflen = BUFSIZ;
3533	    len -= BUFSIZ;
3534	}
3535	else
3536	{
3537	    buflen = len;
3538	    len = 0;
3539	}
3540	memcpy (buf, s, buflen);
3541	s = s + buflen;
3542#endif
3543
3544#ifdef ENABLE_LIBXML2
3545	if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3546#else
3547	if (!XML_ParseBuffer (p, buflen, buflen == 0))
3548#endif
3549	{
3550	    FcConfigMessage (&parse, FcSevereError, "%s",
3551			   XML_ErrorString (XML_GetErrorCode (p)));
3552	    goto bail3;
3553	}
3554#ifndef ENABLE_LIBXML2
3555    } while (buflen != 0);
3556#endif
3557    error = parse.error;
3558    if (load)
3559    {
3560	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3561	{
3562	    FcPtrListIter iter;
3563
3564	    FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3565	    if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
3566	    {
3567		FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3568		FcRuleSetReference (parse.ruleset);
3569		FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3570	    }
3571	}
3572    }
3573    FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3574    FcRuleSetReference (parse.ruleset);
3575    FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3576bail3:
3577    FcConfigCleanup (&parse);
3578bail2:
3579    XML_ParserFree (p);
3580bail1:
3581    if (error && complain)
3582    {
3583	FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3584	return FcFalse;
3585    }
3586    if (FcDebug () & FC_DBG_CONFIG)
3587	printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3588    return FcTrue;
3589}
3590
3591static FcBool
3592_FcConfigParse (FcConfig	*config,
3593		const FcChar8	*name,
3594		FcBool		complain,
3595		FcBool		load)
3596{
3597    FcChar8	    *filename = NULL, *realfilename = NULL;
3598    int		    fd;
3599    int		    len;
3600    FcStrBuf	    sbuf;
3601    char            buf[BUFSIZ];
3602    FcBool	    ret = FcFalse, complain_again = complain;
3603    FcStrBuf	    reason;
3604
3605    FcStrBufInit (&reason, NULL, 0);
3606#ifdef _WIN32
3607    _ensureWin32GettersReady();
3608#endif
3609
3610    filename = FcConfigGetFilename (config, name);
3611    if (!filename)
3612    {
3613	FcStrBufString (&reason, (FcChar8 *)"No such file: ");
3614	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3615	goto bail0;
3616    }
3617    realfilename = FcConfigRealFilename (config, name);
3618    if (!realfilename)
3619    {
3620	FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3621	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3622	goto bail0;
3623    }
3624    if (FcStrSetMember (config->availConfigFiles, realfilename))
3625    {
3626        FcStrFree (filename);
3627	FcStrFree (realfilename);
3628        return FcTrue;
3629    }
3630
3631    if (load)
3632    {
3633	if (!FcStrSetAdd (config->configFiles, filename))
3634	    goto bail0;
3635    }
3636    if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3637	goto bail0;
3638
3639    if (FcFileIsDir (realfilename))
3640    {
3641	ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3642	FcStrFree (filename);
3643	FcStrFree (realfilename);
3644	return ret;
3645    }
3646
3647    FcStrBufInit (&sbuf, NULL, 0);
3648
3649    fd = FcOpen ((char *) realfilename, O_RDONLY);
3650    if (fd == -1)
3651    {
3652	FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3653	FcStrBufString (&reason, realfilename);
3654	goto bail1;
3655    }
3656
3657    do {
3658	len = read (fd, buf, BUFSIZ);
3659	if (len < 0)
3660	{
3661	    int errno_ = errno;
3662	    char ebuf[BUFSIZ+1];
3663
3664#if HAVE_STRERROR_R
3665	    strerror_r (errno_, ebuf, BUFSIZ);
3666#elif HAVE_STRERROR
3667	    char *tmp = strerror (errno_);
3668	    size_t len = strlen (tmp);
3669	    memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3670	    ebuf[FC_MIN (BUFSIZ, len)] = 0;
3671#else
3672	    ebuf[0] = 0;
3673#endif
3674	    FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3675	    close (fd);
3676	    goto bail1;
3677	}
3678	FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3679    } while (len != 0);
3680    close (fd);
3681
3682    ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3683    complain_again = FcFalse; /* no need to reclaim here */
3684bail1:
3685    FcStrBufDestroy (&sbuf);
3686bail0:
3687    if (filename)
3688	FcStrFree (filename);
3689    if (realfilename)
3690	FcStrFree (realfilename);
3691    if (!complain)
3692    {
3693	FcStrBufDestroy (&reason);
3694	return FcTrue;
3695    }
3696    if (!ret && complain_again)
3697    {
3698	if (name)
3699	    FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
3700	else
3701	    FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3702	FcStrBufDestroy (&reason);
3703	return FcFalse;
3704    }
3705    FcStrBufDestroy (&reason);
3706    return ret;
3707}
3708
3709FcBool
3710FcConfigParseOnly (FcConfig		*config,
3711		   const FcChar8	*name,
3712		   FcBool		complain)
3713{
3714    return _FcConfigParse (config, name, complain, FcFalse);
3715}
3716
3717FcBool
3718FcConfigParseAndLoad (FcConfig	    *config,
3719		      const FcChar8 *name,
3720		      FcBool	    complain)
3721{
3722    return _FcConfigParse (config, name, complain, FcTrue);
3723}
3724
3725FcBool
3726FcConfigParseAndLoadFromMemory (FcConfig       *config,
3727				const FcChar8  *buffer,
3728				FcBool         complain)
3729{
3730    return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3731}
3732
3733#ifdef _WIN32
3734static void
3735_ensureWin32GettersReady()
3736{
3737    if (!pGetSystemWindowsDirectory)
3738    {
3739        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3740        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3741            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3742    }
3743    if (!pSHGetFolderPathA)
3744    {
3745        HMODULE hSh = LoadLibraryA("shfolder.dll");
3746        /* the check is done later, because there is no provided fallback */
3747        if (hSh)
3748            pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress(hSh, "SHGetFolderPathA");
3749    }
3750}
3751#endif // _WIN32
3752
3753#define __fcxml__
3754#include "fcaliastail.h"
3755#undef __fcxml__
3756