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