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