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