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