]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Don't add current_arch_start more than once.
[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 }
591 break;
592 case FcOpQuest:
593 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
594 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
595 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
596 break;
597 case FcOpAssign:
598 case FcOpAssignReplace:
599 break;
600 case FcOpEqual:
601 case FcOpNotEqual:
602 case FcOpLess:
603 case FcOpLessEqual:
604 case FcOpMore:
605 case FcOpMoreEqual:
606 case FcOpContains:
607 case FcOpNotContains:
608 case FcOpListing:
609 FcTypecheckValue (parse, FcTypeBool, type);
610 break;
611 case FcOpComma:
612 case FcOpOr:
613 case FcOpAnd:
614 case FcOpPlus:
615 case FcOpMinus:
616 case FcOpTimes:
617 case FcOpDivide:
618 FcTypecheckExpr (parse, expr->u.tree.left, type);
619 FcTypecheckExpr (parse, expr->u.tree.right, type);
620 break;
621 case FcOpNot:
622 FcTypecheckValue (parse, FcTypeBool, type);
623 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
624 break;
625 case FcOpFloor:
626 case FcOpCeil:
627 case FcOpRound:
628 case FcOpTrunc:
629 FcTypecheckValue (parse, FcTypeDouble, type);
630 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
631 break;
632 default:
633 break;
634 }
635}
636
637static FcTest *
638FcTestCreate (FcConfigParse *parse,
639 FcMatchKind kind,
640 FcQual qual,
641 const FcChar8 *field,
642 FcOp compare,
643 FcExpr *expr)
644{
645 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
646
647 if (test)
648 {
649 const FcObjectType *o;
650
651 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
652 test->next = 0;
653 test->kind = kind;
654 test->qual = qual;
655 test->field = (char *) FcStrCopy (field);
656 test->op = compare;
657 test->expr = expr;
658 o = FcNameGetObjectType (test->field);
659 if (o)
660 FcTypecheckExpr (parse, expr, o->type);
661 }
662 return test;
663}
664
665static FcEdit *
666FcEditCreate (FcConfigParse *parse,
667 const char *field,
668 FcOp op,
669 FcExpr *expr,
670 FcValueBinding binding)
671{
672 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
673
674 if (e)
675 {
676 const FcObjectType *o;
677
678 e->next = 0;
679 e->field = field; /* already saved in grammar */
680 e->op = op;
681 e->expr = expr;
682 e->binding = binding;
683 o = FcNameGetObjectType (e->field);
684 if (o)
685 FcTypecheckExpr (parse, expr, o->type);
686 }
687 return e;
688}
689
c2e7c611
KP
690static void
691FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
24330d27 692{
c2e7c611
KP
693 vstack->prev = parse->vstack;
694 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
695 parse->vstack = vstack;
24330d27
KP
696}
697
c2e7c611
KP
698static FcVStack *
699FcVStackCreate (void)
24330d27 700{
c2e7c611 701 FcVStack *new;
24330d27 702
c2e7c611
KP
703 new = malloc (sizeof (FcVStack));
704 if (!new)
705 return 0;
9dac3c59 706 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
707 new->tag = FcVStackNone;
708 new->prev = 0;
709 return new;
710}
24330d27 711
c2e7c611
KP
712static void
713FcVStackDestroy (FcVStack *vstack)
24330d27 714{
c2e7c611 715 FcVStack *prev;
24330d27 716
c2e7c611
KP
717 for (; vstack; vstack = prev)
718 {
719 prev = vstack->prev;
720 switch (vstack->tag) {
721 case FcVStackNone:
722 break;
723 case FcVStackString:
724 case FcVStackFamily:
725 case FcVStackField:
726 case FcVStackConstant:
d47c9d6e 727 case FcVStackGlob:
c2e7c611
KP
728 FcStrFree (vstack->u.string);
729 break;
4f27c1c0
KP
730 case FcVStackPattern:
731 FcPatternDestroy (vstack->u.pattern);
732 break;
c2e7c611
KP
733 case FcVStackInteger:
734 case FcVStackDouble:
735 break;
736 case FcVStackMatrix:
737 FcMatrixFree (vstack->u.matrix);
738 break;
739 case FcVStackBool:
740 break;
741 case FcVStackTest:
742 FcTestDestroy (vstack->u.test);
743 break;
744 case FcVStackExpr:
745 case FcVStackPrefer:
746 case FcVStackAccept:
747 case FcVStackDefault:
748 FcExprDestroy (vstack->u.expr);
749 break;
750 case FcVStackEdit:
751 FcEditDestroy (vstack->u.edit);
752 break;
753 }
9dac3c59 754 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
755 free (vstack);
756 }
24330d27
KP
757}
758
759static FcBool
c2e7c611 760FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 761{
c2e7c611
KP
762 FcVStack *vstack = FcVStackCreate ();
763 if (!vstack)
764 return FcFalse;
765 vstack->u.string = string;
766 vstack->tag = tag;
767 FcVStackPush (parse, vstack);
768 return FcTrue;
24330d27
KP
769}
770
771static FcBool
c2e7c611 772FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 773{
c2e7c611
KP
774 FcVStack *vstack = FcVStackCreate ();
775 if (!vstack)
24330d27 776 return FcFalse;
c2e7c611
KP
777 vstack->u.integer = integer;
778 vstack->tag = FcVStackInteger;
779 FcVStackPush (parse, vstack);
780 return FcTrue;
24330d27
KP
781}
782
783static FcBool
c2e7c611 784FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 785{
c2e7c611
KP
786 FcVStack *vstack = FcVStackCreate ();
787 if (!vstack)
24330d27 788 return FcFalse;
c2e7c611
KP
789 vstack->u._double = _double;
790 vstack->tag = FcVStackDouble;
791 FcVStackPush (parse, vstack);
792 return FcTrue;
24330d27
KP
793}
794
795static FcBool
c2e7c611 796FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 797{
c2e7c611
KP
798 FcVStack *vstack = FcVStackCreate ();
799 if (!vstack)
24330d27 800 return FcFalse;
c2e7c611
KP
801 matrix = FcMatrixCopy (matrix);
802 if (!matrix)
24330d27 803 {
c2e7c611
KP
804 FcVStackDestroy (vstack);
805 return FcFalse;
24330d27 806 }
c2e7c611
KP
807 vstack->u.matrix = matrix;
808 vstack->tag = FcVStackMatrix;
809 FcVStackPush (parse, vstack);
810 return FcTrue;
24330d27
KP
811}
812
813static FcBool
c2e7c611 814FcVStackPushBool (FcConfigParse *parse, FcBool bool)
24330d27 815{
c2e7c611
KP
816 FcVStack *vstack = FcVStackCreate ();
817 if (!vstack)
818 return FcFalse;
819 vstack->u.bool = bool;
820 vstack->tag = FcVStackBool;
821 FcVStackPush (parse, vstack);
822 return FcTrue;
823}
24330d27 824
c2e7c611
KP
825static FcBool
826FcVStackPushTest (FcConfigParse *parse, FcTest *test)
827{
828 FcVStack *vstack = FcVStackCreate ();
829 if (!vstack)
24330d27 830 return FcFalse;
c2e7c611
KP
831 vstack->u.test = test;
832 vstack->tag = FcVStackTest;
833 FcVStackPush (parse, vstack);
24330d27
KP
834 return FcTrue;
835}
836
837static FcBool
c2e7c611 838FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 839{
c2e7c611
KP
840 FcVStack *vstack = FcVStackCreate ();
841 if (!vstack)
842 return FcFalse;
843 vstack->u.expr = expr;
844 vstack->tag = tag;
845 FcVStackPush (parse, vstack);
846 return FcTrue;
847}
24330d27 848
c2e7c611
KP
849static FcBool
850FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
851{
852 FcVStack *vstack = FcVStackCreate ();
853 if (!vstack)
24330d27 854 return FcFalse;
c2e7c611
KP
855 vstack->u.edit = edit;
856 vstack->tag = FcVStackEdit;
857 FcVStackPush (parse, vstack);
24330d27
KP
858 return FcTrue;
859}
860
4f27c1c0
KP
861static FcBool
862FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
863{
864 FcVStack *vstack = FcVStackCreate ();
865 if (!vstack)
866 return FcFalse;
867 vstack->u.pattern = pattern;
868 vstack->tag = FcVStackPattern;
869 FcVStackPush (parse, vstack);
870 return FcTrue;
871}
872
c2e7c611
KP
873static FcVStack *
874FcVStackFetch (FcConfigParse *parse, int off)
24330d27 875{
c2e7c611 876 FcVStack *vstack;
24330d27 877
c2e7c611
KP
878 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
879 return vstack;
880}
881
882static void
883FcVStackClear (FcConfigParse *parse)
884{
885 while (parse->vstack && parse->vstack->pstack == parse->pstack)
24330d27 886 {
c2e7c611
KP
887 FcVStack *vstack = parse->vstack;
888 parse->vstack = vstack->prev;
889 vstack->prev = 0;
890 FcVStackDestroy (vstack);
24330d27 891 }
24330d27
KP
892}
893
c2e7c611
KP
894static FcVStack *
895FcVStackPop (FcConfigParse *parse)
24330d27 896{
c2e7c611 897 FcVStack *vstack = parse->vstack;
24330d27 898
c2e7c611 899 if (!vstack || vstack->pstack != parse->pstack)
24330d27 900 return 0;
c2e7c611
KP
901 parse->vstack = vstack->prev;
902 vstack->prev = 0;
903 return vstack;
904}
905
906static int
907FcVStackElements (FcConfigParse *parse)
908{
909 int h = 0;
910 FcVStack *vstack = parse->vstack;
911 while (vstack && vstack->pstack == parse->pstack)
912 {
913 h++;
914 vstack = vstack->prev;
24330d27 915 }
c2e7c611 916 return h;
24330d27
KP
917}
918
c2e7c611
KP
919static FcChar8 **
920FcConfigSaveAttr (const XML_Char **attr)
24330d27 921{
c2e7c611
KP
922 int n;
923 int slen;
924 int i;
925 FcChar8 **new;
926 FcChar8 *s;
24330d27 927
c2e7c611
KP
928 if (!attr)
929 return 0;
930 slen = 0;
931 for (i = 0; attr[i]; i++)
932 slen += strlen (attr[i]) + 1;
933 n = i;
934 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
935 if (!new)
936 return 0;
9dac3c59 937 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
c2e7c611
KP
938 s = (FcChar8 *) (new + (i + 1));
939 for (i = 0; attr[i]; i++)
24330d27 940 {
c2e7c611
KP
941 new[i] = s;
942 strcpy ((char *) s, (char *) attr[i]);
943 s += strlen ((char *) s) + 1;
24330d27 944 }
c2e7c611
KP
945 new[i] = 0;
946 return new;
947}
24330d27 948
c2e7c611
KP
949static FcBool
950FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
951{
952 FcPStack *new = malloc (sizeof (FcPStack));
953
954 if (!new)
955 return FcFalse;
9dac3c59 956 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
957 new->prev = parse->pstack;
958 new->element = element;
959 if (attr)
24330d27 960 {
c2e7c611
KP
961 new->attr = FcConfigSaveAttr (attr);
962 if (!new->attr)
179c3995 963 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 964 }
c2e7c611
KP
965 else
966 new->attr = 0;
967 FcStrBufInit (&new->str, 0, 0);
968 parse->pstack = new;
969 return FcTrue;
970}
24330d27 971
c2e7c611
KP
972static FcBool
973FcPStackPop (FcConfigParse *parse)
974{
975 FcPStack *old;
976
977 if (!parse->pstack)
24330d27 978 {
179c3995 979 FcConfigMessage (parse, FcSevereError, "mismatching element");
c2e7c611 980 return FcFalse;
24330d27 981 }
c2e7c611
KP
982 FcVStackClear (parse);
983 old = parse->pstack;
984 parse->pstack = old->prev;
985 FcStrBufDestroy (&old->str);
986 if (old->attr)
9dac3c59
KP
987 {
988 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
c2e7c611 989 free (old->attr);
9dac3c59
KP
990 }
991 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
992 free (old);
993 return FcTrue;
24330d27
KP
994}
995
c2e7c611
KP
996static FcBool
997FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
24330d27 998{
c2e7c611
KP
999 parse->pstack = 0;
1000 parse->vstack = 0;
1001 parse->error = FcFalse;
1002 parse->name = name;
1003 parse->config = config;
1004 parse->parser = parser;
1005 return FcTrue;
1006}
1007
1008static void
1009FcConfigCleanup (FcConfigParse *parse)
1010{
1011 while (parse->pstack)
1012 FcPStackPop (parse);
1013}
1014
1015static const FcChar8 *
67accef4 1016FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
c2e7c611
KP
1017{
1018 FcChar8 **attrs;
1019 if (!parse->pstack)
24330d27 1020 return 0;
24330d27 1021
c2e7c611
KP
1022 attrs = parse->pstack->attr;
1023 while (*attrs)
24330d27 1024 {
c2e7c611
KP
1025 if (!strcmp ((char *) *attrs, attr))
1026 return attrs[1];
1027 attrs += 2;
24330d27 1028 }
24330d27
KP
1029 return 0;
1030}
1031
c2e7c611
KP
1032static void
1033FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
24330d27 1034{
c2e7c611
KP
1035 FcConfigParse *parse = userData;
1036 FcElement element;
1037
1038 element = FcElementMap (name);
1039 if (element == FcElementUnknown)
179c3995 1040 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
c2e7c611
KP
1041
1042 if (!FcPStackPush (parse, element, attr))
24330d27 1043 {
179c3995 1044 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1045 return;
24330d27 1046 }
c2e7c611
KP
1047 return;
1048}
24330d27 1049
c2e7c611
KP
1050static void
1051FcParseBlank (FcConfigParse *parse)
1052{
1053 int n = FcVStackElements (parse);
1054 while (n-- > 0)
24330d27 1055 {
c2e7c611
KP
1056 FcVStack *v = FcVStackFetch (parse, n);
1057 if (v->tag != FcVStackInteger)
179c3995 1058 FcConfigMessage (parse, FcSevereError, "non-integer blank");
c2e7c611 1059 else
24330d27 1060 {
c2e7c611 1061 if (!parse->config->blanks)
24330d27 1062 {
c2e7c611
KP
1063 parse->config->blanks = FcBlanksCreate ();
1064 if (!parse->config->blanks)
1065 {
179c3995 1066 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1067 break;
1068 }
24330d27 1069 }
c2e7c611 1070 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
24330d27 1071 {
179c3995 1072 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1073 break;
24330d27
KP
1074 }
1075 }
1076 }
c2e7c611 1077}
24330d27 1078
179c3995
KP
1079static void
1080FcParseRescan (FcConfigParse *parse)
1081{
1082 int n = FcVStackElements (parse);
1083 while (n-- > 0)
1084 {
1085 FcVStack *v = FcVStackFetch (parse, n);
1086 if (v->tag != FcVStackInteger)
1087 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1088 else
1089 parse->config->rescanInterval = v->u.integer;
1090 }
1091}
1092
c2e7c611
KP
1093static void
1094FcParseInt (FcConfigParse *parse)
1095{
1096 FcChar8 *s, *end;
1097 int l;
1098
1099 if (!parse->pstack)
1100 return;
1101 s = FcStrBufDone (&parse->pstack->str);
1102 if (!s)
24330d27 1103 {
179c3995 1104 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1105 return;
24330d27 1106 }
c2e7c611
KP
1107 end = 0;
1108 l = (int) strtol ((char *) s, (char **)&end, 0);
1109 if (end != s + strlen ((char *) s))
179c3995 1110 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
c2e7c611
KP
1111 else
1112 FcVStackPushInteger (parse, l);
1113 FcStrFree (s);
24330d27
KP
1114}
1115
223c0289
KP
1116/*
1117 * idea copied from glib g_ascii_strtod with
1118 * permission of the author (Alexander Larsson)
1119 */
1120
1121#include <locale.h>
1122
1123static double
1124FcStrtod (char *s, char **end)
1125{
1126 struct lconv *locale_data;
1127 char *dot;
1128 double v;
1129
1130 /*
1131 * Have to swap the decimal point to match the current locale
1132 * if that locale doesn't use 0x2e
1133 */
1134 if ((dot = strchr (s, 0x2e)) &&
1135 (locale_data = localeconv ()) &&
1136 (locale_data->decimal_point[0] != 0x2e ||
1137 locale_data->decimal_point[1] != 0))
1138 {
1139 char buf[128];
1140 int slen = strlen (s);
1141 int dlen = strlen (locale_data->decimal_point);
1142
67accef4 1143 if (slen + dlen > (int) sizeof (buf))
223c0289
KP
1144 {
1145 if (end)
1146 *end = s;
1147 v = 0;
1148 }
1149 else
1150 {
1151 char *buf_end;
1152 /* mantissa */
1153 strncpy (buf, s, dot - s);
1154 /* decimal point */
1155 strcpy (buf + (dot - s), locale_data->decimal_point);
1156 /* rest of number */
1157 strcpy (buf + (dot - s) + dlen, dot + 1);
1158 buf_end = 0;
1159 v = strtod (buf, &buf_end);
344a0e33
RP
1160 if (buf_end) {
1161 buf_end = s + (buf_end - buf);
1162 if (buf_end > dot)
1163 buf_end -= dlen - 1;
1164 }
223c0289
KP
1165 if (end)
1166 *end = buf_end;
1167 }
1168 }
1169 else
1170 v = strtod (s, end);
1171 return v;
1172}
1173
c2e7c611
KP
1174static void
1175FcParseDouble (FcConfigParse *parse)
24330d27 1176{
c2e7c611
KP
1177 FcChar8 *s, *end;
1178 double d;
24330d27 1179
c2e7c611
KP
1180 if (!parse->pstack)
1181 return;
1182 s = FcStrBufDone (&parse->pstack->str);
1183 if (!s)
24330d27 1184 {
179c3995 1185 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1186 return;
24330d27 1187 }
c2e7c611 1188 end = 0;
223c0289 1189 d = FcStrtod ((char *) s, (char **)&end);
c2e7c611 1190 if (end != s + strlen ((char *) s))
179c3995 1191 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
24330d27 1192 else
c2e7c611
KP
1193 FcVStackPushDouble (parse, d);
1194 FcStrFree (s);
1195}
24330d27 1196
c2e7c611
KP
1197static void
1198FcParseString (FcConfigParse *parse, FcVStackTag tag)
1199{
1200 FcChar8 *s;
1201
1202 if (!parse->pstack)
1203 return;
1204 s = FcStrBufDone (&parse->pstack->str);
1205 if (!s)
1206 {
179c3995 1207 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1208 return;
1209 }
1210 if (!FcVStackPushString (parse, tag, s))
1211 FcStrFree (s);
1212}
1213
1214static void
1215FcParseMatrix (FcConfigParse *parse)
1216{
1217 FcVStack *vstack;
1218 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1219 FcMatrix m;
1220
1221 while ((vstack = FcVStackPop (parse)))
1222 {
179c3995
KP
1223 double v;
1224 switch (vstack->tag) {
1225 case FcVStackInteger:
1226 v = vstack->u.integer;
1227 break;
1228 case FcVStackDouble:
1229 v = vstack->u._double;
1230 break;
1231 default:
1232 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1233 v = 1.0;
1234 break;
1235 }
1236 switch (matrix_state) {
1237 case m_xx: m.xx = v; break;
1238 case m_xy: m.xy = v; break;
1239 case m_yx: m.yx = v; break;
1240 case m_yy: m.yy = v; break;
1241 default: break;
c2e7c611 1242 }
f4fe447f 1243 FcVStackDestroy (vstack);
179c3995 1244 matrix_state--;
c2e7c611
KP
1245 }
1246 if (matrix_state != m_done)
179c3995 1247 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
c2e7c611
KP
1248 else
1249 FcVStackPushMatrix (parse, &m);
24330d27
KP
1250}
1251
1252static FcBool
ca60d2b5 1253FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
c2e7c611 1254{
ca60d2b5
KP
1255 FcBool result = FcFalse;
1256
1257 if (!FcNameBool (bool, &result))
1258 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1259 bool);
1260 return result;
c2e7c611
KP
1261}
1262
1263static void
1264FcParseBool (FcConfigParse *parse)
1265{
1266 FcChar8 *s;
1267
1268 if (!parse->pstack)
1269 return;
1270 s = FcStrBufDone (&parse->pstack->str);
1271 if (!s)
1272 {
179c3995 1273 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1274 return;
1275 }
ca60d2b5 1276 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
c2e7c611
KP
1277 FcStrFree (s);
1278}
1279
1280static void
1281FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1282{
c2e7c611
KP
1283 FcVStack *vstack;
1284 FcExpr *left, *expr = 0, *new;
1285
1286 while ((vstack = FcVStackPop (parse)))
1287 {
1288 if (vstack->tag != FcVStackFamily)
1289 {
179c3995
KP
1290 FcConfigMessage (parse, FcSevereWarning, "non-family");
1291 FcVStackDestroy (vstack);
1292 continue;
c2e7c611
KP
1293 }
1294 left = vstack->u.expr;
1295 vstack->tag = FcVStackNone;
1296 FcVStackDestroy (vstack);
1297 if (expr)
1298 {
1299 new = FcExprCreateOp (left, FcOpComma, expr);
1300 if (!new)
1301 {
179c3995 1302 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1303 FcExprDestroy (left);
1304 FcExprDestroy (expr);
1305 break;
1306 }
1307 expr = new;
1308 }
1309 else
1310 expr = left;
1311 }
1312 if (expr)
1313 {
1314 if (!FcVStackPushExpr (parse, tag, expr))
1315 {
179c3995 1316 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1317 if (expr)
1318 FcExprDestroy (expr);
1319 }
1320 }
1321}
1322
1323static void
1324FcParseFamily (FcConfigParse *parse)
1325{
1326 FcChar8 *s;
1327 FcExpr *expr;
1328
1329 if (!parse->pstack)
1330 return;
1331 s = FcStrBufDone (&parse->pstack->str);
1332 if (!s)
1333 {
179c3995 1334 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1335 return;
1336 }
1337 expr = FcExprCreateString (s);
1338 FcStrFree (s);
1339 if (expr)
1340 FcVStackPushExpr (parse, FcVStackFamily, expr);
1341}
1342
1343static void
1344FcParseAlias (FcConfigParse *parse)
1345{
179c3995 1346 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1347 FcEdit *edit = 0, *next;
c2e7c611 1348 FcVStack *vstack;
24330d27
KP
1349 FcTest *test;
1350
c2e7c611 1351 while ((vstack = FcVStackPop (parse)))
24330d27 1352 {
c2e7c611
KP
1353 switch (vstack->tag) {
1354 case FcVStackFamily:
1355 if (family)
179c3995
KP
1356 {
1357 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1358 if (!new)
1359 FcConfigMessage (parse, FcSevereError, "out of memory");
1360 else
1361 family = new;
1362 }
1363 else
1364 new = vstack->u.expr;
1365 if (new)
1366 {
1367 family = new;
1368 vstack->tag = FcVStackNone;
1369 }
c2e7c611
KP
1370 break;
1371 case FcVStackPrefer:
1372 if (prefer)
1373 FcExprDestroy (prefer);
1374 prefer = vstack->u.expr;
1375 vstack->tag = FcVStackNone;
1376 break;
1377 case FcVStackAccept:
1378 if (accept)
1379 FcExprDestroy (accept);
1380 accept = vstack->u.expr;
1381 vstack->tag = FcVStackNone;
1382 break;
1383 case FcVStackDefault:
1384 if (def)
1385 FcExprDestroy (def);
1386 def = vstack->u.expr;
1387 vstack->tag = FcVStackNone;
1388 break;
1389 default:
179c3995 1390 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1391 break;
1392 }
1393 FcVStackDestroy (vstack);
24330d27 1394 }
ccb3e93b 1395 if (!family)
c2e7c611 1396 {
179c3995
KP
1397 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1398 if (prefer)
1399 FcExprDestroy (prefer);
1400 if (accept)
1401 FcExprDestroy (accept);
1402 if (def)
1403 FcExprDestroy (def);
c2e7c611
KP
1404 return;
1405 }
24330d27
KP
1406 if (prefer)
1407 {
ca60d2b5
KP
1408 edit = FcEditCreate (parse,
1409 FcConfigSaveField ("family"),
24330d27 1410 FcOpPrepend,
6fff2cda
KP
1411 prefer,
1412 FcValueBindingWeak);
24330d27
KP
1413 if (edit)
1414 edit->next = 0;
c2e7c611
KP
1415 else
1416 FcExprDestroy (prefer);
24330d27
KP
1417 }
1418 if (accept)
1419 {
1420 next = edit;
ca60d2b5
KP
1421 edit = FcEditCreate (parse,
1422 FcConfigSaveField ("family"),
24330d27 1423 FcOpAppend,
6fff2cda
KP
1424 accept,
1425 FcValueBindingWeak);
24330d27
KP
1426 if (edit)
1427 edit->next = next;
c2e7c611
KP
1428 else
1429 FcExprDestroy (accept);
24330d27
KP
1430 }
1431 if (def)
1432 {
1433 next = edit;
ca60d2b5
KP
1434 edit = FcEditCreate (parse,
1435 FcConfigSaveField ("family"),
6fff2cda
KP
1436 FcOpAppendLast,
1437 def,
1438 FcValueBindingWeak);
24330d27
KP
1439 if (edit)
1440 edit->next = next;
c2e7c611
KP
1441 else
1442 FcExprDestroy (def);
24330d27
KP
1443 }
1444 if (edit)
1445 {
ca60d2b5 1446 test = FcTestCreate (parse, FcMatchPattern,
938bc633 1447 FcQualAny,
2623c1eb 1448 (FcChar8 *) FC_FAMILY,
24330d27
KP
1449 FcOpEqual,
1450 family);
1451 if (test)
c2e7c611
KP
1452 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1453 FcTestDestroy (test);
24330d27 1454 }
c2e7c611
KP
1455 else
1456 FcExprDestroy (family);
24330d27
KP
1457}
1458
c2e7c611
KP
1459static FcExpr *
1460FcPopExpr (FcConfigParse *parse)
24330d27 1461{
c2e7c611
KP
1462 FcVStack *vstack = FcVStackPop (parse);
1463 FcExpr *expr = 0;
1464 if (!vstack)
1465 return 0;
1466 switch (vstack->tag) {
1467 case FcVStackNone:
1468 break;
1469 case FcVStackString:
1470 case FcVStackFamily:
bbbaac36
KP
1471 expr = FcExprCreateString (vstack->u.string);
1472 break;
c2e7c611 1473 case FcVStackField:
bbbaac36
KP
1474 expr = FcExprCreateField ((char *) vstack->u.string);
1475 break;
c2e7c611 1476 case FcVStackConstant:
bbbaac36 1477 expr = FcExprCreateConst (vstack->u.string);
c2e7c611 1478 break;
34cd0514
CW
1479 case FcVStackGlob:
1480 /* XXX: What's the correct action here? (CDW) */
1481 break;
c2e7c611
KP
1482 case FcVStackPrefer:
1483 case FcVStackAccept:
1484 case FcVStackDefault:
1485 expr = vstack->u.expr;
1486 vstack->tag = FcVStackNone;
1487 break;
1488 case FcVStackInteger:
1489 expr = FcExprCreateInteger (vstack->u.integer);
1490 break;
1491 case FcVStackDouble:
1492 expr = FcExprCreateDouble (vstack->u._double);
1493 break;
1494 case FcVStackMatrix:
1495 expr = FcExprCreateMatrix (vstack->u.matrix);
1496 break;
1497 case FcVStackBool:
1498 expr = FcExprCreateBool (vstack->u.bool);
1499 break;
1500 case FcVStackTest:
1501 break;
1502 case FcVStackExpr:
1503 expr = vstack->u.expr;
8ec077f2 1504 vstack->tag = FcVStackNone;
c2e7c611
KP
1505 break;
1506 case FcVStackEdit:
1507 break;
4f27c1c0
KP
1508 default:
1509 break;
c2e7c611
KP
1510 }
1511 FcVStackDestroy (vstack);
1512 return expr;
1513}
1514
3f7653c2
KP
1515/*
1516 * This builds a tree of binary operations. Note
1517 * that every operator is defined so that if only
1518 * a single operand is contained, the value of the
1519 * whole expression is the value of the operand.
1520 *
1521 * This code reduces in that case to returning that
1522 * operand.
1523 */
c2e7c611 1524static FcExpr *
3f7653c2 1525FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1526{
1527 FcExpr *left, *expr = 0, *new;
24330d27 1528
c2e7c611 1529 while ((left = FcPopExpr (parse)))
24330d27 1530 {
c2e7c611 1531 if (expr)
24330d27 1532 {
c2e7c611
KP
1533 new = FcExprCreateOp (left, op, expr);
1534 if (!new)
1535 {
179c3995 1536 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1537 FcExprDestroy (left);
1538 FcExprDestroy (expr);
24330d27 1539 break;
c2e7c611
KP
1540 }
1541 expr = new;
24330d27 1542 }
c2e7c611
KP
1543 else
1544 expr = left;
1545 }
1546 return expr;
1547}
1548
1549static void
3f7653c2
KP
1550FcParseBinary (FcConfigParse *parse, FcOp op)
1551{
1552 FcExpr *expr = FcPopBinary (parse, op);
1553 if (expr)
1554 FcVStackPushExpr (parse, FcVStackExpr, expr);
1555}
1556
1557/*
1558 * This builds a a unary operator, it consumes only
1559 * a single operand
1560 */
1561
1562static FcExpr *
1563FcPopUnary (FcConfigParse *parse, FcOp op)
1564{
1565 FcExpr *operand, *new = 0;
1566
1567 if ((operand = FcPopExpr (parse)))
1568 {
1569 new = FcExprCreateOp (operand, op, 0);
1570 if (!new)
1571 {
1572 FcExprDestroy (operand);
1573 FcConfigMessage (parse, FcSevereError, "out of memory");
1574 }
1575 }
1576 return new;
1577}
1578
1579static void
1580FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1581{
3f7653c2 1582 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1583 if (expr)
1584 FcVStackPushExpr (parse, FcVStackExpr, expr);
1585}
1586
1587static void
1588FcParseInclude (FcConfigParse *parse)
1589{
1590 FcChar8 *s;
1591 const FcChar8 *i;
1592 FcBool ignore_missing = FcFalse;
1593
1594 s = FcStrBufDone (&parse->pstack->str);
1595 if (!s)
1596 {
179c3995 1597 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1598 return;
1599 }
1600 i = FcConfigGetAttribute (parse, "ignore_missing");
ca60d2b5 1601 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
c2e7c611 1602 ignore_missing = FcTrue;
24c90386 1603 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1604 parse->error = FcTrue;
9dac3c59 1605 FcStrFree (s);
c2e7c611
KP
1606}
1607
1608typedef struct _FcOpMap {
67accef4 1609 char name[16];
c2e7c611
KP
1610 FcOp op;
1611} FcOpMap;
1612
1613static FcOp
1614FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1615{
1616 int i;
1617
1618 for (i = 0; i < nmap; i++)
1619 if (!strcmp ((char *) op, map[i].name))
1620 return map[i].op;
1621 return FcOpInvalid;
1622}
1623
1624static const FcOpMap fcCompareOps[] = {
1625 { "eq", FcOpEqual },
1626 { "not_eq", FcOpNotEqual },
1627 { "less", FcOpLess },
1628 { "less_eq", FcOpLessEqual },
1629 { "more", FcOpMore },
47d4f950
KP
1630 { "more_eq", FcOpMoreEqual },
1631 { "contains", FcOpContains },
1632 { "not_contains", FcOpNotContains }
c2e7c611
KP
1633};
1634
67accef4 1635#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
c2e7c611
KP
1636
1637static FcOp
1638FcConfigLexCompare (const FcChar8 *compare)
1639{
1640 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1641}
1642
1643
1644static void
1645FcParseTest (FcConfigParse *parse)
1646{
938bc633
KP
1647 const FcChar8 *kind_string;
1648 FcMatchKind kind;
c2e7c611
KP
1649 const FcChar8 *qual_string;
1650 FcQual qual;
1651 const FcChar8 *name;
1652 const FcChar8 *compare_string;
1653 FcOp compare;
1654 FcExpr *expr;
1655 FcTest *test;
1656
938bc633
KP
1657 kind_string = FcConfigGetAttribute (parse, "target");
1658 if (!kind_string)
1659 kind = FcMatchDefault;
1660 else
1661 {
1662 if (!strcmp ((char *) kind_string, "pattern"))
1663 kind = FcMatchPattern;
1664 else if (!strcmp ((char *) kind_string, "font"))
1665 kind = FcMatchFont;
1666 else if (!strcmp ((char *) kind_string, "default"))
1667 kind = FcMatchDefault;
1668 else
1669 {
1670 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1671 return;
1672 }
1673 }
c2e7c611
KP
1674 qual_string = FcConfigGetAttribute (parse, "qual");
1675 if (!qual_string)
1676 qual = FcQualAny;
1677 else
1678 {
1679 if (!strcmp ((char *) qual_string, "any"))
1680 qual = FcQualAny;
1681 else if (!strcmp ((char *) qual_string, "all"))
1682 qual = FcQualAll;
6f6563ed
KP
1683 else if (!strcmp ((char *) qual_string, "first"))
1684 qual = FcQualFirst;
1685 else if (!strcmp ((char *) qual_string, "not_first"))
1686 qual = FcQualNotFirst;
c2e7c611 1687 else
24330d27 1688 {
179c3995 1689 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1690 return;
24330d27 1691 }
c2e7c611
KP
1692 }
1693 name = FcConfigGetAttribute (parse, "name");
1694 if (!name)
1695 {
179c3995 1696 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1697 return;
c2e7c611
KP
1698 }
1699 compare_string = FcConfigGetAttribute (parse, "compare");
1700 if (!compare_string)
1701 compare = FcOpEqual;
1702 else
1703 {
1704 compare = FcConfigLexCompare (compare_string);
1705 if (compare == FcOpInvalid)
24330d27 1706 {
179c3995 1707 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1708 return;
24330d27 1709 }
c2e7c611 1710 }
3f7653c2 1711 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1712 if (!expr)
1713 {
179c3995 1714 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1715 return;
1716 }
ca60d2b5 1717 test = FcTestCreate (parse, kind, qual, name, compare, expr);
c2e7c611
KP
1718 if (!test)
1719 {
179c3995 1720 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1721 return;
1722 }
1723 FcVStackPushTest (parse, test);
1724}
1725
1726static const FcOpMap fcModeOps[] = {
1727 { "assign", FcOpAssign },
1728 { "assign_replace", FcOpAssignReplace },
1729 { "prepend", FcOpPrepend },
1730 { "prepend_first", FcOpPrependFirst },
1731 { "append", FcOpAppend },
1732 { "append_last", FcOpAppendLast },
1733};
1734
67accef4 1735#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
c2e7c611
KP
1736
1737static FcOp
1738FcConfigLexMode (const FcChar8 *mode)
1739{
1740 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1741}
1742
1743static void
1744FcParseEdit (FcConfigParse *parse)
1745{
1746 const FcChar8 *name;
1747 const FcChar8 *mode_string;
6fff2cda 1748 const FcChar8 *binding_string;
c2e7c611 1749 FcOp mode;
6fff2cda 1750 FcValueBinding binding;
c2e7c611
KP
1751 FcExpr *expr;
1752 FcEdit *edit;
1753
1754 name = FcConfigGetAttribute (parse, "name");
1755 if (!name)
1756 {
179c3995 1757 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1758 return;
c2e7c611
KP
1759 }
1760 mode_string = FcConfigGetAttribute (parse, "mode");
1761 if (!mode_string)
8ec077f2 1762 mode = FcOpAssign;
c2e7c611
KP
1763 else
1764 {
1765 mode = FcConfigLexMode (mode_string);
1766 if (mode == FcOpInvalid)
24330d27 1767 {
179c3995 1768 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1769 return;
24330d27 1770 }
c2e7c611 1771 }
6fff2cda
KP
1772 binding_string = FcConfigGetAttribute (parse, "binding");
1773 if (!binding_string)
1774 binding = FcValueBindingWeak;
1775 else
1776 {
1777 if (!strcmp ((char *) binding_string, "weak"))
1778 binding = FcValueBindingWeak;
1779 else if (!strcmp ((char *) binding_string, "strong"))
1780 binding = FcValueBindingStrong;
dda7794f
KP
1781 else if (!strcmp ((char *) binding_string, "same"))
1782 binding = FcValueBindingSame;
6fff2cda
KP
1783 else
1784 {
1785 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1786 return;
1787 }
1788 }
3f7653c2 1789 expr = FcPopBinary (parse, FcOpComma);
ca60d2b5 1790 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
c2e7c611
KP
1791 if (!edit)
1792 {
179c3995 1793 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1794 FcExprDestroy (expr);
1795 return;
1796 }
1797 if (!FcVStackPushEdit (parse, edit))
1798 FcEditDestroy (edit);
1799}
1800
1801static void
1802FcParseMatch (FcConfigParse *parse)
1803{
1804 const FcChar8 *kind_name;
1805 FcMatchKind kind;
1806 FcTest *test = 0;
1807 FcEdit *edit = 0;
1808 FcVStack *vstack;
1809
1810 kind_name = FcConfigGetAttribute (parse, "target");
1811 if (!kind_name)
1812 kind = FcMatchPattern;
1813 else
1814 {
1815 if (!strcmp ((char *) kind_name, "pattern"))
1816 kind = FcMatchPattern;
1817 else if (!strcmp ((char *) kind_name, "font"))
1818 kind = FcMatchFont;
1819 else
24330d27 1820 {
179c3995 1821 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1822 return;
24330d27 1823 }
c2e7c611
KP
1824 }
1825 while ((vstack = FcVStackPop (parse)))
1826 {
1827 switch (vstack->tag) {
1828 case FcVStackTest:
1829 vstack->u.test->next = test;
1830 test = vstack->u.test;
1831 vstack->tag = FcVStackNone;
1832 break;
1833 case FcVStackEdit:
1834 vstack->u.edit->next = edit;
1835 edit = vstack->u.edit;
1836 vstack->tag = FcVStackNone;
1837 break;
1838 default:
179c3995 1839 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1840 break;
1841 }
1842 FcVStackDestroy (vstack);
1843 }
1844 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1845 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1846}
1847
d47c9d6e
KP
1848static void
1849FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1850{
1851 FcVStack *vstack;
1852
1853 while ((vstack = FcVStackPop (parse)))
1854 {
1855 switch (vstack->tag) {
1856 case FcVStackGlob:
1857 if (!FcConfigGlobAdd (parse->config,
1858 vstack->u.string,
1859 element == FcElementAcceptfont))
1860 {
1861 FcConfigMessage (parse, FcSevereError, "out of memory");
1862 }
1863 break;
4f27c1c0
KP
1864 case FcVStackPattern:
1865 if (!FcConfigPatternsAdd (parse->config,
1866 vstack->u.pattern,
1867 element == FcElementAcceptfont))
1868 {
1869 FcConfigMessage (parse, FcSevereError, "out of memory");
1870 }
1871 else
1872 vstack->tag = FcVStackNone;
1873 break;
d47c9d6e
KP
1874 default:
1875 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1876 break;
1877 }
1878 FcVStackDestroy (vstack);
1879 }
1880}
1881
4f27c1c0
KP
1882
1883static FcValue
1884FcPopValue (FcConfigParse *parse)
1885{
1886 FcVStack *vstack = FcVStackPop (parse);
1887 FcValue value;
1888
1889 value.type = FcTypeVoid;
1890
1891 if (!vstack)
1892 return value;
1893
1894 switch (vstack->tag) {
1895 case FcVStackString:
4262e0b3
PL
1896 value.u.s = FcStrCopy (vstack->u.string);
1897 if (value.u.s)
4f27c1c0
KP
1898 value.type = FcTypeString;
1899 break;
1900 case FcVStackConstant:
1901 if (FcNameConstant (vstack->u.string, &value.u.i))
1902 value.type = FcTypeInteger;
1903 break;
1904 case FcVStackInteger:
1905 value.u.i = vstack->u.integer;
1906 value.type = FcTypeInteger;
1907 break;
1908 case FcVStackDouble:
1909 value.u.d = vstack->u._double;
1910 value.type = FcTypeInteger;
1911 break;
1912 case FcVStackMatrix:
4262e0b3
PL
1913 value.u.m = FcMatrixCopy (vstack->u.matrix);
1914 if (value.u.m)
4f27c1c0
KP
1915 value.type = FcTypeMatrix;
1916 break;
1917 case FcVStackBool:
1918 value.u.b = vstack->u.bool;
1919 value.type = FcTypeBool;
1920 break;
1921 default:
1922 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1923 vstack->tag);
1924 break;
1925 }
1926 FcVStackDestroy (vstack);
1927
1928 return value;
1929}
1930
1931static void
1932FcParsePatelt (FcConfigParse *parse)
1933{
1934 FcValue value;
1935 FcPattern *pattern = FcPatternCreate ();
1936 const char *name;
1937
1938 if (!pattern)
1939 {
1940 FcConfigMessage (parse, FcSevereError, "out of memory");
1941 return;
1942 }
1943
8245771d 1944 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
1945 if (!name)
1946 {
1947 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1948 return;
1949 }
4f27c1c0
KP
1950
1951 for (;;)
1952 {
1953 value = FcPopValue (parse);
1954 if (value.type == FcTypeVoid)
1955 break;
1956 if (!FcPatternAdd (pattern, name, value, FcTrue))
1957 {
1958 FcConfigMessage (parse, FcSevereError, "out of memory");
1959 break;
1960 }
1961 }
1962
1963 FcVStackPushPattern (parse, pattern);
1964}
1965
1966static void
1967FcParsePattern (FcConfigParse *parse)
1968{
1969 FcVStack *vstack;
1970 FcPattern *pattern = FcPatternCreate ();
1971
1972 if (!pattern)
1973 {
1974 FcConfigMessage (parse, FcSevereError, "out of memory");
1975 return;
1976 }
1977
1978 while ((vstack = FcVStackPop (parse)))
1979 {
1980 switch (vstack->tag) {
1981 case FcVStackPattern:
1982 if (!FcPatternAppend (pattern, vstack->u.pattern))
1983 {
1984 FcConfigMessage (parse, FcSevereError, "out of memory");
1985 return;
1986 }
1987 break;
1988 default:
1989 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1990 break;
1991 }
1992 FcVStackDestroy (vstack);
1993 }
1994
1995 FcVStackPushPattern (parse, pattern);
1996}
1997
c2e7c611
KP
1998static void
1999FcEndElement(void *userData, const XML_Char *name)
2000{
2001 FcConfigParse *parse = userData;
2002 FcChar8 *data;
2003
2004 if (!parse->pstack)
2005 return;
2006 switch (parse->pstack->element) {
2007 case FcElementNone:
2008 break;
2009 case FcElementFontconfig:
2010 break;
2011 case FcElementDir:
2012 data = FcStrBufDone (&parse->pstack->str);
2013 if (!data)
24330d27 2014 {
179c3995 2015 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2016 break;
24330d27 2017 }
daeed6e0
TL
2018#ifdef _WIN32
2019 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2020 {
2021 int rc;
2022 FcStrFree (data);
2023 data = malloc (1000);
2024 if (!data)
2025 {
2026 FcConfigMessage (parse, FcSevereError, "out of memory");
2027 break;
2028 }
2029 FcMemAlloc (FC_MEM_STRING, 1000);
2030 rc = GetWindowsDirectory (data, 800);
2031 if (rc == 0 || rc > 800)
2032 {
2033 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2034 FcStrFree (data);
2035 break;
2036 }
2037 if (data [strlen (data) - 1] != '\\')
2038 strcat (data, "\\");
2039 strcat (data, "fonts");
2040 }
2041#endif
ff3f1f98
KP
2042 if (!FcStrUsesHome (data) || FcConfigHome ())
2043 {
2044 if (!FcConfigAddDir (parse->config, data))
2045 FcConfigMessage (parse, FcSevereError, "out of memory");
2046 }
9dac3c59 2047 FcStrFree (data);
c2e7c611
KP
2048 break;
2049 case FcElementCache:
2050 data = FcStrBufDone (&parse->pstack->str);
2051 if (!data)
24330d27 2052 {
179c3995 2053 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2054 break;
c2e7c611 2055 }
ff3f1f98
KP
2056 if (!FcStrUsesHome (data) || FcConfigHome ())
2057 {
2058 if (!FcConfigSetCache (parse->config, data))
2059 FcConfigMessage (parse, FcSevereError, "out of memory");
2060 }
9dac3c59 2061 FcStrFree (data);
c2e7c611
KP
2062 break;
2063 case FcElementInclude:
2064 FcParseInclude (parse);
2065 break;
2066 case FcElementConfig:
2067 break;
2068 case FcElementMatch:
2069 FcParseMatch (parse);
2070 break;
2071 case FcElementAlias:
2072 FcParseAlias (parse);
2073 break;
2074
2075 case FcElementBlank:
2076 FcParseBlank (parse);
2077 break;
179c3995
KP
2078 case FcElementRescan:
2079 FcParseRescan (parse);
2080 break;
c2e7c611
KP
2081
2082 case FcElementPrefer:
2083 FcParseFamilies (parse, FcVStackPrefer);
2084 break;
2085 case FcElementAccept:
2086 FcParseFamilies (parse, FcVStackAccept);
2087 break;
2088 case FcElementDefault:
2089 FcParseFamilies (parse, FcVStackDefault);
2090 break;
2091 case FcElementFamily:
2092 FcParseFamily (parse);
2093 break;
2094
2095 case FcElementTest:
2096 FcParseTest (parse);
2097 break;
2098 case FcElementEdit:
2099 FcParseEdit (parse);
2100 break;
2101
2102 case FcElementInt:
2103 FcParseInt (parse);
2104 break;
2105 case FcElementDouble:
2106 FcParseDouble (parse);
2107 break;
2108 case FcElementString:
2109 FcParseString (parse, FcVStackString);
2110 break;
2111 case FcElementMatrix:
2112 FcParseMatrix (parse);
2113 break;
2114 case FcElementBool:
2115 FcParseBool (parse);
2116 break;
2117 case FcElementCharset:
2118/* FcParseCharset (parse); */
2119 break;
d47c9d6e
KP
2120 case FcElementSelectfont:
2121 break;
2122 case FcElementAcceptfont:
2123 case FcElementRejectfont:
2124 FcParseAcceptRejectFont (parse, parse->pstack->element);
2125 break;
2126 case FcElementGlob:
2127 FcParseString (parse, FcVStackGlob);
2128 break;
4f27c1c0
KP
2129 case FcElementPattern:
2130 FcParsePattern (parse);
2131 break;
2132 case FcElementPatelt:
2133 FcParsePatelt (parse);
2134 break;
c2e7c611
KP
2135 case FcElementName:
2136 FcParseString (parse, FcVStackField);
2137 break;
2138 case FcElementConst:
2139 FcParseString (parse, FcVStackConstant);
2140 break;
2141 case FcElementOr:
3f7653c2 2142 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2143 break;
2144 case FcElementAnd:
3f7653c2 2145 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2146 break;
2147 case FcElementEq:
3f7653c2 2148 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2149 break;
2150 case FcElementNotEq:
3f7653c2 2151 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2152 break;
2153 case FcElementLess:
3f7653c2 2154 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2155 break;
2156 case FcElementLessEq:
3f7653c2 2157 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2158 break;
2159 case FcElementMore:
3f7653c2 2160 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2161 break;
2162 case FcElementMoreEq:
3f7653c2 2163 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2164 break;
47d4f950 2165 case FcElementContains:
3f7653c2 2166 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2167 break;
2168 case FcElementNotContains:
3f7653c2 2169 FcParseBinary (parse, FcOpNotContains);
47d4f950 2170 break;
c2e7c611 2171 case FcElementPlus:
3f7653c2 2172 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2173 break;
2174 case FcElementMinus:
3f7653c2 2175 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2176 break;
2177 case FcElementTimes:
3f7653c2 2178 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2179 break;
2180 case FcElementDivide:
3f7653c2 2181 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2182 break;
2183 case FcElementNot:
3f7653c2 2184 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2185 break;
2186 case FcElementIf:
3f7653c2
KP
2187 FcParseBinary (parse, FcOpQuest);
2188 break;
2189 case FcElementFloor:
2190 FcParseUnary (parse, FcOpFloor);
2191 break;
2192 case FcElementCeil:
2193 FcParseUnary (parse, FcOpCeil);
2194 break;
2195 case FcElementRound:
2196 FcParseUnary (parse, FcOpRound);
2197 break;
2198 case FcElementTrunc:
2199 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2200 break;
2201 case FcElementUnknown:
2202 break;
24330d27 2203 }
c2e7c611
KP
2204 (void) FcPStackPop (parse);
2205}
2206
2207static void
2208FcCharacterData (void *userData, const XML_Char *s, int len)
2209{
2210 FcConfigParse *parse = userData;
2211
2212 if (!parse->pstack)
2213 return;
2214 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2215 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2216}
2217
2218static void
2219FcStartDoctypeDecl (void *userData,
2220 const XML_Char *doctypeName,
2221 const XML_Char *sysid,
2222 const XML_Char *pubid,
2223 int has_internal_subset)
2224{
2225 FcConfigParse *parse = userData;
2226
2227 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2228 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2229}
2230
e99f0f0a
PL
2231#if ENABLE_LIBXML2
2232
2233static void
2234FcInternalSubsetDecl (void *userData,
2235 const XML_Char *doctypeName,
2236 const XML_Char *sysid,
2237 const XML_Char *pubid)
2238{
2239 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2240}
2241
2242static void
2243FcExternalSubsetDecl (void *userData,
2244 const XML_Char *doctypeName,
2245 const XML_Char *sysid,
2246 const XML_Char *pubid)
2247{
2248 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2249}
2250
2251#else /* ENABLE_LIBXML2 */
2252
c2e7c611
KP
2253static void
2254FcEndDoctypeDecl (void *userData)
2255{
24330d27
KP
2256}
2257
e99f0f0a
PL
2258#endif /* ENABLE_LIBXML2 */
2259
2d9c79c0
KP
2260static FcBool
2261FcConfigParseAndLoadDir (FcConfig *config,
2262 const FcChar8 *name,
2263 const FcChar8 *dir,
2264 FcBool complain)
2265{
2266 DIR *d;
2267 struct dirent *e;
2268 FcBool ret = FcTrue;
2269 FcChar8 *file;
2270 FcChar8 *base;
2271 FcStrSet *files;
2272
2273 d = opendir ((char *) dir);
2274 if (!d)
2275 {
2276 if (complain)
2277 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2278 name);
2279 ret = FcFalse;
2280 goto bail0;
2281 }
2282 /* freed below */
2283 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2284 if (!file)
2285 {
2286 ret = FcFalse;
2287 goto bail1;
2288 }
2289
2290 strcpy ((char *) file, (char *) dir);
2291 strcat ((char *) file, "/");
2292 base = file + strlen ((char *) file);
2293
2294 files = FcStrSetCreate ();
2295 if (!files)
2296 {
2297 ret = FcFalse;
2298 goto bail2;
2299 }
2300
2301 if (FcDebug () & FC_DBG_CONFIG)
2302 printf ("\tScanning config dir %s\n", dir);
2303
2304 while (ret && (e = readdir (d)))
2305 {
8245771d
PL
2306 int d_len;
2307#define TAIL ".conf"
2308#define TAIL_LEN 5
2d9c79c0 2309 /*
8245771d 2310 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2311 */
2312 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2313 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2314 d_len > TAIL_LEN &&
2315 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2316 {
2317 strcpy ((char *) base, (char *) e->d_name);
2318 if (!FcStrSetAdd (files, file))
2319 {
2320 ret = FcFalse;
2321 goto bail3;
2322 }
2323 }
2324 }
2325 if (ret)
2326 {
2327 int i;
4262e0b3
PL
2328 qsort (files->strs, files->num, sizeof (FcChar8 *),
2329 (int (*)(const void *, const void *)) FcStrCmp);
2d9c79c0 2330 for (i = 0; ret && i < files->num; i++)
4262e0b3 2331 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2332 }
2333bail3:
2334 FcStrSetDestroy (files);
2335bail2:
2336 free (file);
2337bail1:
2338 closedir (d);
2339bail0:
2340 return ret || !complain;
2341}
2342
24330d27
KP
2343FcBool
2344FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2345 const FcChar8 *name,
24330d27
KP
2346 FcBool complain)
2347{
24330d27 2348
c2e7c611
KP
2349 XML_Parser p;
2350 FcChar8 *filename;
2351 FILE *f;
2352 int len;
c2e7c611
KP
2353 FcConfigParse parse;
2354 FcBool error = FcTrue;
2355
e99f0f0a
PL
2356#if ENABLE_LIBXML2
2357 xmlSAXHandler sax;
2358 char buf[BUFSIZ];
2359#else
2360 void *buf;
2361#endif
2362
c2e7c611
KP
2363 filename = FcConfigFilename (name);
2364 if (!filename)
2365 goto bail0;
4aded3e0
KP
2366
2367 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2368 {
2369 FcStrFree (filename);
4aded3e0 2370 goto bail0;
9dac3c59 2371 }
4aded3e0 2372
2d9c79c0
KP
2373 if (FcFileIsDir (filename))
2374 {
2375 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2376 FcStrFree (filename);
2377 return ret;
2378 }
2379
2380 if (FcDebug () & FC_DBG_CONFIG)
2381 printf ("\tLoading config file %s\n", filename);
2382
c2e7c611 2383 f = fopen ((char *) filename, "r");
9dac3c59 2384 FcStrFree (filename);
c2e7c611
KP
2385 if (!f)
2386 goto bail0;
2387
e99f0f0a
PL
2388#if ENABLE_LIBXML2
2389 memset(&sax, 0, sizeof(sax));
2390
2391 sax.internalSubset = FcInternalSubsetDecl;
2392 sax.externalSubset = FcExternalSubsetDecl;
2393 sax.startElement = FcStartElement;
2394 sax.endElement = FcEndElement;
2395 sax.characters = FcCharacterData;
2396
2397 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, filename);
2398#else
c2e7c611 2399 p = XML_ParserCreate ("UTF-8");
e99f0f0a
PL
2400#endif
2401
c2e7c611
KP
2402 if (!p)
2403 goto bail1;
2404
2405 if (!FcConfigInit (&parse, name, config, p))
2406 goto bail2;
2407
e99f0f0a
PL
2408#if !ENABLE_LIBXML2
2409
c2e7c611
KP
2410 XML_SetUserData (p, &parse);
2411
2412 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2413 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2414 XML_SetCharacterDataHandler (p, FcCharacterData);
2415
e99f0f0a
PL
2416#endif /* ENABLE_LIBXML2 */
2417
c2e7c611 2418 do {
e99f0f0a 2419#if !ENABLE_LIBXML2
c2e7c611
KP
2420 buf = XML_GetBuffer (p, BUFSIZ);
2421 if (!buf)
80c053b7 2422 {
179c3995 2423 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2424 goto bail3;
80c053b7 2425 }
e99f0f0a 2426#endif
c2e7c611
KP
2427 len = fread (buf, 1, BUFSIZ, f);
2428 if (len < 0)
80c053b7 2429 {
179c3995 2430 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2431 goto bail3;
80c053b7 2432 }
e99f0f0a
PL
2433
2434#if ENABLE_LIBXML2
2435 if (xmlParseChunk (p, buf, len, len == 0))
2436#else
c2e7c611 2437 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2438#endif
80c053b7 2439 {
179c3995 2440 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2441 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2442 goto bail3;
80c053b7 2443 }
c2e7c611
KP
2444 } while (len != 0);
2445 error = parse.error;
2446bail3:
2447 FcConfigCleanup (&parse);
2448bail2:
2449 XML_ParserFree (p);
2450bail1:
2451 fclose (f);
e1b9d091 2452 f = NULL;
c2e7c611
KP
2453bail0:
2454 if (error && complain)
24330d27 2455 {
c2e7c611 2456 if (name)
179c3995 2457 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2458 else
179c3995 2459 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2460 return FcFalse;
2461 }
2462 return FcTrue;
2463}