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