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