]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
src/fcint.h (FcCacheBankToIndex);
[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
25#include <stdarg.h>
26#include "fcint.h"
2d9c79c0 27#include <dirent.h>
0ab36ca8 28
e99f0f0a
PL
29#if ENABLE_LIBXML2
30
31#include <libxml/parser.h>
32
33#define XML_Char xmlChar
34#define XML_Parser xmlParserCtxtPtr
35#define XML_ParserFree xmlFreeParserCtxt
36#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
37#define XML_GetErrorCode xmlCtxtGetLastError
38#define XML_ErrorString(Error) (Error)->message
39
40#else /* ENABLE_LIBXML2 */
41
d0f07b8d
KP
42#ifndef HAVE_XMLPARSE_H
43#define HAVE_XMLPARSE_H 0
44#endif
fa244f3d 45
179c3995
KP
46#if HAVE_XMLPARSE_H
47#include <xmlparse.h>
48#else
49#include <expat.h>
50#endif
24330d27 51
e99f0f0a
PL
52#endif /* ENABLE_LIBXML2 */
53
daeed6e0
TL
54#ifdef _WIN32
55#define STRICT
56#include <windows.h>
57#undef STRICT
58#endif
59
24330d27
KP
60
61void
62FcTestDestroy (FcTest *test)
63{
64 if (test->next)
65 FcTestDestroy (test->next);
66 FcExprDestroy (test->expr);
67 FcStrFree ((FcChar8 *) test->field);
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;
ccb3e93b 164 e->u.field = (char *) FcStrCopy ((FcChar8 *) 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:
ccb3e93b 220 FcStrFree ((FcChar8 *) e->u.field);
24330d27
KP
221 break;
222 case FcOpConst:
223 FcStrFree (e->u.constant);
224 break;
225 case FcOpAssign:
226 case FcOpAssignReplace:
227 case FcOpPrepend:
228 case FcOpPrependFirst:
229 case FcOpAppend:
230 case FcOpAppendLast:
231 break;
232 case FcOpOr:
233 case FcOpAnd:
234 case FcOpEqual:
24330d27
KP
235 case FcOpNotEqual:
236 case FcOpLess:
237 case FcOpLessEqual:
238 case FcOpMore:
239 case FcOpMoreEqual:
47d4f950 240 case FcOpContains:
74a623e0 241 case FcOpListing:
47d4f950 242 case FcOpNotContains:
24330d27
KP
243 case FcOpPlus:
244 case FcOpMinus:
245 case FcOpTimes:
246 case FcOpDivide:
247 case FcOpQuest:
248 case FcOpComma:
249 FcExprDestroy (e->u.tree.right);
250 /* fall through */
251 case FcOpNot:
3f7653c2
KP
252 case FcOpFloor:
253 case FcOpCeil:
254 case FcOpRound:
255 case FcOpTrunc:
24330d27
KP
256 FcExprDestroy (e->u.tree.left);
257 break;
258 case FcOpNil:
259 case FcOpInvalid:
260 break;
261 }
9dac3c59 262 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
263 free (e);
264}
265
24330d27
KP
266void
267FcEditDestroy (FcEdit *e)
268{
269 if (e->next)
270 FcEditDestroy (e->next);
271 FcStrFree ((FcChar8 *) e->field);
272 if (e->expr)
273 FcExprDestroy (e->expr);
34cd0514 274 free (e);
24330d27
KP
275}
276
277char *
278FcConfigSaveField (const char *field)
279{
ccb3e93b 280 return (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
281}
282
c2e7c611
KP
283typedef enum _FcElement {
284 FcElementNone,
285 FcElementFontconfig,
286 FcElementDir,
287 FcElementCache,
288 FcElementInclude,
289 FcElementConfig,
290 FcElementMatch,
291 FcElementAlias,
292
293 FcElementBlank,
179c3995 294 FcElementRescan,
c2e7c611
KP
295
296 FcElementPrefer,
297 FcElementAccept,
298 FcElementDefault,
299 FcElementFamily,
300
d47c9d6e
KP
301 FcElementSelectfont,
302 FcElementAcceptfont,
303 FcElementRejectfont,
304 FcElementGlob,
4f27c1c0
KP
305 FcElementPattern,
306 FcElementPatelt,
d47c9d6e 307
c2e7c611
KP
308 FcElementTest,
309 FcElementEdit,
310 FcElementInt,
311 FcElementDouble,
312 FcElementString,
313 FcElementMatrix,
314 FcElementBool,
315 FcElementCharset,
316 FcElementName,
317 FcElementConst,
318 FcElementOr,
319 FcElementAnd,
320 FcElementEq,
321 FcElementNotEq,
322 FcElementLess,
323 FcElementLessEq,
324 FcElementMore,
325 FcElementMoreEq,
47d4f950
KP
326 FcElementContains,
327 FcElementNotContains,
c2e7c611
KP
328 FcElementPlus,
329 FcElementMinus,
330 FcElementTimes,
331 FcElementDivide,
332 FcElementNot,
333 FcElementIf,
3f7653c2
KP
334 FcElementFloor,
335 FcElementCeil,
336 FcElementRound,
337 FcElementTrunc,
c2e7c611
KP
338 FcElementUnknown
339} FcElement;
340
67accef4
PL
341static struct {
342 const char name[16];
343 FcElement element;
344} fcElementMap[] = {
345 { "fontconfig", FcElementFontconfig },
346 { "dir", FcElementDir },
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,
c2e7c611
KP
495 parse->name, XML_GetCurrentLineNumber (parse->parser));
496 else
179c3995 497 fprintf (stderr, "Fontconfig %s: line %d: ", s,
c2e7c611 498 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:
579 o = FcNameGetObjectType (expr->u.field);
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;
659 test->field = (char *) FcStrCopy (field);
660 test->op = compare;
661 test->expr = expr;
662 o = FcNameGetObjectType (test->field);
663 if (o)
664 FcTypecheckExpr (parse, expr, o->type);
665 }
666 return test;
667}
668
669static FcEdit *
670FcEditCreate (FcConfigParse *parse,
671 const char *field,
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;
683 e->field = field; /* already saved in grammar */
684 e->op = op;
685 e->expr = expr;
686 e->binding = binding;
687 o = FcNameGetObjectType (e->field);
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 n;
927 int slen;
928 int i;
929 FcChar8 **new;
930 FcChar8 *s;
24330d27 931
c2e7c611
KP
932 if (!attr)
933 return 0;
934 slen = 0;
935 for (i = 0; attr[i]; i++)
8f2a8078 936 slen += strlen ((char *) attr[i]) + 1;
c2e7c611
KP
937 n = i;
938 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
939 if (!new)
940 return 0;
9dac3c59 941 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
c2e7c611
KP
942 s = (FcChar8 *) (new + (i + 1));
943 for (i = 0; attr[i]; i++)
24330d27 944 {
c2e7c611
KP
945 new[i] = s;
946 strcpy ((char *) s, (char *) attr[i]);
947 s += strlen ((char *) s) + 1;
24330d27 948 }
c2e7c611
KP
949 new[i] = 0;
950 return new;
951}
24330d27 952
c2e7c611
KP
953static FcBool
954FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
955{
956 FcPStack *new = malloc (sizeof (FcPStack));
957
958 if (!new)
959 return FcFalse;
9dac3c59 960 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
961 new->prev = parse->pstack;
962 new->element = element;
963 if (attr)
24330d27 964 {
c2e7c611
KP
965 new->attr = FcConfigSaveAttr (attr);
966 if (!new->attr)
179c3995 967 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 968 }
c2e7c611
KP
969 else
970 new->attr = 0;
971 FcStrBufInit (&new->str, 0, 0);
972 parse->pstack = new;
973 return FcTrue;
974}
24330d27 975
c2e7c611
KP
976static FcBool
977FcPStackPop (FcConfigParse *parse)
978{
979 FcPStack *old;
980
981 if (!parse->pstack)
24330d27 982 {
179c3995 983 FcConfigMessage (parse, FcSevereError, "mismatching element");
c2e7c611 984 return FcFalse;
24330d27 985 }
c2e7c611
KP
986 FcVStackClear (parse);
987 old = parse->pstack;
988 parse->pstack = old->prev;
989 FcStrBufDestroy (&old->str);
990 if (old->attr)
9dac3c59
KP
991 {
992 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
c2e7c611 993 free (old->attr);
9dac3c59
KP
994 }
995 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
996 free (old);
997 return FcTrue;
24330d27
KP
998}
999
c2e7c611
KP
1000static FcBool
1001FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
24330d27 1002{
c2e7c611
KP
1003 parse->pstack = 0;
1004 parse->vstack = 0;
1005 parse->error = FcFalse;
1006 parse->name = name;
1007 parse->config = config;
1008 parse->parser = parser;
1009 return FcTrue;
1010}
1011
1012static void
1013FcConfigCleanup (FcConfigParse *parse)
1014{
1015 while (parse->pstack)
1016 FcPStackPop (parse);
1017}
1018
1019static const FcChar8 *
67accef4 1020FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
c2e7c611
KP
1021{
1022 FcChar8 **attrs;
1023 if (!parse->pstack)
24330d27 1024 return 0;
24330d27 1025
c2e7c611
KP
1026 attrs = parse->pstack->attr;
1027 while (*attrs)
24330d27 1028 {
c2e7c611
KP
1029 if (!strcmp ((char *) *attrs, attr))
1030 return attrs[1];
1031 attrs += 2;
24330d27 1032 }
24330d27
KP
1033 return 0;
1034}
1035
c2e7c611
KP
1036static void
1037FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
24330d27 1038{
c2e7c611
KP
1039 FcConfigParse *parse = userData;
1040 FcElement element;
1041
1042 element = FcElementMap (name);
1043 if (element == FcElementUnknown)
179c3995 1044 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
c2e7c611
KP
1045
1046 if (!FcPStackPush (parse, element, attr))
24330d27 1047 {
179c3995 1048 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1049 return;
24330d27 1050 }
c2e7c611
KP
1051 return;
1052}
24330d27 1053
c2e7c611
KP
1054static void
1055FcParseBlank (FcConfigParse *parse)
1056{
1057 int n = FcVStackElements (parse);
1058 while (n-- > 0)
24330d27 1059 {
c2e7c611
KP
1060 FcVStack *v = FcVStackFetch (parse, n);
1061 if (v->tag != FcVStackInteger)
179c3995 1062 FcConfigMessage (parse, FcSevereError, "non-integer blank");
c2e7c611 1063 else
24330d27 1064 {
c2e7c611 1065 if (!parse->config->blanks)
24330d27 1066 {
c2e7c611
KP
1067 parse->config->blanks = FcBlanksCreate ();
1068 if (!parse->config->blanks)
1069 {
179c3995 1070 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1071 break;
1072 }
24330d27 1073 }
c2e7c611 1074 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
24330d27 1075 {
179c3995 1076 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1077 break;
24330d27
KP
1078 }
1079 }
1080 }
c2e7c611 1081}
24330d27 1082
179c3995
KP
1083static void
1084FcParseRescan (FcConfigParse *parse)
1085{
1086 int n = FcVStackElements (parse);
1087 while (n-- > 0)
1088 {
1089 FcVStack *v = FcVStackFetch (parse, n);
1090 if (v->tag != FcVStackInteger)
1091 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1092 else
1093 parse->config->rescanInterval = v->u.integer;
1094 }
1095}
1096
c2e7c611
KP
1097static void
1098FcParseInt (FcConfigParse *parse)
1099{
1100 FcChar8 *s, *end;
1101 int l;
1102
1103 if (!parse->pstack)
1104 return;
1105 s = FcStrBufDone (&parse->pstack->str);
1106 if (!s)
24330d27 1107 {
179c3995 1108 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1109 return;
24330d27 1110 }
c2e7c611
KP
1111 end = 0;
1112 l = (int) strtol ((char *) s, (char **)&end, 0);
1113 if (end != s + strlen ((char *) s))
179c3995 1114 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
c2e7c611
KP
1115 else
1116 FcVStackPushInteger (parse, l);
1117 FcStrFree (s);
24330d27
KP
1118}
1119
223c0289
KP
1120/*
1121 * idea copied from glib g_ascii_strtod with
1122 * permission of the author (Alexander Larsson)
1123 */
1124
1125#include <locale.h>
1126
1127static double
1128FcStrtod (char *s, char **end)
1129{
1130 struct lconv *locale_data;
1131 char *dot;
1132 double v;
1133
1134 /*
1135 * Have to swap the decimal point to match the current locale
1136 * if that locale doesn't use 0x2e
1137 */
1138 if ((dot = strchr (s, 0x2e)) &&
1139 (locale_data = localeconv ()) &&
1140 (locale_data->decimal_point[0] != 0x2e ||
1141 locale_data->decimal_point[1] != 0))
1142 {
1143 char buf[128];
1144 int slen = strlen (s);
1145 int dlen = strlen (locale_data->decimal_point);
1146
67accef4 1147 if (slen + dlen > (int) sizeof (buf))
223c0289
KP
1148 {
1149 if (end)
1150 *end = s;
1151 v = 0;
1152 }
1153 else
1154 {
1155 char *buf_end;
1156 /* mantissa */
1157 strncpy (buf, s, dot - s);
1158 /* decimal point */
1159 strcpy (buf + (dot - s), locale_data->decimal_point);
1160 /* rest of number */
1161 strcpy (buf + (dot - s) + dlen, dot + 1);
1162 buf_end = 0;
1163 v = strtod (buf, &buf_end);
344a0e33
RP
1164 if (buf_end) {
1165 buf_end = s + (buf_end - buf);
1166 if (buf_end > dot)
1167 buf_end -= dlen - 1;
1168 }
223c0289
KP
1169 if (end)
1170 *end = buf_end;
1171 }
1172 }
1173 else
1174 v = strtod (s, end);
1175 return v;
1176}
1177
c2e7c611
KP
1178static void
1179FcParseDouble (FcConfigParse *parse)
24330d27 1180{
c2e7c611
KP
1181 FcChar8 *s, *end;
1182 double d;
24330d27 1183
c2e7c611
KP
1184 if (!parse->pstack)
1185 return;
1186 s = FcStrBufDone (&parse->pstack->str);
1187 if (!s)
24330d27 1188 {
179c3995 1189 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1190 return;
24330d27 1191 }
c2e7c611 1192 end = 0;
223c0289 1193 d = FcStrtod ((char *) s, (char **)&end);
c2e7c611 1194 if (end != s + strlen ((char *) s))
179c3995 1195 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
24330d27 1196 else
c2e7c611
KP
1197 FcVStackPushDouble (parse, d);
1198 FcStrFree (s);
1199}
24330d27 1200
c2e7c611
KP
1201static void
1202FcParseString (FcConfigParse *parse, FcVStackTag tag)
1203{
1204 FcChar8 *s;
1205
1206 if (!parse->pstack)
1207 return;
1208 s = FcStrBufDone (&parse->pstack->str);
1209 if (!s)
1210 {
179c3995 1211 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1212 return;
1213 }
1214 if (!FcVStackPushString (parse, tag, s))
1215 FcStrFree (s);
1216}
1217
1218static void
1219FcParseMatrix (FcConfigParse *parse)
1220{
1221 FcVStack *vstack;
1222 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1223 FcMatrix m;
1224
1225 while ((vstack = FcVStackPop (parse)))
1226 {
179c3995
KP
1227 double v;
1228 switch (vstack->tag) {
1229 case FcVStackInteger:
1230 v = vstack->u.integer;
1231 break;
1232 case FcVStackDouble:
1233 v = vstack->u._double;
1234 break;
1235 default:
1236 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1237 v = 1.0;
1238 break;
1239 }
1240 switch (matrix_state) {
1241 case m_xx: m.xx = v; break;
1242 case m_xy: m.xy = v; break;
1243 case m_yx: m.yx = v; break;
1244 case m_yy: m.yy = v; break;
1245 default: break;
c2e7c611 1246 }
f4fe447f 1247 FcVStackDestroy (vstack);
179c3995 1248 matrix_state--;
c2e7c611
KP
1249 }
1250 if (matrix_state != m_done)
179c3995 1251 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
c2e7c611
KP
1252 else
1253 FcVStackPushMatrix (parse, &m);
24330d27
KP
1254}
1255
1256static FcBool
ca60d2b5 1257FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
c2e7c611 1258{
ca60d2b5
KP
1259 FcBool result = FcFalse;
1260
1261 if (!FcNameBool (bool, &result))
1262 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1263 bool);
1264 return result;
c2e7c611
KP
1265}
1266
1267static void
1268FcParseBool (FcConfigParse *parse)
1269{
1270 FcChar8 *s;
1271
1272 if (!parse->pstack)
1273 return;
1274 s = FcStrBufDone (&parse->pstack->str);
1275 if (!s)
1276 {
179c3995 1277 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1278 return;
1279 }
ca60d2b5 1280 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
c2e7c611
KP
1281 FcStrFree (s);
1282}
1283
1284static void
1285FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1286{
c2e7c611
KP
1287 FcVStack *vstack;
1288 FcExpr *left, *expr = 0, *new;
1289
1290 while ((vstack = FcVStackPop (parse)))
1291 {
1292 if (vstack->tag != FcVStackFamily)
1293 {
179c3995
KP
1294 FcConfigMessage (parse, FcSevereWarning, "non-family");
1295 FcVStackDestroy (vstack);
1296 continue;
c2e7c611
KP
1297 }
1298 left = vstack->u.expr;
1299 vstack->tag = FcVStackNone;
1300 FcVStackDestroy (vstack);
1301 if (expr)
1302 {
1303 new = FcExprCreateOp (left, FcOpComma, expr);
1304 if (!new)
1305 {
179c3995 1306 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1307 FcExprDestroy (left);
1308 FcExprDestroy (expr);
1309 break;
1310 }
1311 expr = new;
1312 }
1313 else
1314 expr = left;
1315 }
1316 if (expr)
1317 {
1318 if (!FcVStackPushExpr (parse, tag, expr))
1319 {
179c3995 1320 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1321 if (expr)
1322 FcExprDestroy (expr);
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
KP
1412 edit = FcEditCreate (parse,
1413 FcConfigSaveField ("family"),
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
KP
1425 edit = FcEditCreate (parse,
1426 FcConfigSaveField ("family"),
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
KP
1438 edit = FcEditCreate (parse,
1439 FcConfigSaveField ("family"),
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);
24330d27 1543 break;
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;
1670 else if (!strcmp ((char *) kind_string, "default"))
1671 kind = FcMatchDefault;
1672 else
1673 {
1674 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1675 return;
1676 }
1677 }
c2e7c611
KP
1678 qual_string = FcConfigGetAttribute (parse, "qual");
1679 if (!qual_string)
1680 qual = FcQualAny;
1681 else
1682 {
1683 if (!strcmp ((char *) qual_string, "any"))
1684 qual = FcQualAny;
1685 else if (!strcmp ((char *) qual_string, "all"))
1686 qual = FcQualAll;
6f6563ed
KP
1687 else if (!strcmp ((char *) qual_string, "first"))
1688 qual = FcQualFirst;
1689 else if (!strcmp ((char *) qual_string, "not_first"))
1690 qual = FcQualNotFirst;
c2e7c611 1691 else
24330d27 1692 {
179c3995 1693 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1694 return;
24330d27 1695 }
c2e7c611
KP
1696 }
1697 name = FcConfigGetAttribute (parse, "name");
1698 if (!name)
1699 {
179c3995 1700 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1701 return;
c2e7c611
KP
1702 }
1703 compare_string = FcConfigGetAttribute (parse, "compare");
1704 if (!compare_string)
1705 compare = FcOpEqual;
1706 else
1707 {
1708 compare = FcConfigLexCompare (compare_string);
1709 if (compare == FcOpInvalid)
24330d27 1710 {
179c3995 1711 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1712 return;
24330d27 1713 }
c2e7c611 1714 }
3f7653c2 1715 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1716 if (!expr)
1717 {
179c3995 1718 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1719 return;
1720 }
ca60d2b5 1721 test = FcTestCreate (parse, kind, qual, name, compare, expr);
c2e7c611
KP
1722 if (!test)
1723 {
179c3995 1724 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1725 return;
1726 }
1727 FcVStackPushTest (parse, test);
1728}
1729
1730static const FcOpMap fcModeOps[] = {
1731 { "assign", FcOpAssign },
1732 { "assign_replace", FcOpAssignReplace },
1733 { "prepend", FcOpPrepend },
1734 { "prepend_first", FcOpPrependFirst },
1735 { "append", FcOpAppend },
1736 { "append_last", FcOpAppendLast },
1737};
1738
67accef4 1739#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
c2e7c611
KP
1740
1741static FcOp
1742FcConfigLexMode (const FcChar8 *mode)
1743{
1744 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1745}
1746
1747static void
1748FcParseEdit (FcConfigParse *parse)
1749{
1750 const FcChar8 *name;
1751 const FcChar8 *mode_string;
6fff2cda 1752 const FcChar8 *binding_string;
c2e7c611 1753 FcOp mode;
6fff2cda 1754 FcValueBinding binding;
c2e7c611
KP
1755 FcExpr *expr;
1756 FcEdit *edit;
1757
1758 name = FcConfigGetAttribute (parse, "name");
1759 if (!name)
1760 {
179c3995 1761 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1762 return;
c2e7c611
KP
1763 }
1764 mode_string = FcConfigGetAttribute (parse, "mode");
1765 if (!mode_string)
8ec077f2 1766 mode = FcOpAssign;
c2e7c611
KP
1767 else
1768 {
1769 mode = FcConfigLexMode (mode_string);
1770 if (mode == FcOpInvalid)
24330d27 1771 {
179c3995 1772 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1773 return;
24330d27 1774 }
c2e7c611 1775 }
6fff2cda
KP
1776 binding_string = FcConfigGetAttribute (parse, "binding");
1777 if (!binding_string)
1778 binding = FcValueBindingWeak;
1779 else
1780 {
1781 if (!strcmp ((char *) binding_string, "weak"))
1782 binding = FcValueBindingWeak;
1783 else if (!strcmp ((char *) binding_string, "strong"))
1784 binding = FcValueBindingStrong;
dda7794f
KP
1785 else if (!strcmp ((char *) binding_string, "same"))
1786 binding = FcValueBindingSame;
6fff2cda
KP
1787 else
1788 {
1789 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1790 return;
1791 }
1792 }
3f7653c2 1793 expr = FcPopBinary (parse, FcOpComma);
ca60d2b5 1794 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
c2e7c611
KP
1795 if (!edit)
1796 {
179c3995 1797 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1798 FcExprDestroy (expr);
1799 return;
1800 }
1801 if (!FcVStackPushEdit (parse, edit))
1802 FcEditDestroy (edit);
1803}
1804
1805static void
1806FcParseMatch (FcConfigParse *parse)
1807{
1808 const FcChar8 *kind_name;
1809 FcMatchKind kind;
1810 FcTest *test = 0;
1811 FcEdit *edit = 0;
1812 FcVStack *vstack;
1813
1814 kind_name = FcConfigGetAttribute (parse, "target");
1815 if (!kind_name)
1816 kind = FcMatchPattern;
1817 else
1818 {
1819 if (!strcmp ((char *) kind_name, "pattern"))
1820 kind = FcMatchPattern;
1821 else if (!strcmp ((char *) kind_name, "font"))
1822 kind = FcMatchFont;
1823 else
24330d27 1824 {
179c3995 1825 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1826 return;
24330d27 1827 }
c2e7c611
KP
1828 }
1829 while ((vstack = FcVStackPop (parse)))
1830 {
1831 switch (vstack->tag) {
1832 case FcVStackTest:
1833 vstack->u.test->next = test;
1834 test = vstack->u.test;
1835 vstack->tag = FcVStackNone;
1836 break;
1837 case FcVStackEdit:
1838 vstack->u.edit->next = edit;
1839 edit = vstack->u.edit;
1840 vstack->tag = FcVStackNone;
1841 break;
1842 default:
179c3995 1843 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1844 break;
1845 }
1846 FcVStackDestroy (vstack);
1847 }
1848 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1849 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1850}
1851
d47c9d6e
KP
1852static void
1853FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1854{
1855 FcVStack *vstack;
1856
1857 while ((vstack = FcVStackPop (parse)))
1858 {
1859 switch (vstack->tag) {
1860 case FcVStackGlob:
1861 if (!FcConfigGlobAdd (parse->config,
1862 vstack->u.string,
1863 element == FcElementAcceptfont))
1864 {
1865 FcConfigMessage (parse, FcSevereError, "out of memory");
1866 }
1867 break;
4f27c1c0
KP
1868 case FcVStackPattern:
1869 if (!FcConfigPatternsAdd (parse->config,
1870 vstack->u.pattern,
1871 element == FcElementAcceptfont))
1872 {
1873 FcConfigMessage (parse, FcSevereError, "out of memory");
1874 }
1875 else
1876 vstack->tag = FcVStackNone;
1877 break;
d47c9d6e
KP
1878 default:
1879 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1880 break;
1881 }
1882 FcVStackDestroy (vstack);
1883 }
1884}
1885
4f27c1c0
KP
1886
1887static FcValue
1888FcPopValue (FcConfigParse *parse)
1889{
1890 FcVStack *vstack = FcVStackPop (parse);
1891 FcValue value;
1892
1893 value.type = FcTypeVoid;
1894
1895 if (!vstack)
1896 return value;
1897
1898 switch (vstack->tag) {
1899 case FcVStackString:
4262e0b3
PL
1900 value.u.s = FcStrCopy (vstack->u.string);
1901 if (value.u.s)
4f27c1c0
KP
1902 value.type = FcTypeString;
1903 break;
1904 case FcVStackConstant:
1905 if (FcNameConstant (vstack->u.string, &value.u.i))
1906 value.type = FcTypeInteger;
1907 break;
1908 case FcVStackInteger:
1909 value.u.i = vstack->u.integer;
1910 value.type = FcTypeInteger;
1911 break;
1912 case FcVStackDouble:
1913 value.u.d = vstack->u._double;
1914 value.type = FcTypeInteger;
1915 break;
1916 case FcVStackMatrix:
4262e0b3
PL
1917 value.u.m = FcMatrixCopy (vstack->u.matrix);
1918 if (value.u.m)
4f27c1c0
KP
1919 value.type = FcTypeMatrix;
1920 break;
1921 case FcVStackBool:
1922 value.u.b = vstack->u.bool;
1923 value.type = FcTypeBool;
1924 break;
1925 default:
1926 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1927 vstack->tag);
1928 break;
1929 }
1930 FcVStackDestroy (vstack);
1931
1932 return value;
1933}
1934
1935static void
1936FcParsePatelt (FcConfigParse *parse)
1937{
1938 FcValue value;
1939 FcPattern *pattern = FcPatternCreate ();
1940 const char *name;
1941
1942 if (!pattern)
1943 {
1944 FcConfigMessage (parse, FcSevereError, "out of memory");
1945 return;
1946 }
1947
8245771d 1948 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
1949 if (!name)
1950 {
1951 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1952 return;
1953 }
4f27c1c0
KP
1954
1955 for (;;)
1956 {
1957 value = FcPopValue (parse);
1958 if (value.type == FcTypeVoid)
1959 break;
1960 if (!FcPatternAdd (pattern, name, value, FcTrue))
1961 {
1962 FcConfigMessage (parse, FcSevereError, "out of memory");
1963 break;
1964 }
1965 }
1966
1967 FcVStackPushPattern (parse, pattern);
1968}
1969
1970static void
1971FcParsePattern (FcConfigParse *parse)
1972{
1973 FcVStack *vstack;
1974 FcPattern *pattern = FcPatternCreate ();
1975
1976 if (!pattern)
1977 {
1978 FcConfigMessage (parse, FcSevereError, "out of memory");
1979 return;
1980 }
1981
1982 while ((vstack = FcVStackPop (parse)))
1983 {
1984 switch (vstack->tag) {
1985 case FcVStackPattern:
1986 if (!FcPatternAppend (pattern, vstack->u.pattern))
1987 {
1988 FcConfigMessage (parse, FcSevereError, "out of memory");
1989 return;
1990 }
1991 break;
1992 default:
1993 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1994 break;
1995 }
1996 FcVStackDestroy (vstack);
1997 }
1998
1999 FcVStackPushPattern (parse, pattern);
2000}
2001
c2e7c611
KP
2002static void
2003FcEndElement(void *userData, const XML_Char *name)
2004{
2005 FcConfigParse *parse = userData;
2006 FcChar8 *data;
2007
2008 if (!parse->pstack)
2009 return;
2010 switch (parse->pstack->element) {
2011 case FcElementNone:
2012 break;
2013 case FcElementFontconfig:
2014 break;
2015 case FcElementDir:
2016 data = FcStrBufDone (&parse->pstack->str);
2017 if (!data)
24330d27 2018 {
179c3995 2019 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2020 break;
24330d27 2021 }
daeed6e0
TL
2022#ifdef _WIN32
2023 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2024 {
2025 int rc;
2026 FcStrFree (data);
2027 data = malloc (1000);
2028 if (!data)
2029 {
2030 FcConfigMessage (parse, FcSevereError, "out of memory");
2031 break;
2032 }
2033 FcMemAlloc (FC_MEM_STRING, 1000);
2034 rc = GetWindowsDirectory (data, 800);
2035 if (rc == 0 || rc > 800)
2036 {
2037 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2038 FcStrFree (data);
2039 break;
2040 }
2041 if (data [strlen (data) - 1] != '\\')
2042 strcat (data, "\\");
2043 strcat (data, "fonts");
2044 }
2045#endif
ff3f1f98
KP
2046 if (!FcStrUsesHome (data) || FcConfigHome ())
2047 {
2048 if (!FcConfigAddDir (parse->config, data))
2049 FcConfigMessage (parse, FcSevereError, "out of memory");
2050 }
9dac3c59 2051 FcStrFree (data);
c2e7c611
KP
2052 break;
2053 case FcElementCache:
2054 data = FcStrBufDone (&parse->pstack->str);
2055 if (!data)
24330d27 2056 {
179c3995 2057 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2058 break;
c2e7c611 2059 }
ff3f1f98
KP
2060 if (!FcStrUsesHome (data) || FcConfigHome ())
2061 {
2062 if (!FcConfigSetCache (parse->config, data))
2063 FcConfigMessage (parse, FcSevereError, "out of memory");
2064 }
9dac3c59 2065 FcStrFree (data);
c2e7c611
KP
2066 break;
2067 case FcElementInclude:
2068 FcParseInclude (parse);
2069 break;
2070 case FcElementConfig:
2071 break;
2072 case FcElementMatch:
2073 FcParseMatch (parse);
2074 break;
2075 case FcElementAlias:
2076 FcParseAlias (parse);
2077 break;
2078
2079 case FcElementBlank:
2080 FcParseBlank (parse);
2081 break;
179c3995
KP
2082 case FcElementRescan:
2083 FcParseRescan (parse);
2084 break;
c2e7c611
KP
2085
2086 case FcElementPrefer:
2087 FcParseFamilies (parse, FcVStackPrefer);
2088 break;
2089 case FcElementAccept:
2090 FcParseFamilies (parse, FcVStackAccept);
2091 break;
2092 case FcElementDefault:
2093 FcParseFamilies (parse, FcVStackDefault);
2094 break;
2095 case FcElementFamily:
2096 FcParseFamily (parse);
2097 break;
2098
2099 case FcElementTest:
2100 FcParseTest (parse);
2101 break;
2102 case FcElementEdit:
2103 FcParseEdit (parse);
2104 break;
2105
2106 case FcElementInt:
2107 FcParseInt (parse);
2108 break;
2109 case FcElementDouble:
2110 FcParseDouble (parse);
2111 break;
2112 case FcElementString:
2113 FcParseString (parse, FcVStackString);
2114 break;
2115 case FcElementMatrix:
2116 FcParseMatrix (parse);
2117 break;
2118 case FcElementBool:
2119 FcParseBool (parse);
2120 break;
2121 case FcElementCharset:
2122/* FcParseCharset (parse); */
2123 break;
d47c9d6e
KP
2124 case FcElementSelectfont:
2125 break;
2126 case FcElementAcceptfont:
2127 case FcElementRejectfont:
2128 FcParseAcceptRejectFont (parse, parse->pstack->element);
2129 break;
2130 case FcElementGlob:
2131 FcParseString (parse, FcVStackGlob);
2132 break;
4f27c1c0
KP
2133 case FcElementPattern:
2134 FcParsePattern (parse);
2135 break;
2136 case FcElementPatelt:
2137 FcParsePatelt (parse);
2138 break;
c2e7c611
KP
2139 case FcElementName:
2140 FcParseString (parse, FcVStackField);
2141 break;
2142 case FcElementConst:
2143 FcParseString (parse, FcVStackConstant);
2144 break;
2145 case FcElementOr:
3f7653c2 2146 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2147 break;
2148 case FcElementAnd:
3f7653c2 2149 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2150 break;
2151 case FcElementEq:
3f7653c2 2152 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2153 break;
2154 case FcElementNotEq:
3f7653c2 2155 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2156 break;
2157 case FcElementLess:
3f7653c2 2158 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2159 break;
2160 case FcElementLessEq:
3f7653c2 2161 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2162 break;
2163 case FcElementMore:
3f7653c2 2164 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2165 break;
2166 case FcElementMoreEq:
3f7653c2 2167 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2168 break;
47d4f950 2169 case FcElementContains:
3f7653c2 2170 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2171 break;
2172 case FcElementNotContains:
3f7653c2 2173 FcParseBinary (parse, FcOpNotContains);
47d4f950 2174 break;
c2e7c611 2175 case FcElementPlus:
3f7653c2 2176 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2177 break;
2178 case FcElementMinus:
3f7653c2 2179 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2180 break;
2181 case FcElementTimes:
3f7653c2 2182 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2183 break;
2184 case FcElementDivide:
3f7653c2 2185 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2186 break;
2187 case FcElementNot:
3f7653c2 2188 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2189 break;
2190 case FcElementIf:
3f7653c2
KP
2191 FcParseBinary (parse, FcOpQuest);
2192 break;
2193 case FcElementFloor:
2194 FcParseUnary (parse, FcOpFloor);
2195 break;
2196 case FcElementCeil:
2197 FcParseUnary (parse, FcOpCeil);
2198 break;
2199 case FcElementRound:
2200 FcParseUnary (parse, FcOpRound);
2201 break;
2202 case FcElementTrunc:
2203 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2204 break;
2205 case FcElementUnknown:
2206 break;
24330d27 2207 }
c2e7c611
KP
2208 (void) FcPStackPop (parse);
2209}
2210
2211static void
2212FcCharacterData (void *userData, const XML_Char *s, int len)
2213{
2214 FcConfigParse *parse = userData;
2215
2216 if (!parse->pstack)
2217 return;
2218 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2219 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2220}
2221
2222static void
2223FcStartDoctypeDecl (void *userData,
2224 const XML_Char *doctypeName,
2225 const XML_Char *sysid,
2226 const XML_Char *pubid,
2227 int has_internal_subset)
2228{
2229 FcConfigParse *parse = userData;
2230
2231 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2232 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2233}
2234
e99f0f0a
PL
2235#if ENABLE_LIBXML2
2236
2237static void
2238FcInternalSubsetDecl (void *userData,
2239 const XML_Char *doctypeName,
2240 const XML_Char *sysid,
2241 const XML_Char *pubid)
2242{
2243 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2244}
2245
2246static void
2247FcExternalSubsetDecl (void *userData,
2248 const XML_Char *doctypeName,
2249 const XML_Char *sysid,
2250 const XML_Char *pubid)
2251{
2252 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2253}
2254
2255#else /* ENABLE_LIBXML2 */
2256
c2e7c611
KP
2257static void
2258FcEndDoctypeDecl (void *userData)
2259{
24330d27
KP
2260}
2261
e99f0f0a
PL
2262#endif /* ENABLE_LIBXML2 */
2263
2d9c79c0
KP
2264static FcBool
2265FcConfigParseAndLoadDir (FcConfig *config,
2266 const FcChar8 *name,
2267 const FcChar8 *dir,
2268 FcBool complain)
2269{
2270 DIR *d;
2271 struct dirent *e;
2272 FcBool ret = FcTrue;
2273 FcChar8 *file;
2274 FcChar8 *base;
2275 FcStrSet *files;
2276
2277 d = opendir ((char *) dir);
2278 if (!d)
2279 {
2280 if (complain)
2281 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2282 name);
2283 ret = FcFalse;
2284 goto bail0;
2285 }
2286 /* freed below */
2287 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2288 if (!file)
2289 {
2290 ret = FcFalse;
2291 goto bail1;
2292 }
2293
2294 strcpy ((char *) file, (char *) dir);
2295 strcat ((char *) file, "/");
2296 base = file + strlen ((char *) file);
2297
2298 files = FcStrSetCreate ();
2299 if (!files)
2300 {
2301 ret = FcFalse;
2302 goto bail2;
2303 }
2304
2305 if (FcDebug () & FC_DBG_CONFIG)
2306 printf ("\tScanning config dir %s\n", dir);
2307
2308 while (ret && (e = readdir (d)))
2309 {
8245771d
PL
2310 int d_len;
2311#define TAIL ".conf"
2312#define TAIL_LEN 5
2d9c79c0 2313 /*
8245771d 2314 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2315 */
2316 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2317 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2318 d_len > TAIL_LEN &&
2319 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2320 {
2321 strcpy ((char *) base, (char *) e->d_name);
2322 if (!FcStrSetAdd (files, file))
2323 {
2324 ret = FcFalse;
2325 goto bail3;
2326 }
2327 }
2328 }
2329 if (ret)
2330 {
2331 int i;
4262e0b3
PL
2332 qsort (files->strs, files->num, sizeof (FcChar8 *),
2333 (int (*)(const void *, const void *)) FcStrCmp);
2d9c79c0 2334 for (i = 0; ret && i < files->num; i++)
4262e0b3 2335 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2336 }
2337bail3:
2338 FcStrSetDestroy (files);
2339bail2:
2340 free (file);
2341bail1:
2342 closedir (d);
2343bail0:
2344 return ret || !complain;
2345}
2346
24330d27
KP
2347FcBool
2348FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2349 const FcChar8 *name,
24330d27
KP
2350 FcBool complain)
2351{
24330d27 2352
c2e7c611
KP
2353 XML_Parser p;
2354 FcChar8 *filename;
2355 FILE *f;
2356 int len;
c2e7c611
KP
2357 FcConfigParse parse;
2358 FcBool error = FcTrue;
2359
e99f0f0a
PL
2360#if ENABLE_LIBXML2
2361 xmlSAXHandler sax;
2362 char buf[BUFSIZ];
2363#else
2364 void *buf;
2365#endif
2366
c2e7c611
KP
2367 filename = FcConfigFilename (name);
2368 if (!filename)
2369 goto bail0;
4aded3e0
KP
2370
2371 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2372 {
2373 FcStrFree (filename);
4aded3e0 2374 goto bail0;
9dac3c59 2375 }
4aded3e0 2376
2d9c79c0
KP
2377 if (FcFileIsDir (filename))
2378 {
2379 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2380 FcStrFree (filename);
2381 return ret;
2382 }
2383
2384 if (FcDebug () & FC_DBG_CONFIG)
2385 printf ("\tLoading config file %s\n", filename);
2386
c2e7c611 2387 f = fopen ((char *) filename, "r");
8f2a8078
PL
2388 if (!f) {
2389 FcStrFree (filename);
c2e7c611 2390 goto bail0;
8f2a8078 2391 }
c2e7c611 2392
e99f0f0a
PL
2393#if ENABLE_LIBXML2
2394 memset(&sax, 0, sizeof(sax));
2395
2396 sax.internalSubset = FcInternalSubsetDecl;
2397 sax.externalSubset = FcExternalSubsetDecl;
2398 sax.startElement = FcStartElement;
2399 sax.endElement = FcEndElement;
2400 sax.characters = FcCharacterData;
2401
8f2a8078 2402 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2403#else
c2e7c611 2404 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2405#endif
8f2a8078 2406 FcStrFree (filename);
e99f0f0a 2407
c2e7c611
KP
2408 if (!p)
2409 goto bail1;
2410
2411 if (!FcConfigInit (&parse, name, config, p))
2412 goto bail2;
2413
e99f0f0a
PL
2414#if !ENABLE_LIBXML2
2415
c2e7c611
KP
2416 XML_SetUserData (p, &parse);
2417
2418 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2419 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2420 XML_SetCharacterDataHandler (p, FcCharacterData);
2421
e99f0f0a
PL
2422#endif /* ENABLE_LIBXML2 */
2423
c2e7c611 2424 do {
e99f0f0a 2425#if !ENABLE_LIBXML2
c2e7c611
KP
2426 buf = XML_GetBuffer (p, BUFSIZ);
2427 if (!buf)
80c053b7 2428 {
179c3995 2429 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2430 goto bail3;
80c053b7 2431 }
e99f0f0a 2432#endif
c2e7c611
KP
2433 len = fread (buf, 1, BUFSIZ, f);
2434 if (len < 0)
80c053b7 2435 {
179c3995 2436 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2437 goto bail3;
80c053b7 2438 }
e99f0f0a
PL
2439
2440#if ENABLE_LIBXML2
2441 if (xmlParseChunk (p, buf, len, len == 0))
2442#else
c2e7c611 2443 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2444#endif
80c053b7 2445 {
179c3995 2446 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2447 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2448 goto bail3;
80c053b7 2449 }
c2e7c611
KP
2450 } while (len != 0);
2451 error = parse.error;
2452bail3:
2453 FcConfigCleanup (&parse);
2454bail2:
2455 XML_ParserFree (p);
2456bail1:
2457 fclose (f);
e1b9d091 2458 f = NULL;
c2e7c611
KP
2459bail0:
2460 if (error && complain)
24330d27 2461 {
c2e7c611 2462 if (name)
179c3995 2463 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2464 else
179c3995 2465 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2466 return FcFalse;
2467 }
2468 return FcTrue;
2469}