source: trunk/poppler/fontconfig-2.3.2-os2/src/fcxml.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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