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