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