]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
[xml] Allocate FcExpr's in a pool in FcConfig
[fontconfig.git] / src / fcxml.c
CommitLineData
24330d27 1/*
317b8492 2 * fontconfig/src/fcxml.c
24330d27 3 *
46b51147 4 * Copyright © 2002 Keith Packard
24330d27
KP
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24330d27 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3074a73b 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24330d27
KP
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
f045376c 25#include "fcint.h"
3bfae75d 26#include <fcntl.h>
24330d27 27#include <stdarg.h>
2d9c79c0 28#include <dirent.h>
0ab36ca8 29
0d745819 30#ifdef ENABLE_LIBXML2
e99f0f0a
PL
31
32#include <libxml/parser.h>
33
34#define XML_Char xmlChar
35#define XML_Parser xmlParserCtxtPtr
36#define XML_ParserFree xmlFreeParserCtxt
37#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
38#define XML_GetErrorCode xmlCtxtGetLastError
39#define XML_ErrorString(Error) (Error)->message
40
41#else /* ENABLE_LIBXML2 */
42
d0f07b8d
KP
43#ifndef HAVE_XMLPARSE_H
44#define HAVE_XMLPARSE_H 0
45#endif
fa244f3d 46
179c3995
KP
47#if HAVE_XMLPARSE_H
48#include <xmlparse.h>
49#else
50#include <expat.h>
51#endif
24330d27 52
e99f0f0a
PL
53#endif /* ENABLE_LIBXML2 */
54
daeed6e0
TL
55#ifdef _WIN32
56#define STRICT
57#include <windows.h>
58#undef STRICT
59#endif
60
398d4364
BE
61static void
62FcExprDestroy (FcExpr *e);
24330d27
KP
63
64void
65FcTestDestroy (FcTest *test)
66{
67 if (test->next)
68 FcTestDestroy (test->next);
69 FcExprDestroy (test->expr);
9dac3c59 70 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
24330d27
KP
71 free (test);
72}
73
a96ecbfa 74static FcExpr *
390c05e6 75FcExprCreateInteger (FcConfig *config, int i)
24330d27 76{
390c05e6 77 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
78 if (e)
79 {
80 e->op = FcOpInteger;
81 e->u.ival = i;
82 }
83 return e;
84}
85
398d4364 86static FcExpr *
390c05e6 87FcExprCreateDouble (FcConfig *config, double d)
24330d27 88{
390c05e6 89 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
90 if (e)
91 {
92 e->op = FcOpDouble;
93 e->u.dval = d;
94 }
95 return e;
96}
97
398d4364 98static FcExpr *
390c05e6 99FcExprCreateString (FcConfig *config, const FcChar8 *s)
24330d27 100{
390c05e6 101 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
102 if (e)
103 {
104 e->op = FcOpString;
105 e->u.sval = FcStrCopy (s);
106 }
107 return e;
108}
109
398d4364 110static FcExpr *
390c05e6 111FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
24330d27 112{
390c05e6 113 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
114 if (e)
115 {
116 e->op = FcOpMatrix;
117 e->u.mval = FcMatrixCopy (m);
118 }
119 return e;
120}
121
398d4364 122static FcExpr *
390c05e6 123FcExprCreateBool (FcConfig *config, FcBool b)
24330d27 124{
390c05e6 125 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
126 if (e)
127 {
128 e->op = FcOpBool;
129 e->u.bval = b;
130 }
131 return e;
132}
133
398d4364 134static FcExpr *
390c05e6 135FcExprCreateNil (FcConfig *config)
24330d27 136{
390c05e6 137 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
138 if (e)
139 {
9dac3c59 140 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
141 e->op = FcOpNil;
142 }
143 return e;
144}
145
398d4364 146static FcExpr *
390c05e6 147FcExprCreateField (FcConfig *config, const char *field)
24330d27 148{
390c05e6 149 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
150 if (e)
151 {
152 e->op = FcOpField;
7ce19673 153 e->u.object = FcObjectFromName (field);
24330d27
KP
154 }
155 return e;
156}
157
398d4364 158static FcExpr *
390c05e6 159FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
24330d27 160{
390c05e6 161 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
162 if (e)
163 {
164 e->op = FcOpConst;
165 e->u.constant = FcStrCopy (constant);
166 }
167 return e;
168}
169
398d4364 170static FcExpr *
390c05e6 171FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
24330d27 172{
390c05e6 173 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
174 if (e)
175 {
176 e->op = op;
177 e->u.tree.left = left;
178 e->u.tree.right = right;
179 }
180 return e;
181}
182
398d4364 183static void
24330d27
KP
184FcExprDestroy (FcExpr *e)
185{
3f7653c2
KP
186 if (!e)
187 return;
24330d27
KP
188 switch (e->op) {
189 case FcOpInteger:
190 break;
191 case FcOpDouble:
192 break;
193 case FcOpString:
194 FcStrFree (e->u.sval);
195 break;
196 case FcOpMatrix:
197 FcMatrixFree (e->u.mval);
198 break;
199 case FcOpCharSet:
200 FcCharSetDestroy (e->u.cval);
201 break;
202 case FcOpBool:
203 break;
204 case FcOpField:
24330d27
KP
205 break;
206 case FcOpConst:
207 FcStrFree (e->u.constant);
208 break;
209 case FcOpAssign:
210 case FcOpAssignReplace:
211 case FcOpPrepend:
212 case FcOpPrependFirst:
213 case FcOpAppend:
214 case FcOpAppendLast:
215 break;
216 case FcOpOr:
217 case FcOpAnd:
218 case FcOpEqual:
24330d27
KP
219 case FcOpNotEqual:
220 case FcOpLess:
221 case FcOpLessEqual:
222 case FcOpMore:
223 case FcOpMoreEqual:
47d4f950 224 case FcOpContains:
74a623e0 225 case FcOpListing:
47d4f950 226 case FcOpNotContains:
24330d27
KP
227 case FcOpPlus:
228 case FcOpMinus:
229 case FcOpTimes:
230 case FcOpDivide:
231 case FcOpQuest:
232 case FcOpComma:
233 FcExprDestroy (e->u.tree.right);
234 /* fall through */
235 case FcOpNot:
3f7653c2
KP
236 case FcOpFloor:
237 case FcOpCeil:
238 case FcOpRound:
239 case FcOpTrunc:
24330d27
KP
240 FcExprDestroy (e->u.tree.left);
241 break;
242 case FcOpNil:
243 case FcOpInvalid:
244 break;
245 }
390c05e6
BE
246
247 e->op = FcOpNil;
24330d27
KP
248}
249
24330d27
KP
250void
251FcEditDestroy (FcEdit *e)
252{
253 if (e->next)
254 FcEditDestroy (e->next);
24330d27
KP
255 if (e->expr)
256 FcExprDestroy (e->expr);
34cd0514 257 free (e);
24330d27
KP
258}
259
c2e7c611
KP
260typedef enum _FcElement {
261 FcElementNone,
262 FcElementFontconfig,
263 FcElementDir,
7410e40b 264 FcElementCacheDir,
c2e7c611
KP
265 FcElementCache,
266 FcElementInclude,
267 FcElementConfig,
268 FcElementMatch,
269 FcElementAlias,
270
271 FcElementBlank,
179c3995 272 FcElementRescan,
c2e7c611
KP
273
274 FcElementPrefer,
275 FcElementAccept,
276 FcElementDefault,
277 FcElementFamily,
278
d47c9d6e
KP
279 FcElementSelectfont,
280 FcElementAcceptfont,
281 FcElementRejectfont,
282 FcElementGlob,
4f27c1c0
KP
283 FcElementPattern,
284 FcElementPatelt,
d47c9d6e 285
c2e7c611
KP
286 FcElementTest,
287 FcElementEdit,
288 FcElementInt,
289 FcElementDouble,
290 FcElementString,
291 FcElementMatrix,
292 FcElementBool,
293 FcElementCharset,
294 FcElementName,
295 FcElementConst,
296 FcElementOr,
297 FcElementAnd,
298 FcElementEq,
299 FcElementNotEq,
300 FcElementLess,
301 FcElementLessEq,
302 FcElementMore,
303 FcElementMoreEq,
47d4f950
KP
304 FcElementContains,
305 FcElementNotContains,
c2e7c611
KP
306 FcElementPlus,
307 FcElementMinus,
308 FcElementTimes,
309 FcElementDivide,
310 FcElementNot,
311 FcElementIf,
3f7653c2
KP
312 FcElementFloor,
313 FcElementCeil,
314 FcElementRound,
315 FcElementTrunc,
c2e7c611
KP
316 FcElementUnknown
317} FcElement;
318
392fa276 319static const struct {
67accef4
PL
320 const char name[16];
321 FcElement element;
322} fcElementMap[] = {
323 { "fontconfig", FcElementFontconfig },
324 { "dir", FcElementDir },
7410e40b 325 { "cachedir", FcElementCacheDir },
67accef4
PL
326 { "cache", FcElementCache },
327 { "include", FcElementInclude },
328 { "config", FcElementConfig },
329 { "match", FcElementMatch },
330 { "alias", FcElementAlias },
331
332 { "blank", FcElementBlank },
333 { "rescan", FcElementRescan },
334
335 { "prefer", FcElementPrefer },
336 { "accept", FcElementAccept },
337 { "default", FcElementDefault },
338 { "family", FcElementFamily },
339
340 { "selectfont", FcElementSelectfont },
341 { "acceptfont", FcElementAcceptfont },
342 { "rejectfont", FcElementRejectfont },
343 { "glob", FcElementGlob },
344 { "pattern", FcElementPattern },
345 { "patelt", FcElementPatelt },
346
347 { "test", FcElementTest },
348 { "edit", FcElementEdit },
349 { "int", FcElementInt },
350 { "double", FcElementDouble },
351 { "string", FcElementString },
352 { "matrix", FcElementMatrix },
353 { "bool", FcElementBool },
354 { "charset", FcElementCharset },
355 { "name", FcElementName },
356 { "const", FcElementConst },
357 { "or", FcElementOr },
358 { "and", FcElementAnd },
359 { "eq", FcElementEq },
360 { "not_eq", FcElementNotEq },
361 { "less", FcElementLess },
362 { "less_eq", FcElementLessEq },
363 { "more", FcElementMore },
364 { "more_eq", FcElementMoreEq },
365 { "contains", FcElementContains },
366 { "not_contains", FcElementNotContains },
367 { "plus", FcElementPlus },
368 { "minus", FcElementMinus },
369 { "times", FcElementTimes },
370 { "divide", FcElementDivide },
371 { "not", FcElementNot },
372 { "if", FcElementIf },
373 { "floor", FcElementFloor },
374 { "ceil", FcElementCeil },
375 { "round", FcElementRound },
376 { "trunc", FcElementTrunc },
377};
378#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
379
c2e7c611
KP
380static FcElement
381FcElementMap (const XML_Char *name)
382{
c2e7c611
KP
383
384 int i;
67accef4 385 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
c2e7c611
KP
386 if (!strcmp ((char *) name, fcElementMap[i].name))
387 return fcElementMap[i].element;
388 return FcElementUnknown;
389}
390
391typedef struct _FcPStack {
392 struct _FcPStack *prev;
393 FcElement element;
394 FcChar8 **attr;
395 FcStrBuf str;
de69ee14 396 FcChar8 *attr_buf_static[16];
c2e7c611
KP
397} FcPStack;
398
399typedef enum _FcVStackTag {
400 FcVStackNone,
401
402 FcVStackString,
403 FcVStackFamily,
404 FcVStackField,
405 FcVStackConstant,
d47c9d6e 406 FcVStackGlob,
4f27c1c0 407 FcVStackPattern,
c2e7c611
KP
408
409 FcVStackPrefer,
410 FcVStackAccept,
411 FcVStackDefault,
412
413 FcVStackInteger,
414 FcVStackDouble,
415 FcVStackMatrix,
416 FcVStackBool,
417
418 FcVStackTest,
419 FcVStackExpr,
420 FcVStackEdit
421} FcVStackTag;
422
423typedef struct _FcVStack {
424 struct _FcVStack *prev;
425 FcPStack *pstack; /* related parse element */
426 FcVStackTag tag;
427 union {
428 FcChar8 *string;
429
430 int integer;
431 double _double;
432 FcMatrix *matrix;
fe8e8a1d 433 FcBool bool_;
c2e7c611
KP
434
435 FcTest *test;
436 FcQual qual;
437 FcOp op;
438 FcExpr *expr;
439 FcEdit *edit;
4f27c1c0
KP
440
441 FcPattern *pattern;
c2e7c611
KP
442 } u;
443} FcVStack;
444
445typedef struct _FcConfigParse {
446 FcPStack *pstack;
447 FcVStack *vstack;
448 FcBool error;
449 const FcChar8 *name;
450 FcConfig *config;
451 XML_Parser parser;
1d7b47da
BE
452 int pstack_static_used;
453 FcPStack pstack_static[8];
39861b7d
BE
454 int vstack_static_used;
455 FcVStack vstack_static[64];
c2e7c611
KP
456} FcConfigParse;
457
179c3995
KP
458typedef enum _FcConfigSeverity {
459 FcSevereInfo, FcSevereWarning, FcSevereError
460} FcConfigSeverity;
461
24330d27 462static void
67accef4 463FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
24330d27 464{
67accef4 465 const char *s = "unknown";
24330d27
KP
466 va_list args;
467
468 va_start (args, fmt);
179c3995
KP
469
470 switch (severe) {
471 case FcSevereInfo: s = "info"; break;
472 case FcSevereWarning: s = "warning"; break;
473 case FcSevereError: s = "error"; break;
474 }
c2e7c611
KP
475 if (parse)
476 {
477 if (parse->name)
179c3995 478 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
68355f38 479 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
c2e7c611 480 else
179c3995 481 fprintf (stderr, "Fontconfig %s: line %d: ", s,
68355f38 482 (int)XML_GetCurrentLineNumber (parse->parser));
179c3995
KP
483 if (severe >= FcSevereError)
484 parse->error = FcTrue;
c2e7c611
KP
485 }
486 else
179c3995 487 fprintf (stderr, "Fontconfig %s: ", s);
24330d27
KP
488 vfprintf (stderr, fmt, args);
489 fprintf (stderr, "\n");
490 va_end (args);
491}
492
ca60d2b5 493
67accef4 494static const char *
ca60d2b5
KP
495FcTypeName (FcType type)
496{
497 switch (type) {
498 case FcTypeVoid:
499 return "void";
500 case FcTypeInteger:
501 case FcTypeDouble:
502 return "number";
503 case FcTypeString:
504 return "string";
505 case FcTypeBool:
506 return "bool";
507 case FcTypeMatrix:
508 return "matrix";
509 case FcTypeCharSet:
510 return "charset";
511 case FcTypeFTFace:
512 return "FT_Face";
513 case FcTypeLangSet:
514 return "langset";
515 default:
516 return "unknown";
517 }
518}
519
520static void
521FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
522{
523 if (value == FcTypeInteger)
524 value = FcTypeDouble;
525 if (type == FcTypeInteger)
526 type = FcTypeDouble;
527 if (value != type)
528 {
529 if ((value == FcTypeLangSet && type == FcTypeString) ||
530 (value == FcTypeString && type == FcTypeLangSet))
531 return;
9a9fd975
KP
532 if (type == (FcType) -1)
533 return;
ca60d2b5
KP
534 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
535 FcTypeName (value), FcTypeName (type));
536 }
537}
538
539static void
540FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
541{
542 const FcObjectType *o;
543 const FcConstant *c;
544
07e646cc
MF
545 /* If parsing the expression failed, some nodes may be NULL */
546 if (!expr)
547 return;
548
ca60d2b5
KP
549 switch (expr->op) {
550 case FcOpInteger:
551 case FcOpDouble:
552 FcTypecheckValue (parse, FcTypeDouble, type);
553 break;
554 case FcOpString:
555 FcTypecheckValue (parse, FcTypeString, type);
556 break;
557 case FcOpMatrix:
558 FcTypecheckValue (parse, FcTypeMatrix, type);
559 break;
560 case FcOpBool:
561 FcTypecheckValue (parse, FcTypeBool, type);
562 break;
563 case FcOpCharSet:
564 FcTypecheckValue (parse, FcTypeCharSet, type);
565 break;
566 case FcOpNil:
567 break;
568 case FcOpField:
7ce19673 569 o = FcNameGetObjectType (FcObjectName (expr->u.object));
ca60d2b5
KP
570 if (o)
571 FcTypecheckValue (parse, o->type, type);
572 break;
573 case FcOpConst:
574 c = FcNameGetConstant (expr->u.constant);
575 if (c)
576 {
577 o = FcNameGetObjectType (c->object);
578 if (o)
579 FcTypecheckValue (parse, o->type, type);
580 }
f28472fd
PL
581 else
582 FcConfigMessage (parse, FcSevereWarning,
583 "invalid constant used : %s",
584 expr->u.constant);
ca60d2b5
KP
585 break;
586 case FcOpQuest:
587 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
588 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
589 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
590 break;
591 case FcOpAssign:
592 case FcOpAssignReplace:
593 break;
594 case FcOpEqual:
595 case FcOpNotEqual:
596 case FcOpLess:
597 case FcOpLessEqual:
598 case FcOpMore:
599 case FcOpMoreEqual:
600 case FcOpContains:
601 case FcOpNotContains:
602 case FcOpListing:
603 FcTypecheckValue (parse, FcTypeBool, type);
604 break;
605 case FcOpComma:
606 case FcOpOr:
607 case FcOpAnd:
608 case FcOpPlus:
609 case FcOpMinus:
610 case FcOpTimes:
611 case FcOpDivide:
612 FcTypecheckExpr (parse, expr->u.tree.left, type);
613 FcTypecheckExpr (parse, expr->u.tree.right, type);
614 break;
615 case FcOpNot:
616 FcTypecheckValue (parse, FcTypeBool, type);
617 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
618 break;
619 case FcOpFloor:
620 case FcOpCeil:
621 case FcOpRound:
622 case FcOpTrunc:
623 FcTypecheckValue (parse, FcTypeDouble, type);
624 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
625 break;
626 default:
627 break;
628 }
629}
630
631static FcTest *
632FcTestCreate (FcConfigParse *parse,
633 FcMatchKind kind,
634 FcQual qual,
635 const FcChar8 *field,
636 FcOp compare,
637 FcExpr *expr)
638{
639 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
640
641 if (test)
642 {
643 const FcObjectType *o;
644
645 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
646 test->next = 0;
647 test->kind = kind;
648 test->qual = qual;
7ce19673 649 test->object = FcObjectFromName ((const char *) field);
ca60d2b5
KP
650 test->op = compare;
651 test->expr = expr;
7ce19673 652 o = FcNameGetObjectType (FcObjectName (test->object));
ca60d2b5
KP
653 if (o)
654 FcTypecheckExpr (parse, expr, o->type);
655 }
656 return test;
657}
658
659static FcEdit *
660FcEditCreate (FcConfigParse *parse,
2d3387fd 661 FcObject object,
ca60d2b5
KP
662 FcOp op,
663 FcExpr *expr,
664 FcValueBinding binding)
665{
666 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
667
668 if (e)
669 {
670 const FcObjectType *o;
671
672 e->next = 0;
2d3387fd 673 e->object = object;
ca60d2b5
KP
674 e->op = op;
675 e->expr = expr;
676 e->binding = binding;
7ce19673 677 o = FcNameGetObjectType (FcObjectName (e->object));
ca60d2b5
KP
678 if (o)
679 FcTypecheckExpr (parse, expr, o->type);
680 }
681 return e;
682}
683
c2e7c611 684static FcVStack *
39861b7d 685FcVStackCreateAndPush (FcConfigParse *parse)
24330d27 686{
c2e7c611 687 FcVStack *new;
24330d27 688
39861b7d
BE
689 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
690 new = &parse->vstack_static[parse->vstack_static_used++];
691 else
692 {
693 new = malloc (sizeof (FcVStack));
694 if (!new)
695 return 0;
696 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
697 }
c2e7c611
KP
698 new->tag = FcVStackNone;
699 new->prev = 0;
24330d27 700
39861b7d
BE
701 new->prev = parse->vstack;
702 new->pstack = parse->pstack ? parse->pstack->prev : 0;
703 parse->vstack = new;
24330d27 704
39861b7d 705 return new;
24330d27
KP
706}
707
708static FcBool
c2e7c611 709FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 710{
39861b7d 711 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
712 if (!vstack)
713 return FcFalse;
714 vstack->u.string = string;
715 vstack->tag = tag;
c2e7c611 716 return FcTrue;
24330d27
KP
717}
718
719static FcBool
c2e7c611 720FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 721{
39861b7d 722 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 723 if (!vstack)
24330d27 724 return FcFalse;
c2e7c611
KP
725 vstack->u.integer = integer;
726 vstack->tag = FcVStackInteger;
c2e7c611 727 return FcTrue;
24330d27
KP
728}
729
730static FcBool
c2e7c611 731FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 732{
39861b7d 733 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 734 if (!vstack)
24330d27 735 return FcFalse;
c2e7c611
KP
736 vstack->u._double = _double;
737 vstack->tag = FcVStackDouble;
c2e7c611 738 return FcTrue;
24330d27
KP
739}
740
741static FcBool
c2e7c611 742FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 743{
39861b7d 744 FcVStack *vstack;
c2e7c611
KP
745 matrix = FcMatrixCopy (matrix);
746 if (!matrix)
c2e7c611 747 return FcFalse;
39861b7d
BE
748 vstack = FcVStackCreateAndPush (parse);
749 if (!vstack)
750 return FcFalse;
c2e7c611
KP
751 vstack->u.matrix = matrix;
752 vstack->tag = FcVStackMatrix;
c2e7c611 753 return FcTrue;
24330d27
KP
754}
755
756static FcBool
fe8e8a1d 757FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
24330d27 758{
39861b7d 759 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
760 if (!vstack)
761 return FcFalse;
fe8e8a1d 762 vstack->u.bool_ = bool_;
c2e7c611 763 vstack->tag = FcVStackBool;
c2e7c611
KP
764 return FcTrue;
765}
24330d27 766
c2e7c611
KP
767static FcBool
768FcVStackPushTest (FcConfigParse *parse, FcTest *test)
769{
39861b7d 770 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 771 if (!vstack)
24330d27 772 return FcFalse;
c2e7c611
KP
773 vstack->u.test = test;
774 vstack->tag = FcVStackTest;
24330d27
KP
775 return FcTrue;
776}
777
778static FcBool
c2e7c611 779FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 780{
39861b7d 781 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
782 if (!vstack)
783 return FcFalse;
784 vstack->u.expr = expr;
785 vstack->tag = tag;
c2e7c611
KP
786 return FcTrue;
787}
24330d27 788
c2e7c611
KP
789static FcBool
790FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
791{
39861b7d 792 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 793 if (!vstack)
24330d27 794 return FcFalse;
c2e7c611
KP
795 vstack->u.edit = edit;
796 vstack->tag = FcVStackEdit;
24330d27
KP
797 return FcTrue;
798}
799
4f27c1c0
KP
800static FcBool
801FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
802{
39861b7d 803 FcVStack *vstack = FcVStackCreateAndPush (parse);
4f27c1c0
KP
804 if (!vstack)
805 return FcFalse;
806 vstack->u.pattern = pattern;
807 vstack->tag = FcVStackPattern;
4f27c1c0
KP
808 return FcTrue;
809}
810
c2e7c611
KP
811static FcVStack *
812FcVStackFetch (FcConfigParse *parse, int off)
24330d27 813{
c2e7c611 814 FcVStack *vstack;
24330d27 815
c2e7c611
KP
816 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
817 return vstack;
818}
819
39861b7d
BE
820static FcVStack *
821FcVStackPeek (FcConfigParse *parse)
c2e7c611 822{
39861b7d
BE
823 FcVStack *vstack = parse->vstack;
824
825 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
24330d27
KP
826}
827
39861b7d
BE
828static void
829FcVStackPopAndDestroy (FcConfigParse *parse)
24330d27 830{
c2e7c611 831 FcVStack *vstack = parse->vstack;
24330d27 832
c2e7c611 833 if (!vstack || vstack->pstack != parse->pstack)
39861b7d
BE
834 return;
835
c2e7c611 836 parse->vstack = vstack->prev;
39861b7d
BE
837
838 switch (vstack->tag) {
839 case FcVStackNone:
840 break;
841 case FcVStackString:
842 case FcVStackFamily:
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:
4262e0b3
PL
1923 value.u.s = FcStrCopy (vstack->u.string);
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);
2103 rc = GetWindowsDirectory (data, 800);
2104 if (rc == 0 || rc > 800)
2105 {
2106 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
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 {
2146 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
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__