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