]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Respect "binding" attribute in <alias> entries.
[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
681bb379
KP
1291static FcBool
1292FcConfigLexBinding (FcConfigParse *parse,
1293 const FcChar8 *binding_string,
1294 FcValueBinding *binding_ret)
1295{
1296 FcValueBinding binding;
1297
1298 if (!binding_string)
1299 binding = FcValueBindingWeak;
1300 else
1301 {
1302 if (!strcmp ((char *) binding_string, "weak"))
1303 binding = FcValueBindingWeak;
1304 else if (!strcmp ((char *) binding_string, "strong"))
1305 binding = FcValueBindingStrong;
1306 else if (!strcmp ((char *) binding_string, "same"))
1307 binding = FcValueBindingSame;
1308 else
1309 {
1310 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1311 return FcFalse;
1312 }
1313 }
1314 *binding_ret = binding;
1315 return FcTrue;
1316}
1317
c2e7c611
KP
1318static void
1319FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1320{
c2e7c611
KP
1321 FcVStack *vstack;
1322 FcExpr *left, *expr = 0, *new;
1323
1324 while ((vstack = FcVStackPop (parse)))
1325 {
1326 if (vstack->tag != FcVStackFamily)
1327 {
179c3995
KP
1328 FcConfigMessage (parse, FcSevereWarning, "non-family");
1329 FcVStackDestroy (vstack);
1330 continue;
c2e7c611
KP
1331 }
1332 left = vstack->u.expr;
1333 vstack->tag = FcVStackNone;
1334 FcVStackDestroy (vstack);
1335 if (expr)
1336 {
1337 new = FcExprCreateOp (left, FcOpComma, expr);
1338 if (!new)
1339 {
179c3995 1340 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1341 FcExprDestroy (left);
1342 FcExprDestroy (expr);
1343 break;
1344 }
1345 expr = new;
1346 }
1347 else
1348 expr = left;
1349 }
1350 if (expr)
1351 {
1352 if (!FcVStackPushExpr (parse, tag, expr))
1353 {
179c3995 1354 FcConfigMessage (parse, FcSevereError, "out of memory");
f2fb985c 1355 FcExprDestroy (expr);
c2e7c611
KP
1356 }
1357 }
1358}
1359
1360static void
1361FcParseFamily (FcConfigParse *parse)
1362{
1363 FcChar8 *s;
1364 FcExpr *expr;
1365
1366 if (!parse->pstack)
1367 return;
1368 s = FcStrBufDone (&parse->pstack->str);
1369 if (!s)
1370 {
179c3995 1371 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1372 return;
1373 }
1374 expr = FcExprCreateString (s);
1375 FcStrFree (s);
1376 if (expr)
1377 FcVStackPushExpr (parse, FcVStackFamily, expr);
1378}
1379
1380static void
1381FcParseAlias (FcConfigParse *parse)
1382{
179c3995 1383 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1384 FcEdit *edit = 0, *next;
c2e7c611 1385 FcVStack *vstack;
24330d27 1386 FcTest *test;
681bb379 1387 FcValueBinding binding;
24330d27 1388
681bb379
KP
1389 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1390 return;
c2e7c611 1391 while ((vstack = FcVStackPop (parse)))
24330d27 1392 {
c2e7c611
KP
1393 switch (vstack->tag) {
1394 case FcVStackFamily:
1395 if (family)
179c3995
KP
1396 {
1397 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1398 if (!new)
1399 FcConfigMessage (parse, FcSevereError, "out of memory");
1400 else
1401 family = new;
1402 }
1403 else
1404 new = vstack->u.expr;
1405 if (new)
1406 {
1407 family = new;
1408 vstack->tag = FcVStackNone;
1409 }
c2e7c611
KP
1410 break;
1411 case FcVStackPrefer:
1412 if (prefer)
1413 FcExprDestroy (prefer);
1414 prefer = vstack->u.expr;
1415 vstack->tag = FcVStackNone;
1416 break;
1417 case FcVStackAccept:
1418 if (accept)
1419 FcExprDestroy (accept);
1420 accept = vstack->u.expr;
1421 vstack->tag = FcVStackNone;
1422 break;
1423 case FcVStackDefault:
1424 if (def)
1425 FcExprDestroy (def);
1426 def = vstack->u.expr;
1427 vstack->tag = FcVStackNone;
1428 break;
1429 default:
179c3995 1430 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1431 break;
1432 }
1433 FcVStackDestroy (vstack);
24330d27 1434 }
ccb3e93b 1435 if (!family)
c2e7c611 1436 {
179c3995
KP
1437 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1438 if (prefer)
1439 FcExprDestroy (prefer);
1440 if (accept)
1441 FcExprDestroy (accept);
1442 if (def)
1443 FcExprDestroy (def);
c2e7c611
KP
1444 return;
1445 }
24330d27
KP
1446 if (prefer)
1447 {
ca60d2b5 1448 edit = FcEditCreate (parse,
2d3387fd 1449 FC_FAMILY_OBJECT,
24330d27 1450 FcOpPrepend,
6fff2cda 1451 prefer,
681bb379 1452 binding);
24330d27
KP
1453 if (edit)
1454 edit->next = 0;
c2e7c611
KP
1455 else
1456 FcExprDestroy (prefer);
24330d27
KP
1457 }
1458 if (accept)
1459 {
1460 next = edit;
ca60d2b5 1461 edit = FcEditCreate (parse,
2d3387fd 1462 FC_FAMILY_OBJECT,
24330d27 1463 FcOpAppend,
6fff2cda 1464 accept,
681bb379 1465 binding);
24330d27
KP
1466 if (edit)
1467 edit->next = next;
c2e7c611
KP
1468 else
1469 FcExprDestroy (accept);
24330d27
KP
1470 }
1471 if (def)
1472 {
1473 next = edit;
ca60d2b5 1474 edit = FcEditCreate (parse,
2d3387fd 1475 FC_FAMILY_OBJECT,
6fff2cda
KP
1476 FcOpAppendLast,
1477 def,
681bb379 1478 binding);
24330d27
KP
1479 if (edit)
1480 edit->next = next;
c2e7c611
KP
1481 else
1482 FcExprDestroy (def);
24330d27
KP
1483 }
1484 if (edit)
1485 {
ca60d2b5 1486 test = FcTestCreate (parse, FcMatchPattern,
938bc633 1487 FcQualAny,
2623c1eb 1488 (FcChar8 *) FC_FAMILY,
24330d27
KP
1489 FcOpEqual,
1490 family);
1491 if (test)
c2e7c611
KP
1492 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1493 FcTestDestroy (test);
24330d27 1494 }
c2e7c611
KP
1495 else
1496 FcExprDestroy (family);
24330d27
KP
1497}
1498
c2e7c611
KP
1499static FcExpr *
1500FcPopExpr (FcConfigParse *parse)
24330d27 1501{
c2e7c611
KP
1502 FcVStack *vstack = FcVStackPop (parse);
1503 FcExpr *expr = 0;
1504 if (!vstack)
1505 return 0;
1506 switch (vstack->tag) {
1507 case FcVStackNone:
1508 break;
1509 case FcVStackString:
1510 case FcVStackFamily:
bbbaac36
KP
1511 expr = FcExprCreateString (vstack->u.string);
1512 break;
c2e7c611 1513 case FcVStackField:
bbbaac36
KP
1514 expr = FcExprCreateField ((char *) vstack->u.string);
1515 break;
c2e7c611 1516 case FcVStackConstant:
bbbaac36 1517 expr = FcExprCreateConst (vstack->u.string);
c2e7c611 1518 break;
34cd0514
CW
1519 case FcVStackGlob:
1520 /* XXX: What's the correct action here? (CDW) */
1521 break;
c2e7c611
KP
1522 case FcVStackPrefer:
1523 case FcVStackAccept:
1524 case FcVStackDefault:
1525 expr = vstack->u.expr;
1526 vstack->tag = FcVStackNone;
1527 break;
1528 case FcVStackInteger:
1529 expr = FcExprCreateInteger (vstack->u.integer);
1530 break;
1531 case FcVStackDouble:
1532 expr = FcExprCreateDouble (vstack->u._double);
1533 break;
1534 case FcVStackMatrix:
1535 expr = FcExprCreateMatrix (vstack->u.matrix);
1536 break;
1537 case FcVStackBool:
1538 expr = FcExprCreateBool (vstack->u.bool);
1539 break;
1540 case FcVStackTest:
1541 break;
1542 case FcVStackExpr:
1543 expr = vstack->u.expr;
8ec077f2 1544 vstack->tag = FcVStackNone;
c2e7c611
KP
1545 break;
1546 case FcVStackEdit:
1547 break;
4f27c1c0
KP
1548 default:
1549 break;
c2e7c611
KP
1550 }
1551 FcVStackDestroy (vstack);
1552 return expr;
1553}
1554
3f7653c2
KP
1555/*
1556 * This builds a tree of binary operations. Note
1557 * that every operator is defined so that if only
1558 * a single operand is contained, the value of the
1559 * whole expression is the value of the operand.
1560 *
1561 * This code reduces in that case to returning that
1562 * operand.
1563 */
c2e7c611 1564static FcExpr *
3f7653c2 1565FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1566{
1567 FcExpr *left, *expr = 0, *new;
24330d27 1568
c2e7c611 1569 while ((left = FcPopExpr (parse)))
24330d27 1570 {
c2e7c611 1571 if (expr)
24330d27 1572 {
c2e7c611
KP
1573 new = FcExprCreateOp (left, op, expr);
1574 if (!new)
1575 {
179c3995 1576 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1577 FcExprDestroy (left);
1578 FcExprDestroy (expr);
2de24638 1579 return 0;
c2e7c611
KP
1580 }
1581 expr = new;
24330d27 1582 }
c2e7c611
KP
1583 else
1584 expr = left;
1585 }
1586 return expr;
1587}
1588
1589static void
3f7653c2
KP
1590FcParseBinary (FcConfigParse *parse, FcOp op)
1591{
1592 FcExpr *expr = FcPopBinary (parse, op);
1593 if (expr)
1594 FcVStackPushExpr (parse, FcVStackExpr, expr);
1595}
1596
1597/*
1598 * This builds a a unary operator, it consumes only
1599 * a single operand
1600 */
1601
1602static FcExpr *
1603FcPopUnary (FcConfigParse *parse, FcOp op)
1604{
1605 FcExpr *operand, *new = 0;
1606
1607 if ((operand = FcPopExpr (parse)))
1608 {
1609 new = FcExprCreateOp (operand, op, 0);
1610 if (!new)
1611 {
1612 FcExprDestroy (operand);
1613 FcConfigMessage (parse, FcSevereError, "out of memory");
1614 }
1615 }
1616 return new;
1617}
1618
1619static void
1620FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1621{
3f7653c2 1622 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1623 if (expr)
1624 FcVStackPushExpr (parse, FcVStackExpr, expr);
1625}
1626
1627static void
1628FcParseInclude (FcConfigParse *parse)
1629{
1630 FcChar8 *s;
1631 const FcChar8 *i;
1632 FcBool ignore_missing = FcFalse;
1633
1634 s = FcStrBufDone (&parse->pstack->str);
1635 if (!s)
1636 {
179c3995 1637 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1638 return;
1639 }
1640 i = FcConfigGetAttribute (parse, "ignore_missing");
ca60d2b5 1641 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
c2e7c611 1642 ignore_missing = FcTrue;
24c90386 1643 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1644 parse->error = FcTrue;
9dac3c59 1645 FcStrFree (s);
c2e7c611
KP
1646}
1647
1648typedef struct _FcOpMap {
67accef4 1649 char name[16];
c2e7c611
KP
1650 FcOp op;
1651} FcOpMap;
1652
1653static FcOp
1654FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1655{
1656 int i;
1657
1658 for (i = 0; i < nmap; i++)
1659 if (!strcmp ((char *) op, map[i].name))
1660 return map[i].op;
1661 return FcOpInvalid;
1662}
1663
1664static const FcOpMap fcCompareOps[] = {
1665 { "eq", FcOpEqual },
1666 { "not_eq", FcOpNotEqual },
1667 { "less", FcOpLess },
1668 { "less_eq", FcOpLessEqual },
1669 { "more", FcOpMore },
47d4f950
KP
1670 { "more_eq", FcOpMoreEqual },
1671 { "contains", FcOpContains },
1672 { "not_contains", FcOpNotContains }
c2e7c611
KP
1673};
1674
67accef4 1675#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
c2e7c611
KP
1676
1677static FcOp
1678FcConfigLexCompare (const FcChar8 *compare)
1679{
1680 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1681}
1682
c2e7c611
KP
1683static void
1684FcParseTest (FcConfigParse *parse)
1685{
938bc633
KP
1686 const FcChar8 *kind_string;
1687 FcMatchKind kind;
c2e7c611
KP
1688 const FcChar8 *qual_string;
1689 FcQual qual;
1690 const FcChar8 *name;
1691 const FcChar8 *compare_string;
1692 FcOp compare;
1693 FcExpr *expr;
1694 FcTest *test;
1695
938bc633
KP
1696 kind_string = FcConfigGetAttribute (parse, "target");
1697 if (!kind_string)
1698 kind = FcMatchDefault;
1699 else
1700 {
1701 if (!strcmp ((char *) kind_string, "pattern"))
1702 kind = FcMatchPattern;
1703 else if (!strcmp ((char *) kind_string, "font"))
1704 kind = FcMatchFont;
c2c6976d
KP
1705 else if (!strcmp ((char *) kind_string, "scan"))
1706 kind = FcMatchScan;
938bc633
KP
1707 else if (!strcmp ((char *) kind_string, "default"))
1708 kind = FcMatchDefault;
1709 else
1710 {
1711 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1712 return;
1713 }
1714 }
c2e7c611
KP
1715 qual_string = FcConfigGetAttribute (parse, "qual");
1716 if (!qual_string)
1717 qual = FcQualAny;
1718 else
1719 {
1720 if (!strcmp ((char *) qual_string, "any"))
1721 qual = FcQualAny;
1722 else if (!strcmp ((char *) qual_string, "all"))
1723 qual = FcQualAll;
6f6563ed
KP
1724 else if (!strcmp ((char *) qual_string, "first"))
1725 qual = FcQualFirst;
1726 else if (!strcmp ((char *) qual_string, "not_first"))
1727 qual = FcQualNotFirst;
c2e7c611 1728 else
24330d27 1729 {
179c3995 1730 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1731 return;
24330d27 1732 }
c2e7c611
KP
1733 }
1734 name = FcConfigGetAttribute (parse, "name");
1735 if (!name)
1736 {
179c3995 1737 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1738 return;
c2e7c611
KP
1739 }
1740 compare_string = FcConfigGetAttribute (parse, "compare");
1741 if (!compare_string)
1742 compare = FcOpEqual;
1743 else
1744 {
1745 compare = FcConfigLexCompare (compare_string);
1746 if (compare == FcOpInvalid)
24330d27 1747 {
179c3995 1748 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1749 return;
24330d27 1750 }
c2e7c611 1751 }
3f7653c2 1752 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1753 if (!expr)
1754 {
179c3995 1755 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1756 return;
1757 }
ca60d2b5 1758 test = FcTestCreate (parse, kind, qual, name, compare, expr);
c2e7c611
KP
1759 if (!test)
1760 {
179c3995 1761 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1762 return;
1763 }
1764 FcVStackPushTest (parse, test);
1765}
1766
1767static const FcOpMap fcModeOps[] = {
1768 { "assign", FcOpAssign },
1769 { "assign_replace", FcOpAssignReplace },
1770 { "prepend", FcOpPrepend },
1771 { "prepend_first", FcOpPrependFirst },
1772 { "append", FcOpAppend },
1773 { "append_last", FcOpAppendLast },
1774};
1775
67accef4 1776#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
c2e7c611
KP
1777
1778static FcOp
1779FcConfigLexMode (const FcChar8 *mode)
1780{
1781 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1782}
1783
1784static void
1785FcParseEdit (FcConfigParse *parse)
1786{
1787 const FcChar8 *name;
1788 const FcChar8 *mode_string;
1789 FcOp mode;
6fff2cda 1790 FcValueBinding binding;
c2e7c611
KP
1791 FcExpr *expr;
1792 FcEdit *edit;
1793
1794 name = FcConfigGetAttribute (parse, "name");
1795 if (!name)
1796 {
179c3995 1797 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1798 return;
c2e7c611
KP
1799 }
1800 mode_string = FcConfigGetAttribute (parse, "mode");
1801 if (!mode_string)
8ec077f2 1802 mode = FcOpAssign;
c2e7c611
KP
1803 else
1804 {
1805 mode = FcConfigLexMode (mode_string);
1806 if (mode == FcOpInvalid)
24330d27 1807 {
179c3995 1808 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1809 return;
24330d27 1810 }
c2e7c611 1811 }
681bb379
KP
1812 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1813 return;
1814
3f7653c2 1815 expr = FcPopBinary (parse, FcOpComma);
2d3387fd
KP
1816 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1817 mode, expr, binding);
c2e7c611
KP
1818 if (!edit)
1819 {
179c3995 1820 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1821 FcExprDestroy (expr);
1822 return;
1823 }
1824 if (!FcVStackPushEdit (parse, edit))
1825 FcEditDestroy (edit);
1826}
1827
1828static void
1829FcParseMatch (FcConfigParse *parse)
1830{
1831 const FcChar8 *kind_name;
1832 FcMatchKind kind;
1833 FcTest *test = 0;
1834 FcEdit *edit = 0;
1835 FcVStack *vstack;
1836
1837 kind_name = FcConfigGetAttribute (parse, "target");
1838 if (!kind_name)
1839 kind = FcMatchPattern;
1840 else
1841 {
1842 if (!strcmp ((char *) kind_name, "pattern"))
1843 kind = FcMatchPattern;
1844 else if (!strcmp ((char *) kind_name, "font"))
1845 kind = FcMatchFont;
c2c6976d
KP
1846 else if (!strcmp ((char *) kind_name, "scan"))
1847 kind = FcMatchScan;
c2e7c611 1848 else
24330d27 1849 {
179c3995 1850 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1851 return;
24330d27 1852 }
c2e7c611
KP
1853 }
1854 while ((vstack = FcVStackPop (parse)))
1855 {
1856 switch (vstack->tag) {
1857 case FcVStackTest:
1858 vstack->u.test->next = test;
1859 test = vstack->u.test;
1860 vstack->tag = FcVStackNone;
1861 break;
1862 case FcVStackEdit:
1863 vstack->u.edit->next = edit;
1864 edit = vstack->u.edit;
1865 vstack->tag = FcVStackNone;
0f963b0d
KP
1866 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
1867 {
1868 FcConfigMessage (parse, FcSevereError,
1869 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
1870 FcObjectName(edit->object));
1871 }
c2e7c611
KP
1872 break;
1873 default:
179c3995 1874 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1875 break;
1876 }
1877 FcVStackDestroy (vstack);
1878 }
1879 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1880 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1881}
1882
d47c9d6e
KP
1883static void
1884FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1885{
1886 FcVStack *vstack;
1887
1888 while ((vstack = FcVStackPop (parse)))
1889 {
1890 switch (vstack->tag) {
1891 case FcVStackGlob:
1892 if (!FcConfigGlobAdd (parse->config,
1893 vstack->u.string,
1894 element == FcElementAcceptfont))
1895 {
1896 FcConfigMessage (parse, FcSevereError, "out of memory");
1897 }
1898 break;
4f27c1c0
KP
1899 case FcVStackPattern:
1900 if (!FcConfigPatternsAdd (parse->config,
1901 vstack->u.pattern,
1902 element == FcElementAcceptfont))
1903 {
1904 FcConfigMessage (parse, FcSevereError, "out of memory");
1905 }
1906 else
1907 vstack->tag = FcVStackNone;
1908 break;
d47c9d6e
KP
1909 default:
1910 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1911 break;
1912 }
1913 FcVStackDestroy (vstack);
1914 }
1915}
1916
4f27c1c0
KP
1917
1918static FcValue
1919FcPopValue (FcConfigParse *parse)
1920{
1921 FcVStack *vstack = FcVStackPop (parse);
1922 FcValue value;
1923
1924 value.type = FcTypeVoid;
1925
1926 if (!vstack)
1927 return value;
1928
1929 switch (vstack->tag) {
1930 case FcVStackString:
4262e0b3
PL
1931 value.u.s = FcStrCopy (vstack->u.string);
1932 if (value.u.s)
4f27c1c0
KP
1933 value.type = FcTypeString;
1934 break;
1935 case FcVStackConstant:
1936 if (FcNameConstant (vstack->u.string, &value.u.i))
1937 value.type = FcTypeInteger;
1938 break;
1939 case FcVStackInteger:
1940 value.u.i = vstack->u.integer;
1941 value.type = FcTypeInteger;
1942 break;
1943 case FcVStackDouble:
1944 value.u.d = vstack->u._double;
1945 value.type = FcTypeInteger;
1946 break;
1947 case FcVStackMatrix:
4262e0b3
PL
1948 value.u.m = FcMatrixCopy (vstack->u.matrix);
1949 if (value.u.m)
4f27c1c0
KP
1950 value.type = FcTypeMatrix;
1951 break;
1952 case FcVStackBool:
1953 value.u.b = vstack->u.bool;
1954 value.type = FcTypeBool;
1955 break;
1956 default:
1957 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1958 vstack->tag);
1959 break;
1960 }
1961 FcVStackDestroy (vstack);
1962
1963 return value;
1964}
1965
1966static void
1967FcParsePatelt (FcConfigParse *parse)
1968{
1969 FcValue value;
1970 FcPattern *pattern = FcPatternCreate ();
1971 const char *name;
1972
1973 if (!pattern)
1974 {
1975 FcConfigMessage (parse, FcSevereError, "out of memory");
1976 return;
1977 }
1978
8245771d 1979 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
1980 if (!name)
1981 {
1982 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2de24638 1983 FcPatternDestroy (pattern);
4f27c1c0
KP
1984 return;
1985 }
4f27c1c0
KP
1986
1987 for (;;)
1988 {
1989 value = FcPopValue (parse);
1990 if (value.type == FcTypeVoid)
1991 break;
1992 if (!FcPatternAdd (pattern, name, value, FcTrue))
1993 {
1994 FcConfigMessage (parse, FcSevereError, "out of memory");
1995 break;
1996 }
1997 }
1998
529291be 1999 FcVStackPushPattern (parse, pattern);
4f27c1c0
KP
2000}
2001
2002static void
2003FcParsePattern (FcConfigParse *parse)
2004{
2005 FcVStack *vstack;
2006 FcPattern *pattern = FcPatternCreate ();
2007
2008 if (!pattern)
2009 {
2010 FcConfigMessage (parse, FcSevereError, "out of memory");
2011 return;
2012 }
2013
2014 while ((vstack = FcVStackPop (parse)))
2015 {
2016 switch (vstack->tag) {
2017 case FcVStackPattern:
2018 if (!FcPatternAppend (pattern, vstack->u.pattern))
2019 {
2020 FcConfigMessage (parse, FcSevereError, "out of memory");
2de24638 2021 FcPatternDestroy (pattern);
4f27c1c0
KP
2022 return;
2023 }
2024 break;
2025 default:
2026 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2027 break;
2028 }
2029 FcVStackDestroy (vstack);
2030 }
2031
2032 FcVStackPushPattern (parse, pattern);
2033}
2034
c2e7c611
KP
2035static void
2036FcEndElement(void *userData, const XML_Char *name)
2037{
2038 FcConfigParse *parse = userData;
2039 FcChar8 *data;
2040
2041 if (!parse->pstack)
2042 return;
2043 switch (parse->pstack->element) {
2044 case FcElementNone:
2045 break;
2046 case FcElementFontconfig:
2047 break;
2048 case FcElementDir:
2049 data = FcStrBufDone (&parse->pstack->str);
2050 if (!data)
24330d27 2051 {
179c3995 2052 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2053 break;
24330d27 2054 }
daeed6e0
TL
2055#ifdef _WIN32
2056 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2057 {
2058 int rc;
2059 FcStrFree (data);
2060 data = malloc (1000);
2061 if (!data)
2062 {
2063 FcConfigMessage (parse, FcSevereError, "out of memory");
2064 break;
2065 }
2066 FcMemAlloc (FC_MEM_STRING, 1000);
2067 rc = GetWindowsDirectory (data, 800);
2068 if (rc == 0 || rc > 800)
2069 {
2070 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2071 FcStrFree (data);
2072 break;
2073 }
2074 if (data [strlen (data) - 1] != '\\')
2075 strcat (data, "\\");
2076 strcat (data, "fonts");
2077 }
2078#endif
ff3f1f98
KP
2079 if (!FcStrUsesHome (data) || FcConfigHome ())
2080 {
2081 if (!FcConfigAddDir (parse->config, data))
f468f568 2082 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
ff3f1f98 2083 }
9dac3c59 2084 FcStrFree (data);
c2e7c611 2085 break;
7410e40b
PL
2086 case FcElementCacheDir:
2087 data = FcStrBufDone (&parse->pstack->str);
2088 if (!data)
2089 {
2090 FcConfigMessage (parse, FcSevereError, "out of memory");
2091 break;
2092 }
2093 if (!FcStrUsesHome (data) || FcConfigHome ())
2094 {
2095 if (!FcConfigAddCacheDir (parse->config, data))
2096 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2097 }
2098 FcStrFree (data);
2099 break;
2100
c2e7c611
KP
2101 case FcElementCache:
2102 data = FcStrBufDone (&parse->pstack->str);
2103 if (!data)
24330d27 2104 {
179c3995 2105 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2106 break;
c2e7c611 2107 }
2d3387fd 2108 /* discard this data; no longer used */
9dac3c59 2109 FcStrFree (data);
c2e7c611
KP
2110 break;
2111 case FcElementInclude:
2112 FcParseInclude (parse);
2113 break;
2114 case FcElementConfig:
2115 break;
2116 case FcElementMatch:
2117 FcParseMatch (parse);
2118 break;
2119 case FcElementAlias:
2120 FcParseAlias (parse);
2121 break;
2122
2123 case FcElementBlank:
2124 FcParseBlank (parse);
2125 break;
179c3995
KP
2126 case FcElementRescan:
2127 FcParseRescan (parse);
2128 break;
c2e7c611
KP
2129
2130 case FcElementPrefer:
2131 FcParseFamilies (parse, FcVStackPrefer);
2132 break;
2133 case FcElementAccept:
2134 FcParseFamilies (parse, FcVStackAccept);
2135 break;
2136 case FcElementDefault:
2137 FcParseFamilies (parse, FcVStackDefault);
2138 break;
2139 case FcElementFamily:
2140 FcParseFamily (parse);
2141 break;
2142
2143 case FcElementTest:
2144 FcParseTest (parse);
2145 break;
2146 case FcElementEdit:
2147 FcParseEdit (parse);
2148 break;
2149
2150 case FcElementInt:
2151 FcParseInt (parse);
2152 break;
2153 case FcElementDouble:
2154 FcParseDouble (parse);
2155 break;
2156 case FcElementString:
2157 FcParseString (parse, FcVStackString);
2158 break;
2159 case FcElementMatrix:
2160 FcParseMatrix (parse);
2161 break;
2162 case FcElementBool:
2163 FcParseBool (parse);
2164 break;
2165 case FcElementCharset:
2166/* FcParseCharset (parse); */
2167 break;
d47c9d6e
KP
2168 case FcElementSelectfont:
2169 break;
2170 case FcElementAcceptfont:
2171 case FcElementRejectfont:
2172 FcParseAcceptRejectFont (parse, parse->pstack->element);
2173 break;
2174 case FcElementGlob:
2175 FcParseString (parse, FcVStackGlob);
2176 break;
4f27c1c0
KP
2177 case FcElementPattern:
2178 FcParsePattern (parse);
2179 break;
2180 case FcElementPatelt:
2181 FcParsePatelt (parse);
2182 break;
c2e7c611
KP
2183 case FcElementName:
2184 FcParseString (parse, FcVStackField);
2185 break;
2186 case FcElementConst:
2187 FcParseString (parse, FcVStackConstant);
2188 break;
2189 case FcElementOr:
3f7653c2 2190 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2191 break;
2192 case FcElementAnd:
3f7653c2 2193 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2194 break;
2195 case FcElementEq:
3f7653c2 2196 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2197 break;
2198 case FcElementNotEq:
3f7653c2 2199 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2200 break;
2201 case FcElementLess:
3f7653c2 2202 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2203 break;
2204 case FcElementLessEq:
3f7653c2 2205 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2206 break;
2207 case FcElementMore:
3f7653c2 2208 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2209 break;
2210 case FcElementMoreEq:
3f7653c2 2211 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2212 break;
47d4f950 2213 case FcElementContains:
3f7653c2 2214 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2215 break;
2216 case FcElementNotContains:
3f7653c2 2217 FcParseBinary (parse, FcOpNotContains);
47d4f950 2218 break;
c2e7c611 2219 case FcElementPlus:
3f7653c2 2220 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2221 break;
2222 case FcElementMinus:
3f7653c2 2223 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2224 break;
2225 case FcElementTimes:
3f7653c2 2226 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2227 break;
2228 case FcElementDivide:
3f7653c2 2229 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2230 break;
2231 case FcElementNot:
3f7653c2 2232 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2233 break;
2234 case FcElementIf:
3f7653c2
KP
2235 FcParseBinary (parse, FcOpQuest);
2236 break;
2237 case FcElementFloor:
2238 FcParseUnary (parse, FcOpFloor);
2239 break;
2240 case FcElementCeil:
2241 FcParseUnary (parse, FcOpCeil);
2242 break;
2243 case FcElementRound:
2244 FcParseUnary (parse, FcOpRound);
2245 break;
2246 case FcElementTrunc:
2247 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2248 break;
2249 case FcElementUnknown:
2250 break;
24330d27 2251 }
c2e7c611
KP
2252 (void) FcPStackPop (parse);
2253}
2254
2255static void
2256FcCharacterData (void *userData, const XML_Char *s, int len)
2257{
2258 FcConfigParse *parse = userData;
2259
2260 if (!parse->pstack)
2261 return;
2262 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2263 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2264}
2265
2266static void
2267FcStartDoctypeDecl (void *userData,
2268 const XML_Char *doctypeName,
2269 const XML_Char *sysid,
2270 const XML_Char *pubid,
2271 int has_internal_subset)
2272{
2273 FcConfigParse *parse = userData;
2274
2275 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2276 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2277}
2278
0d745819 2279#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2280
2281static void
2282FcInternalSubsetDecl (void *userData,
2283 const XML_Char *doctypeName,
2284 const XML_Char *sysid,
2285 const XML_Char *pubid)
2286{
2287 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2288}
2289
2290static void
2291FcExternalSubsetDecl (void *userData,
2292 const XML_Char *doctypeName,
2293 const XML_Char *sysid,
2294 const XML_Char *pubid)
2295{
2296 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2297}
2298
2299#else /* ENABLE_LIBXML2 */
2300
c2e7c611
KP
2301static void
2302FcEndDoctypeDecl (void *userData)
2303{
24330d27
KP
2304}
2305
e99f0f0a
PL
2306#endif /* ENABLE_LIBXML2 */
2307
9419bb34
KP
2308static int
2309FcSortCmpStr (const void *a, const void *b)
2310{
2311 const FcChar8 *as = *((FcChar8 **) a);
2312 const FcChar8 *bs = *((FcChar8 **) b);
2313 return FcStrCmp (as, bs);
2314}
2315
2d9c79c0
KP
2316static FcBool
2317FcConfigParseAndLoadDir (FcConfig *config,
2318 const FcChar8 *name,
2319 const FcChar8 *dir,
2320 FcBool complain)
2321{
2322 DIR *d;
2323 struct dirent *e;
2324 FcBool ret = FcTrue;
2325 FcChar8 *file;
2326 FcChar8 *base;
2327 FcStrSet *files;
2328
2329 d = opendir ((char *) dir);
2330 if (!d)
2331 {
2332 if (complain)
2333 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2334 name);
2335 ret = FcFalse;
2336 goto bail0;
2337 }
2338 /* freed below */
2339 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2340 if (!file)
2341 {
2342 ret = FcFalse;
2343 goto bail1;
2344 }
2345
2346 strcpy ((char *) file, (char *) dir);
2347 strcat ((char *) file, "/");
2348 base = file + strlen ((char *) file);
2349
2350 files = FcStrSetCreate ();
2351 if (!files)
2352 {
2353 ret = FcFalse;
2354 goto bail2;
2355 }
2356
2357 if (FcDebug () & FC_DBG_CONFIG)
2358 printf ("\tScanning config dir %s\n", dir);
2359
2360 while (ret && (e = readdir (d)))
2361 {
8245771d
PL
2362 int d_len;
2363#define TAIL ".conf"
2364#define TAIL_LEN 5
2d9c79c0 2365 /*
8245771d 2366 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2367 */
2368 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2369 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2370 d_len > TAIL_LEN &&
2371 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2372 {
2373 strcpy ((char *) base, (char *) e->d_name);
2374 if (!FcStrSetAdd (files, file))
2375 {
2376 ret = FcFalse;
2377 goto bail3;
2378 }
2379 }
2380 }
2381 if (ret)
2382 {
2383 int i;
4262e0b3 2384 qsort (files->strs, files->num, sizeof (FcChar8 *),
9419bb34 2385 (int (*)(const void *, const void *)) FcSortCmpStr);
2d9c79c0 2386 for (i = 0; ret && i < files->num; i++)
4262e0b3 2387 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2388 }
2389bail3:
2390 FcStrSetDestroy (files);
2391bail2:
2392 free (file);
2393bail1:
2394 closedir (d);
2395bail0:
2396 return ret || !complain;
2397}
2398
24330d27
KP
2399FcBool
2400FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2401 const FcChar8 *name,
24330d27
KP
2402 FcBool complain)
2403{
24330d27 2404
c2e7c611
KP
2405 XML_Parser p;
2406 FcChar8 *filename;
3bfae75d 2407 int fd;
c2e7c611 2408 int len;
c2e7c611
KP
2409 FcConfigParse parse;
2410 FcBool error = FcTrue;
2411
0d745819 2412#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2413 xmlSAXHandler sax;
2414 char buf[BUFSIZ];
2415#else
2416 void *buf;
2417#endif
2418
c2e7c611
KP
2419 filename = FcConfigFilename (name);
2420 if (!filename)
2421 goto bail0;
4aded3e0 2422
cb6d97eb
PL
2423 if (FcStrSetMember (config->configFiles, filename))
2424 {
2425 FcStrFree (filename);
2426 return FcTrue;
2427 }
2428
4aded3e0 2429 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2430 {
2431 FcStrFree (filename);
4aded3e0 2432 goto bail0;
9dac3c59 2433 }
4aded3e0 2434
2d9c79c0
KP
2435 if (FcFileIsDir (filename))
2436 {
2437 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2438 FcStrFree (filename);
2439 return ret;
2440 }
2441
2442 if (FcDebug () & FC_DBG_CONFIG)
2443 printf ("\tLoading config file %s\n", filename);
2444
3bfae75d
PL
2445 fd = open ((char *) filename, O_RDONLY);
2446 if (fd == -1) {
8f2a8078 2447 FcStrFree (filename);
c2e7c611 2448 goto bail0;
8f2a8078 2449 }
c2e7c611 2450
0d745819 2451#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2452 memset(&sax, 0, sizeof(sax));
2453
2454 sax.internalSubset = FcInternalSubsetDecl;
2455 sax.externalSubset = FcExternalSubsetDecl;
2456 sax.startElement = FcStartElement;
2457 sax.endElement = FcEndElement;
2458 sax.characters = FcCharacterData;
2459
8f2a8078 2460 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2461#else
c2e7c611 2462 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2463#endif
8f2a8078 2464 FcStrFree (filename);
e99f0f0a 2465
c2e7c611
KP
2466 if (!p)
2467 goto bail1;
2468
2469 if (!FcConfigInit (&parse, name, config, p))
2470 goto bail2;
2471
0d745819 2472#ifndef ENABLE_LIBXML2
e99f0f0a 2473
c2e7c611
KP
2474 XML_SetUserData (p, &parse);
2475
2476 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2477 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2478 XML_SetCharacterDataHandler (p, FcCharacterData);
2479
e99f0f0a
PL
2480#endif /* ENABLE_LIBXML2 */
2481
c2e7c611 2482 do {
0d745819 2483#ifndef ENABLE_LIBXML2
c2e7c611
KP
2484 buf = XML_GetBuffer (p, BUFSIZ);
2485 if (!buf)
80c053b7 2486 {
179c3995 2487 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2488 goto bail3;
80c053b7 2489 }
e99f0f0a 2490#endif
3bfae75d 2491 len = read (fd, buf, BUFSIZ);
c2e7c611 2492 if (len < 0)
80c053b7 2493 {
179c3995 2494 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2495 goto bail3;
80c053b7 2496 }
e99f0f0a 2497
0d745819 2498#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2499 if (xmlParseChunk (p, buf, len, len == 0))
2500#else
c2e7c611 2501 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2502#endif
80c053b7 2503 {
179c3995 2504 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2505 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2506 goto bail3;
80c053b7 2507 }
c2e7c611
KP
2508 } while (len != 0);
2509 error = parse.error;
2510bail3:
2511 FcConfigCleanup (&parse);
2512bail2:
2513 XML_ParserFree (p);
2514bail1:
3bfae75d
PL
2515 close (fd);
2516 fd = -1;
c2e7c611
KP
2517bail0:
2518 if (error && complain)
24330d27 2519 {
c2e7c611 2520 if (name)
179c3995 2521 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2522 else
179c3995 2523 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2524 return FcFalse;
2525 }
2526 return FcTrue;
2527}
23816bf9
KP
2528#define __fcxml__
2529#include "fcaliastail.h"
2530#undef __fcxml__