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