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