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