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