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