]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Restore code to skip over PCF fonts that have no encoded characters. (We
[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
25#include <stdarg.h>
26#include "fcint.h"
2d9c79c0 27#include <dirent.h>
0ab36ca8 28
e99f0f0a
PL
29#if ENABLE_LIBXML2
30
31#include <libxml/parser.h>
32
33#define XML_Char xmlChar
34#define XML_Parser xmlParserCtxtPtr
35#define XML_ParserFree xmlFreeParserCtxt
36#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
37#define XML_GetErrorCode xmlCtxtGetLastError
38#define XML_ErrorString(Error) (Error)->message
39
40#else /* ENABLE_LIBXML2 */
41
d0f07b8d
KP
42#ifndef HAVE_XMLPARSE_H
43#define HAVE_XMLPARSE_H 0
44#endif
fa244f3d 45
179c3995
KP
46#if HAVE_XMLPARSE_H
47#include <xmlparse.h>
48#else
49#include <expat.h>
50#endif
24330d27 51
e99f0f0a
PL
52#endif /* ENABLE_LIBXML2 */
53
daeed6e0
TL
54#ifdef _WIN32
55#define STRICT
56#include <windows.h>
57#undef STRICT
58#endif
59
24330d27
KP
60
61void
62FcTestDestroy (FcTest *test)
63{
64 if (test->next)
65 FcTestDestroy (test->next);
66 FcExprDestroy (test->expr);
67 FcStrFree ((FcChar8 *) test->field);
9dac3c59 68 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
24330d27
KP
69 free (test);
70}
71
72FcExpr *
73FcExprCreateInteger (int i)
74{
75 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
76
77 if (e)
78 {
9dac3c59 79 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
80 e->op = FcOpInteger;
81 e->u.ival = i;
82 }
83 return e;
84}
85
86FcExpr *
87FcExprCreateDouble (double d)
88{
89 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
90
91 if (e)
92 {
9dac3c59 93 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
94 e->op = FcOpDouble;
95 e->u.dval = d;
96 }
97 return e;
98}
99
100FcExpr *
ccb3e93b 101FcExprCreateString (const FcChar8 *s)
24330d27
KP
102{
103 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
104
105 if (e)
106 {
9dac3c59 107 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
108 e->op = FcOpString;
109 e->u.sval = FcStrCopy (s);
110 }
111 return e;
112}
113
114FcExpr *
115FcExprCreateMatrix (const FcMatrix *m)
116{
117 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119 if (e)
120 {
9dac3c59 121 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
122 e->op = FcOpMatrix;
123 e->u.mval = FcMatrixCopy (m);
124 }
125 return e;
126}
127
128FcExpr *
129FcExprCreateBool (FcBool b)
130{
131 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
132
133 if (e)
134 {
9dac3c59 135 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
136 e->op = FcOpBool;
137 e->u.bval = b;
138 }
139 return e;
140}
141
142FcExpr *
143FcExprCreateNil (void)
144{
145 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
146
147 if (e)
148 {
9dac3c59 149 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
150 e->op = FcOpNil;
151 }
152 return e;
153}
154
155FcExpr *
156FcExprCreateField (const char *field)
157{
158 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
159
160 if (e)
161 {
9dac3c59 162 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27 163 e->op = FcOpField;
ccb3e93b 164 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
165 }
166 return e;
167}
168
169FcExpr *
ccb3e93b 170FcExprCreateConst (const FcChar8 *constant)
24330d27
KP
171{
172 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174 if (e)
175 {
9dac3c59 176 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
177 e->op = FcOpConst;
178 e->u.constant = FcStrCopy (constant);
179 }
180 return e;
181}
182
183FcExpr *
184FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
185{
186 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
187
188 if (e)
189 {
9dac3c59 190 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
191 e->op = op;
192 e->u.tree.left = left;
193 e->u.tree.right = right;
194 }
195 return e;
196}
197
198void
199FcExprDestroy (FcExpr *e)
200{
3f7653c2
KP
201 if (!e)
202 return;
24330d27
KP
203 switch (e->op) {
204 case FcOpInteger:
205 break;
206 case FcOpDouble:
207 break;
208 case FcOpString:
209 FcStrFree (e->u.sval);
210 break;
211 case FcOpMatrix:
212 FcMatrixFree (e->u.mval);
213 break;
214 case FcOpCharSet:
215 FcCharSetDestroy (e->u.cval);
216 break;
217 case FcOpBool:
218 break;
219 case FcOpField:
ccb3e93b 220 FcStrFree ((FcChar8 *) e->u.field);
24330d27
KP
221 break;
222 case FcOpConst:
223 FcStrFree (e->u.constant);
224 break;
225 case FcOpAssign:
226 case FcOpAssignReplace:
227 case FcOpPrepend:
228 case FcOpPrependFirst:
229 case FcOpAppend:
230 case FcOpAppendLast:
231 break;
232 case FcOpOr:
233 case FcOpAnd:
234 case FcOpEqual:
24330d27
KP
235 case FcOpNotEqual:
236 case FcOpLess:
237 case FcOpLessEqual:
238 case FcOpMore:
239 case FcOpMoreEqual:
47d4f950 240 case FcOpContains:
74a623e0 241 case FcOpListing:
47d4f950 242 case FcOpNotContains:
24330d27
KP
243 case FcOpPlus:
244 case FcOpMinus:
245 case FcOpTimes:
246 case FcOpDivide:
247 case FcOpQuest:
248 case FcOpComma:
249 FcExprDestroy (e->u.tree.right);
250 /* fall through */
251 case FcOpNot:
3f7653c2
KP
252 case FcOpFloor:
253 case FcOpCeil:
254 case FcOpRound:
255 case FcOpTrunc:
24330d27
KP
256 FcExprDestroy (e->u.tree.left);
257 break;
258 case FcOpNil:
259 case FcOpInvalid:
260 break;
261 }
9dac3c59 262 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
263 free (e);
264}
265
24330d27
KP
266void
267FcEditDestroy (FcEdit *e)
268{
269 if (e->next)
270 FcEditDestroy (e->next);
271 FcStrFree ((FcChar8 *) e->field);
272 if (e->expr)
273 FcExprDestroy (e->expr);
34cd0514 274 free (e);
24330d27
KP
275}
276
277char *
278FcConfigSaveField (const char *field)
279{
ccb3e93b 280 return (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
281}
282
c2e7c611
KP
283typedef enum _FcElement {
284 FcElementNone,
285 FcElementFontconfig,
286 FcElementDir,
287 FcElementCache,
288 FcElementInclude,
289 FcElementConfig,
290 FcElementMatch,
291 FcElementAlias,
292
293 FcElementBlank,
179c3995 294 FcElementRescan,
c2e7c611
KP
295
296 FcElementPrefer,
297 FcElementAccept,
298 FcElementDefault,
299 FcElementFamily,
300
d47c9d6e
KP
301 FcElementSelectfont,
302 FcElementAcceptfont,
303 FcElementRejectfont,
304 FcElementGlob,
4f27c1c0
KP
305 FcElementPattern,
306 FcElementPatelt,
d47c9d6e 307
c2e7c611
KP
308 FcElementTest,
309 FcElementEdit,
310 FcElementInt,
311 FcElementDouble,
312 FcElementString,
313 FcElementMatrix,
314 FcElementBool,
315 FcElementCharset,
316 FcElementName,
317 FcElementConst,
318 FcElementOr,
319 FcElementAnd,
320 FcElementEq,
321 FcElementNotEq,
322 FcElementLess,
323 FcElementLessEq,
324 FcElementMore,
325 FcElementMoreEq,
47d4f950
KP
326 FcElementContains,
327 FcElementNotContains,
c2e7c611
KP
328 FcElementPlus,
329 FcElementMinus,
330 FcElementTimes,
331 FcElementDivide,
332 FcElementNot,
333 FcElementIf,
3f7653c2
KP
334 FcElementFloor,
335 FcElementCeil,
336 FcElementRound,
337 FcElementTrunc,
c2e7c611
KP
338 FcElementUnknown
339} FcElement;
340
67accef4
PL
341static struct {
342 const char name[16];
343 FcElement element;
344} fcElementMap[] = {
345 { "fontconfig", FcElementFontconfig },
346 { "dir", FcElementDir },
347 { "cache", FcElementCache },
348 { "include", FcElementInclude },
349 { "config", FcElementConfig },
350 { "match", FcElementMatch },
351 { "alias", FcElementAlias },
352
353 { "blank", FcElementBlank },
354 { "rescan", FcElementRescan },
355
356 { "prefer", FcElementPrefer },
357 { "accept", FcElementAccept },
358 { "default", FcElementDefault },
359 { "family", FcElementFamily },
360
361 { "selectfont", FcElementSelectfont },
362 { "acceptfont", FcElementAcceptfont },
363 { "rejectfont", FcElementRejectfont },
364 { "glob", FcElementGlob },
365 { "pattern", FcElementPattern },
366 { "patelt", FcElementPatelt },
367
368 { "test", FcElementTest },
369 { "edit", FcElementEdit },
370 { "int", FcElementInt },
371 { "double", FcElementDouble },
372 { "string", FcElementString },
373 { "matrix", FcElementMatrix },
374 { "bool", FcElementBool },
375 { "charset", FcElementCharset },
376 { "name", FcElementName },
377 { "const", FcElementConst },
378 { "or", FcElementOr },
379 { "and", FcElementAnd },
380 { "eq", FcElementEq },
381 { "not_eq", FcElementNotEq },
382 { "less", FcElementLess },
383 { "less_eq", FcElementLessEq },
384 { "more", FcElementMore },
385 { "more_eq", FcElementMoreEq },
386 { "contains", FcElementContains },
387 { "not_contains", FcElementNotContains },
388 { "plus", FcElementPlus },
389 { "minus", FcElementMinus },
390 { "times", FcElementTimes },
391 { "divide", FcElementDivide },
392 { "not", FcElementNot },
393 { "if", FcElementIf },
394 { "floor", FcElementFloor },
395 { "ceil", FcElementCeil },
396 { "round", FcElementRound },
397 { "trunc", FcElementTrunc },
398};
399#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
400
c2e7c611
KP
401static FcElement
402FcElementMap (const XML_Char *name)
403{
c2e7c611
KP
404
405 int i;
67accef4 406 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
c2e7c611
KP
407 if (!strcmp ((char *) name, fcElementMap[i].name))
408 return fcElementMap[i].element;
409 return FcElementUnknown;
410}
411
412typedef struct _FcPStack {
413 struct _FcPStack *prev;
414 FcElement element;
415 FcChar8 **attr;
416 FcStrBuf str;
417} FcPStack;
418
419typedef enum _FcVStackTag {
420 FcVStackNone,
421
422 FcVStackString,
423 FcVStackFamily,
424 FcVStackField,
425 FcVStackConstant,
d47c9d6e 426 FcVStackGlob,
4f27c1c0 427 FcVStackPattern,
c2e7c611
KP
428
429 FcVStackPrefer,
430 FcVStackAccept,
431 FcVStackDefault,
432
433 FcVStackInteger,
434 FcVStackDouble,
435 FcVStackMatrix,
436 FcVStackBool,
437
438 FcVStackTest,
439 FcVStackExpr,
440 FcVStackEdit
441} FcVStackTag;
442
443typedef struct _FcVStack {
444 struct _FcVStack *prev;
445 FcPStack *pstack; /* related parse element */
446 FcVStackTag tag;
447 union {
448 FcChar8 *string;
449
450 int integer;
451 double _double;
452 FcMatrix *matrix;
453 FcBool bool;
454
455 FcTest *test;
456 FcQual qual;
457 FcOp op;
458 FcExpr *expr;
459 FcEdit *edit;
4f27c1c0
KP
460
461 FcPattern *pattern;
c2e7c611
KP
462 } u;
463} FcVStack;
464
465typedef struct _FcConfigParse {
466 FcPStack *pstack;
467 FcVStack *vstack;
468 FcBool error;
469 const FcChar8 *name;
470 FcConfig *config;
471 XML_Parser parser;
472} FcConfigParse;
473
179c3995
KP
474typedef enum _FcConfigSeverity {
475 FcSevereInfo, FcSevereWarning, FcSevereError
476} FcConfigSeverity;
477
24330d27 478static void
67accef4 479FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
24330d27 480{
67accef4 481 const char *s = "unknown";
24330d27
KP
482 va_list args;
483
484 va_start (args, fmt);
179c3995
KP
485
486 switch (severe) {
487 case FcSevereInfo: s = "info"; break;
488 case FcSevereWarning: s = "warning"; break;
489 case FcSevereError: s = "error"; break;
490 }
c2e7c611
KP
491 if (parse)
492 {
493 if (parse->name)
179c3995 494 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
c2e7c611
KP
495 parse->name, XML_GetCurrentLineNumber (parse->parser));
496 else
179c3995 497 fprintf (stderr, "Fontconfig %s: line %d: ", s,
c2e7c611 498 XML_GetCurrentLineNumber (parse->parser));
179c3995
KP
499 if (severe >= FcSevereError)
500 parse->error = FcTrue;
c2e7c611
KP
501 }
502 else
179c3995 503 fprintf (stderr, "Fontconfig %s: ", s);
24330d27
KP
504 vfprintf (stderr, fmt, args);
505 fprintf (stderr, "\n");
506 va_end (args);
507}
508
ca60d2b5 509
67accef4 510static const char *
ca60d2b5
KP
511FcTypeName (FcType type)
512{
513 switch (type) {
514 case FcTypeVoid:
515 return "void";
516 case FcTypeInteger:
517 case FcTypeDouble:
518 return "number";
519 case FcTypeString:
520 return "string";
521 case FcTypeBool:
522 return "bool";
523 case FcTypeMatrix:
524 return "matrix";
525 case FcTypeCharSet:
526 return "charset";
527 case FcTypeFTFace:
528 return "FT_Face";
529 case FcTypeLangSet:
530 return "langset";
531 default:
532 return "unknown";
533 }
534}
535
536static void
537FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
538{
539 if (value == FcTypeInteger)
540 value = FcTypeDouble;
541 if (type == FcTypeInteger)
542 type = FcTypeDouble;
543 if (value != type)
544 {
545 if ((value == FcTypeLangSet && type == FcTypeString) ||
546 (value == FcTypeString && type == FcTypeLangSet))
547 return;
548 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
549 FcTypeName (value), FcTypeName (type));
550 }
551}
552
553static void
554FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
555{
556 const FcObjectType *o;
557 const FcConstant *c;
558
559 switch (expr->op) {
560 case FcOpInteger:
561 case FcOpDouble:
562 FcTypecheckValue (parse, FcTypeDouble, type);
563 break;
564 case FcOpString:
565 FcTypecheckValue (parse, FcTypeString, type);
566 break;
567 case FcOpMatrix:
568 FcTypecheckValue (parse, FcTypeMatrix, type);
569 break;
570 case FcOpBool:
571 FcTypecheckValue (parse, FcTypeBool, type);
572 break;
573 case FcOpCharSet:
574 FcTypecheckValue (parse, FcTypeCharSet, type);
575 break;
576 case FcOpNil:
577 break;
578 case FcOpField:
579 o = FcNameGetObjectType (expr->u.field);
580 if (o)
581 FcTypecheckValue (parse, o->type, type);
582 break;
583 case FcOpConst:
584 c = FcNameGetConstant (expr->u.constant);
585 if (c)
586 {
587 o = FcNameGetObjectType (c->object);
588 if (o)
589 FcTypecheckValue (parse, o->type, type);
590 }
f28472fd
PL
591 else
592 FcConfigMessage (parse, FcSevereWarning,
593 "invalid constant used : %s",
594 expr->u.constant);
ca60d2b5
KP
595 break;
596 case FcOpQuest:
597 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
598 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
599 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
600 break;
601 case FcOpAssign:
602 case FcOpAssignReplace:
603 break;
604 case FcOpEqual:
605 case FcOpNotEqual:
606 case FcOpLess:
607 case FcOpLessEqual:
608 case FcOpMore:
609 case FcOpMoreEqual:
610 case FcOpContains:
611 case FcOpNotContains:
612 case FcOpListing:
613 FcTypecheckValue (parse, FcTypeBool, type);
614 break;
615 case FcOpComma:
616 case FcOpOr:
617 case FcOpAnd:
618 case FcOpPlus:
619 case FcOpMinus:
620 case FcOpTimes:
621 case FcOpDivide:
622 FcTypecheckExpr (parse, expr->u.tree.left, type);
623 FcTypecheckExpr (parse, expr->u.tree.right, type);
624 break;
625 case FcOpNot:
626 FcTypecheckValue (parse, FcTypeBool, type);
627 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
628 break;
629 case FcOpFloor:
630 case FcOpCeil:
631 case FcOpRound:
632 case FcOpTrunc:
633 FcTypecheckValue (parse, FcTypeDouble, type);
634 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
635 break;
636 default:
637 break;
638 }
639}
640
641static FcTest *
642FcTestCreate (FcConfigParse *parse,
643 FcMatchKind kind,
644 FcQual qual,
645 const FcChar8 *field,
646 FcOp compare,
647 FcExpr *expr)
648{
649 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
650
651 if (test)
652 {
653 const FcObjectType *o;
654
655 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
656 test->next = 0;
657 test->kind = kind;
658 test->qual = qual;
659 test->field = (char *) FcStrCopy (field);
660 test->op = compare;
661 test->expr = expr;
662 o = FcNameGetObjectType (test->field);
663 if (o)
664 FcTypecheckExpr (parse, expr, o->type);
665 }
666 return test;
667}
668
669static FcEdit *
670FcEditCreate (FcConfigParse *parse,
671 const char *field,
672 FcOp op,
673 FcExpr *expr,
674 FcValueBinding binding)
675{
676 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
677
678 if (e)
679 {
680 const FcObjectType *o;
681
682 e->next = 0;
683 e->field = field; /* already saved in grammar */
684 e->op = op;
685 e->expr = expr;
686 e->binding = binding;
687 o = FcNameGetObjectType (e->field);
688 if (o)
689 FcTypecheckExpr (parse, expr, o->type);
690 }
691 return e;
692}
693
c2e7c611
KP
694static void
695FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
24330d27 696{
c2e7c611
KP
697 vstack->prev = parse->vstack;
698 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
699 parse->vstack = vstack;
24330d27
KP
700}
701
c2e7c611
KP
702static FcVStack *
703FcVStackCreate (void)
24330d27 704{
c2e7c611 705 FcVStack *new;
24330d27 706
c2e7c611
KP
707 new = malloc (sizeof (FcVStack));
708 if (!new)
709 return 0;
9dac3c59 710 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
711 new->tag = FcVStackNone;
712 new->prev = 0;
713 return new;
714}
24330d27 715
c2e7c611
KP
716static void
717FcVStackDestroy (FcVStack *vstack)
24330d27 718{
c2e7c611 719 FcVStack *prev;
24330d27 720
c2e7c611
KP
721 for (; vstack; vstack = prev)
722 {
723 prev = vstack->prev;
724 switch (vstack->tag) {
725 case FcVStackNone:
726 break;
727 case FcVStackString:
728 case FcVStackFamily:
729 case FcVStackField:
730 case FcVStackConstant:
d47c9d6e 731 case FcVStackGlob:
c2e7c611
KP
732 FcStrFree (vstack->u.string);
733 break;
4f27c1c0
KP
734 case FcVStackPattern:
735 FcPatternDestroy (vstack->u.pattern);
736 break;
c2e7c611
KP
737 case FcVStackInteger:
738 case FcVStackDouble:
739 break;
740 case FcVStackMatrix:
741 FcMatrixFree (vstack->u.matrix);
742 break;
743 case FcVStackBool:
744 break;
745 case FcVStackTest:
746 FcTestDestroy (vstack->u.test);
747 break;
748 case FcVStackExpr:
749 case FcVStackPrefer:
750 case FcVStackAccept:
751 case FcVStackDefault:
752 FcExprDestroy (vstack->u.expr);
753 break;
754 case FcVStackEdit:
755 FcEditDestroy (vstack->u.edit);
756 break;
757 }
9dac3c59 758 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
759 free (vstack);
760 }
24330d27
KP
761}
762
763static FcBool
c2e7c611 764FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 765{
c2e7c611
KP
766 FcVStack *vstack = FcVStackCreate ();
767 if (!vstack)
768 return FcFalse;
769 vstack->u.string = string;
770 vstack->tag = tag;
771 FcVStackPush (parse, vstack);
772 return FcTrue;
24330d27
KP
773}
774
775static FcBool
c2e7c611 776FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 777{
c2e7c611
KP
778 FcVStack *vstack = FcVStackCreate ();
779 if (!vstack)
24330d27 780 return FcFalse;
c2e7c611
KP
781 vstack->u.integer = integer;
782 vstack->tag = FcVStackInteger;
783 FcVStackPush (parse, vstack);
784 return FcTrue;
24330d27
KP
785}
786
787static FcBool
c2e7c611 788FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 789{
c2e7c611
KP
790 FcVStack *vstack = FcVStackCreate ();
791 if (!vstack)
24330d27 792 return FcFalse;
c2e7c611
KP
793 vstack->u._double = _double;
794 vstack->tag = FcVStackDouble;
795 FcVStackPush (parse, vstack);
796 return FcTrue;
24330d27
KP
797}
798
799static FcBool
c2e7c611 800FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 801{
c2e7c611
KP
802 FcVStack *vstack = FcVStackCreate ();
803 if (!vstack)
24330d27 804 return FcFalse;
c2e7c611
KP
805 matrix = FcMatrixCopy (matrix);
806 if (!matrix)
24330d27 807 {
c2e7c611
KP
808 FcVStackDestroy (vstack);
809 return FcFalse;
24330d27 810 }
c2e7c611
KP
811 vstack->u.matrix = matrix;
812 vstack->tag = FcVStackMatrix;
813 FcVStackPush (parse, vstack);
814 return FcTrue;
24330d27
KP
815}
816
817static FcBool
c2e7c611 818FcVStackPushBool (FcConfigParse *parse, FcBool bool)
24330d27 819{
c2e7c611
KP
820 FcVStack *vstack = FcVStackCreate ();
821 if (!vstack)
822 return FcFalse;
823 vstack->u.bool = bool;
824 vstack->tag = FcVStackBool;
825 FcVStackPush (parse, vstack);
826 return FcTrue;
827}
24330d27 828
c2e7c611
KP
829static FcBool
830FcVStackPushTest (FcConfigParse *parse, FcTest *test)
831{
832 FcVStack *vstack = FcVStackCreate ();
833 if (!vstack)
24330d27 834 return FcFalse;
c2e7c611
KP
835 vstack->u.test = test;
836 vstack->tag = FcVStackTest;
837 FcVStackPush (parse, vstack);
24330d27
KP
838 return FcTrue;
839}
840
841static FcBool
c2e7c611 842FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 843{
c2e7c611
KP
844 FcVStack *vstack = FcVStackCreate ();
845 if (!vstack)
846 return FcFalse;
847 vstack->u.expr = expr;
848 vstack->tag = tag;
849 FcVStackPush (parse, vstack);
850 return FcTrue;
851}
24330d27 852
c2e7c611
KP
853static FcBool
854FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
855{
856 FcVStack *vstack = FcVStackCreate ();
857 if (!vstack)
24330d27 858 return FcFalse;
c2e7c611
KP
859 vstack->u.edit = edit;
860 vstack->tag = FcVStackEdit;
861 FcVStackPush (parse, vstack);
24330d27
KP
862 return FcTrue;
863}
864
4f27c1c0
KP
865static FcBool
866FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
867{
868 FcVStack *vstack = FcVStackCreate ();
869 if (!vstack)
870 return FcFalse;
871 vstack->u.pattern = pattern;
872 vstack->tag = FcVStackPattern;
873 FcVStackPush (parse, vstack);
874 return FcTrue;
875}
876
c2e7c611
KP
877static FcVStack *
878FcVStackFetch (FcConfigParse *parse, int off)
24330d27 879{
c2e7c611 880 FcVStack *vstack;
24330d27 881
c2e7c611
KP
882 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
883 return vstack;
884}
885
886static void
887FcVStackClear (FcConfigParse *parse)
888{
889 while (parse->vstack && parse->vstack->pstack == parse->pstack)
24330d27 890 {
c2e7c611
KP
891 FcVStack *vstack = parse->vstack;
892 parse->vstack = vstack->prev;
893 vstack->prev = 0;
894 FcVStackDestroy (vstack);
24330d27 895 }
24330d27
KP
896}
897
c2e7c611
KP
898static FcVStack *
899FcVStackPop (FcConfigParse *parse)
24330d27 900{
c2e7c611 901 FcVStack *vstack = parse->vstack;
24330d27 902
c2e7c611 903 if (!vstack || vstack->pstack != parse->pstack)
24330d27 904 return 0;
c2e7c611
KP
905 parse->vstack = vstack->prev;
906 vstack->prev = 0;
907 return vstack;
908}
909
910static int
911FcVStackElements (FcConfigParse *parse)
912{
913 int h = 0;
914 FcVStack *vstack = parse->vstack;
915 while (vstack && vstack->pstack == parse->pstack)
916 {
917 h++;
918 vstack = vstack->prev;
24330d27 919 }
c2e7c611 920 return h;
24330d27
KP
921}
922
c2e7c611
KP
923static FcChar8 **
924FcConfigSaveAttr (const XML_Char **attr)
24330d27 925{
c2e7c611
KP
926 int n;
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 n = i;
938 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
939 if (!new)
940 return 0;
9dac3c59 941 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
c2e7c611
KP
942 s = (FcChar8 *) (new + (i + 1));
943 for (i = 0; attr[i]; i++)
24330d27 944 {
c2e7c611
KP
945 new[i] = s;
946 strcpy ((char *) s, (char *) attr[i]);
947 s += strlen ((char *) s) + 1;
24330d27 948 }
c2e7c611
KP
949 new[i] = 0;
950 return new;
951}
24330d27 952
c2e7c611
KP
953static FcBool
954FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
955{
956 FcPStack *new = malloc (sizeof (FcPStack));
957
958 if (!new)
959 return FcFalse;
9dac3c59 960 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
961 new->prev = parse->pstack;
962 new->element = element;
963 if (attr)
24330d27 964 {
c2e7c611
KP
965 new->attr = FcConfigSaveAttr (attr);
966 if (!new->attr)
179c3995 967 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 968 }
c2e7c611
KP
969 else
970 new->attr = 0;
971 FcStrBufInit (&new->str, 0, 0);
972 parse->pstack = new;
973 return FcTrue;
974}
24330d27 975
c2e7c611
KP
976static FcBool
977FcPStackPop (FcConfigParse *parse)
978{
979 FcPStack *old;
980
981 if (!parse->pstack)
24330d27 982 {
179c3995 983 FcConfigMessage (parse, FcSevereError, "mismatching element");
c2e7c611 984 return FcFalse;
24330d27 985 }
c2e7c611
KP
986 FcVStackClear (parse);
987 old = parse->pstack;
988 parse->pstack = old->prev;
989 FcStrBufDestroy (&old->str);
990 if (old->attr)
9dac3c59
KP
991 {
992 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
c2e7c611 993 free (old->attr);
9dac3c59
KP
994 }
995 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
996 free (old);
997 return FcTrue;
24330d27
KP
998}
999
c2e7c611
KP
1000static FcBool
1001FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
24330d27 1002{
c2e7c611
KP
1003 parse->pstack = 0;
1004 parse->vstack = 0;
1005 parse->error = FcFalse;
1006 parse->name = name;
1007 parse->config = config;
1008 parse->parser = parser;
1009 return FcTrue;
1010}
1011
1012static void
1013FcConfigCleanup (FcConfigParse *parse)
1014{
1015 while (parse->pstack)
1016 FcPStackPop (parse);
1017}
1018
1019static const FcChar8 *
67accef4 1020FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
c2e7c611
KP
1021{
1022 FcChar8 **attrs;
1023 if (!parse->pstack)
24330d27 1024 return 0;
24330d27 1025
c2e7c611 1026 attrs = parse->pstack->attr;
368104c3
PL
1027 if (!attrs)
1028 return 0;
1029
c2e7c611 1030 while (*attrs)
24330d27 1031 {
c2e7c611
KP
1032 if (!strcmp ((char *) *attrs, attr))
1033 return attrs[1];
1034 attrs += 2;
24330d27 1035 }
24330d27
KP
1036 return 0;
1037}
1038
c2e7c611
KP
1039static void
1040FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
24330d27 1041{
c2e7c611
KP
1042 FcConfigParse *parse = userData;
1043 FcElement element;
1044
1045 element = FcElementMap (name);
1046 if (element == FcElementUnknown)
179c3995 1047 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
c2e7c611
KP
1048
1049 if (!FcPStackPush (parse, element, attr))
24330d27 1050 {
179c3995 1051 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1052 return;
24330d27 1053 }
c2e7c611
KP
1054 return;
1055}
24330d27 1056
c2e7c611
KP
1057static void
1058FcParseBlank (FcConfigParse *parse)
1059{
1060 int n = FcVStackElements (parse);
1061 while (n-- > 0)
24330d27 1062 {
c2e7c611
KP
1063 FcVStack *v = FcVStackFetch (parse, n);
1064 if (v->tag != FcVStackInteger)
179c3995 1065 FcConfigMessage (parse, FcSevereError, "non-integer blank");
c2e7c611 1066 else
24330d27 1067 {
c2e7c611 1068 if (!parse->config->blanks)
24330d27 1069 {
c2e7c611
KP
1070 parse->config->blanks = FcBlanksCreate ();
1071 if (!parse->config->blanks)
1072 {
179c3995 1073 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1074 break;
1075 }
24330d27 1076 }
c2e7c611 1077 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
24330d27 1078 {
179c3995 1079 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1080 break;
24330d27
KP
1081 }
1082 }
1083 }
c2e7c611 1084}
24330d27 1085
179c3995
KP
1086static void
1087FcParseRescan (FcConfigParse *parse)
1088{
1089 int n = FcVStackElements (parse);
1090 while (n-- > 0)
1091 {
1092 FcVStack *v = FcVStackFetch (parse, n);
1093 if (v->tag != FcVStackInteger)
1094 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1095 else
1096 parse->config->rescanInterval = v->u.integer;
1097 }
1098}
1099
c2e7c611
KP
1100static void
1101FcParseInt (FcConfigParse *parse)
1102{
1103 FcChar8 *s, *end;
1104 int l;
1105
1106 if (!parse->pstack)
1107 return;
1108 s = FcStrBufDone (&parse->pstack->str);
1109 if (!s)
24330d27 1110 {
179c3995 1111 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1112 return;
24330d27 1113 }
c2e7c611
KP
1114 end = 0;
1115 l = (int) strtol ((char *) s, (char **)&end, 0);
1116 if (end != s + strlen ((char *) s))
179c3995 1117 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
c2e7c611
KP
1118 else
1119 FcVStackPushInteger (parse, l);
1120 FcStrFree (s);
24330d27
KP
1121}
1122
223c0289
KP
1123/*
1124 * idea copied from glib g_ascii_strtod with
1125 * permission of the author (Alexander Larsson)
1126 */
1127
1128#include <locale.h>
1129
1130static double
1131FcStrtod (char *s, char **end)
1132{
1133 struct lconv *locale_data;
1134 char *dot;
1135 double v;
1136
1137 /*
1138 * Have to swap the decimal point to match the current locale
1139 * if that locale doesn't use 0x2e
1140 */
1141 if ((dot = strchr (s, 0x2e)) &&
1142 (locale_data = localeconv ()) &&
1143 (locale_data->decimal_point[0] != 0x2e ||
1144 locale_data->decimal_point[1] != 0))
1145 {
1146 char buf[128];
1147 int slen = strlen (s);
1148 int dlen = strlen (locale_data->decimal_point);
1149
67accef4 1150 if (slen + dlen > (int) sizeof (buf))
223c0289
KP
1151 {
1152 if (end)
1153 *end = s;
1154 v = 0;
1155 }
1156 else
1157 {
1158 char *buf_end;
1159 /* mantissa */
1160 strncpy (buf, s, dot - s);
1161 /* decimal point */
1162 strcpy (buf + (dot - s), locale_data->decimal_point);
1163 /* rest of number */
1164 strcpy (buf + (dot - s) + dlen, dot + 1);
1165 buf_end = 0;
1166 v = strtod (buf, &buf_end);
344a0e33
RP
1167 if (buf_end) {
1168 buf_end = s + (buf_end - buf);
1169 if (buf_end > dot)
1170 buf_end -= dlen - 1;
1171 }
223c0289
KP
1172 if (end)
1173 *end = buf_end;
1174 }
1175 }
1176 else
1177 v = strtod (s, end);
1178 return v;
1179}
1180
c2e7c611
KP
1181static void
1182FcParseDouble (FcConfigParse *parse)
24330d27 1183{
c2e7c611
KP
1184 FcChar8 *s, *end;
1185 double d;
24330d27 1186
c2e7c611
KP
1187 if (!parse->pstack)
1188 return;
1189 s = FcStrBufDone (&parse->pstack->str);
1190 if (!s)
24330d27 1191 {
179c3995 1192 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1193 return;
24330d27 1194 }
c2e7c611 1195 end = 0;
223c0289 1196 d = FcStrtod ((char *) s, (char **)&end);
c2e7c611 1197 if (end != s + strlen ((char *) s))
179c3995 1198 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
24330d27 1199 else
c2e7c611
KP
1200 FcVStackPushDouble (parse, d);
1201 FcStrFree (s);
1202}
24330d27 1203
c2e7c611
KP
1204static void
1205FcParseString (FcConfigParse *parse, FcVStackTag tag)
1206{
1207 FcChar8 *s;
1208
1209 if (!parse->pstack)
1210 return;
1211 s = FcStrBufDone (&parse->pstack->str);
1212 if (!s)
1213 {
179c3995 1214 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1215 return;
1216 }
1217 if (!FcVStackPushString (parse, tag, s))
1218 FcStrFree (s);
1219}
1220
1221static void
1222FcParseMatrix (FcConfigParse *parse)
1223{
1224 FcVStack *vstack;
1225 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1226 FcMatrix m;
1227
1228 while ((vstack = FcVStackPop (parse)))
1229 {
179c3995
KP
1230 double v;
1231 switch (vstack->tag) {
1232 case FcVStackInteger:
1233 v = vstack->u.integer;
1234 break;
1235 case FcVStackDouble:
1236 v = vstack->u._double;
1237 break;
1238 default:
1239 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1240 v = 1.0;
1241 break;
1242 }
1243 switch (matrix_state) {
1244 case m_xx: m.xx = v; break;
1245 case m_xy: m.xy = v; break;
1246 case m_yx: m.yx = v; break;
1247 case m_yy: m.yy = v; break;
1248 default: break;
c2e7c611 1249 }
f4fe447f 1250 FcVStackDestroy (vstack);
179c3995 1251 matrix_state--;
c2e7c611
KP
1252 }
1253 if (matrix_state != m_done)
179c3995 1254 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
c2e7c611
KP
1255 else
1256 FcVStackPushMatrix (parse, &m);
24330d27
KP
1257}
1258
1259static FcBool
ca60d2b5 1260FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
c2e7c611 1261{
ca60d2b5
KP
1262 FcBool result = FcFalse;
1263
1264 if (!FcNameBool (bool, &result))
1265 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1266 bool);
1267 return result;
c2e7c611
KP
1268}
1269
1270static void
1271FcParseBool (FcConfigParse *parse)
1272{
1273 FcChar8 *s;
1274
1275 if (!parse->pstack)
1276 return;
1277 s = FcStrBufDone (&parse->pstack->str);
1278 if (!s)
1279 {
179c3995 1280 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1281 return;
1282 }
ca60d2b5 1283 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
c2e7c611
KP
1284 FcStrFree (s);
1285}
1286
1287static void
1288FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1289{
c2e7c611
KP
1290 FcVStack *vstack;
1291 FcExpr *left, *expr = 0, *new;
1292
1293 while ((vstack = FcVStackPop (parse)))
1294 {
1295 if (vstack->tag != FcVStackFamily)
1296 {
179c3995
KP
1297 FcConfigMessage (parse, FcSevereWarning, "non-family");
1298 FcVStackDestroy (vstack);
1299 continue;
c2e7c611
KP
1300 }
1301 left = vstack->u.expr;
1302 vstack->tag = FcVStackNone;
1303 FcVStackDestroy (vstack);
1304 if (expr)
1305 {
1306 new = FcExprCreateOp (left, FcOpComma, expr);
1307 if (!new)
1308 {
179c3995 1309 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1310 FcExprDestroy (left);
1311 FcExprDestroy (expr);
1312 break;
1313 }
1314 expr = new;
1315 }
1316 else
1317 expr = left;
1318 }
1319 if (expr)
1320 {
1321 if (!FcVStackPushExpr (parse, tag, expr))
1322 {
179c3995 1323 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1324 if (expr)
1325 FcExprDestroy (expr);
1326 }
1327 }
1328}
1329
1330static void
1331FcParseFamily (FcConfigParse *parse)
1332{
1333 FcChar8 *s;
1334 FcExpr *expr;
1335
1336 if (!parse->pstack)
1337 return;
1338 s = FcStrBufDone (&parse->pstack->str);
1339 if (!s)
1340 {
179c3995 1341 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1342 return;
1343 }
1344 expr = FcExprCreateString (s);
1345 FcStrFree (s);
1346 if (expr)
1347 FcVStackPushExpr (parse, FcVStackFamily, expr);
1348}
1349
1350static void
1351FcParseAlias (FcConfigParse *parse)
1352{
179c3995 1353 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1354 FcEdit *edit = 0, *next;
c2e7c611 1355 FcVStack *vstack;
24330d27
KP
1356 FcTest *test;
1357
c2e7c611 1358 while ((vstack = FcVStackPop (parse)))
24330d27 1359 {
c2e7c611
KP
1360 switch (vstack->tag) {
1361 case FcVStackFamily:
1362 if (family)
179c3995
KP
1363 {
1364 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1365 if (!new)
1366 FcConfigMessage (parse, FcSevereError, "out of memory");
1367 else
1368 family = new;
1369 }
1370 else
1371 new = vstack->u.expr;
1372 if (new)
1373 {
1374 family = new;
1375 vstack->tag = FcVStackNone;
1376 }
c2e7c611
KP
1377 break;
1378 case FcVStackPrefer:
1379 if (prefer)
1380 FcExprDestroy (prefer);
1381 prefer = vstack->u.expr;
1382 vstack->tag = FcVStackNone;
1383 break;
1384 case FcVStackAccept:
1385 if (accept)
1386 FcExprDestroy (accept);
1387 accept = vstack->u.expr;
1388 vstack->tag = FcVStackNone;
1389 break;
1390 case FcVStackDefault:
1391 if (def)
1392 FcExprDestroy (def);
1393 def = vstack->u.expr;
1394 vstack->tag = FcVStackNone;
1395 break;
1396 default:
179c3995 1397 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1398 break;
1399 }
1400 FcVStackDestroy (vstack);
24330d27 1401 }
ccb3e93b 1402 if (!family)
c2e7c611 1403 {
179c3995
KP
1404 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1405 if (prefer)
1406 FcExprDestroy (prefer);
1407 if (accept)
1408 FcExprDestroy (accept);
1409 if (def)
1410 FcExprDestroy (def);
c2e7c611
KP
1411 return;
1412 }
24330d27
KP
1413 if (prefer)
1414 {
ca60d2b5
KP
1415 edit = FcEditCreate (parse,
1416 FcConfigSaveField ("family"),
24330d27 1417 FcOpPrepend,
6fff2cda
KP
1418 prefer,
1419 FcValueBindingWeak);
24330d27
KP
1420 if (edit)
1421 edit->next = 0;
c2e7c611
KP
1422 else
1423 FcExprDestroy (prefer);
24330d27
KP
1424 }
1425 if (accept)
1426 {
1427 next = edit;
ca60d2b5
KP
1428 edit = FcEditCreate (parse,
1429 FcConfigSaveField ("family"),
24330d27 1430 FcOpAppend,
6fff2cda
KP
1431 accept,
1432 FcValueBindingWeak);
24330d27
KP
1433 if (edit)
1434 edit->next = next;
c2e7c611
KP
1435 else
1436 FcExprDestroy (accept);
24330d27
KP
1437 }
1438 if (def)
1439 {
1440 next = edit;
ca60d2b5
KP
1441 edit = FcEditCreate (parse,
1442 FcConfigSaveField ("family"),
6fff2cda
KP
1443 FcOpAppendLast,
1444 def,
1445 FcValueBindingWeak);
24330d27
KP
1446 if (edit)
1447 edit->next = next;
c2e7c611
KP
1448 else
1449 FcExprDestroy (def);
24330d27
KP
1450 }
1451 if (edit)
1452 {
ca60d2b5 1453 test = FcTestCreate (parse, FcMatchPattern,
938bc633 1454 FcQualAny,
2623c1eb 1455 (FcChar8 *) FC_FAMILY,
24330d27
KP
1456 FcOpEqual,
1457 family);
1458 if (test)
c2e7c611
KP
1459 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1460 FcTestDestroy (test);
24330d27 1461 }
c2e7c611
KP
1462 else
1463 FcExprDestroy (family);
24330d27
KP
1464}
1465
c2e7c611
KP
1466static FcExpr *
1467FcPopExpr (FcConfigParse *parse)
24330d27 1468{
c2e7c611
KP
1469 FcVStack *vstack = FcVStackPop (parse);
1470 FcExpr *expr = 0;
1471 if (!vstack)
1472 return 0;
1473 switch (vstack->tag) {
1474 case FcVStackNone:
1475 break;
1476 case FcVStackString:
1477 case FcVStackFamily:
bbbaac36
KP
1478 expr = FcExprCreateString (vstack->u.string);
1479 break;
c2e7c611 1480 case FcVStackField:
bbbaac36
KP
1481 expr = FcExprCreateField ((char *) vstack->u.string);
1482 break;
c2e7c611 1483 case FcVStackConstant:
bbbaac36 1484 expr = FcExprCreateConst (vstack->u.string);
c2e7c611 1485 break;
34cd0514
CW
1486 case FcVStackGlob:
1487 /* XXX: What's the correct action here? (CDW) */
1488 break;
c2e7c611
KP
1489 case FcVStackPrefer:
1490 case FcVStackAccept:
1491 case FcVStackDefault:
1492 expr = vstack->u.expr;
1493 vstack->tag = FcVStackNone;
1494 break;
1495 case FcVStackInteger:
1496 expr = FcExprCreateInteger (vstack->u.integer);
1497 break;
1498 case FcVStackDouble:
1499 expr = FcExprCreateDouble (vstack->u._double);
1500 break;
1501 case FcVStackMatrix:
1502 expr = FcExprCreateMatrix (vstack->u.matrix);
1503 break;
1504 case FcVStackBool:
1505 expr = FcExprCreateBool (vstack->u.bool);
1506 break;
1507 case FcVStackTest:
1508 break;
1509 case FcVStackExpr:
1510 expr = vstack->u.expr;
8ec077f2 1511 vstack->tag = FcVStackNone;
c2e7c611
KP
1512 break;
1513 case FcVStackEdit:
1514 break;
4f27c1c0
KP
1515 default:
1516 break;
c2e7c611
KP
1517 }
1518 FcVStackDestroy (vstack);
1519 return expr;
1520}
1521
3f7653c2
KP
1522/*
1523 * This builds a tree of binary operations. Note
1524 * that every operator is defined so that if only
1525 * a single operand is contained, the value of the
1526 * whole expression is the value of the operand.
1527 *
1528 * This code reduces in that case to returning that
1529 * operand.
1530 */
c2e7c611 1531static FcExpr *
3f7653c2 1532FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1533{
1534 FcExpr *left, *expr = 0, *new;
24330d27 1535
c2e7c611 1536 while ((left = FcPopExpr (parse)))
24330d27 1537 {
c2e7c611 1538 if (expr)
24330d27 1539 {
c2e7c611
KP
1540 new = FcExprCreateOp (left, op, expr);
1541 if (!new)
1542 {
179c3995 1543 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1544 FcExprDestroy (left);
1545 FcExprDestroy (expr);
24330d27 1546 break;
c2e7c611
KP
1547 }
1548 expr = new;
24330d27 1549 }
c2e7c611
KP
1550 else
1551 expr = left;
1552 }
1553 return expr;
1554}
1555
1556static void
3f7653c2
KP
1557FcParseBinary (FcConfigParse *parse, FcOp op)
1558{
1559 FcExpr *expr = FcPopBinary (parse, op);
1560 if (expr)
1561 FcVStackPushExpr (parse, FcVStackExpr, expr);
1562}
1563
1564/*
1565 * This builds a a unary operator, it consumes only
1566 * a single operand
1567 */
1568
1569static FcExpr *
1570FcPopUnary (FcConfigParse *parse, FcOp op)
1571{
1572 FcExpr *operand, *new = 0;
1573
1574 if ((operand = FcPopExpr (parse)))
1575 {
1576 new = FcExprCreateOp (operand, op, 0);
1577 if (!new)
1578 {
1579 FcExprDestroy (operand);
1580 FcConfigMessage (parse, FcSevereError, "out of memory");
1581 }
1582 }
1583 return new;
1584}
1585
1586static void
1587FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1588{
3f7653c2 1589 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1590 if (expr)
1591 FcVStackPushExpr (parse, FcVStackExpr, expr);
1592}
1593
1594static void
1595FcParseInclude (FcConfigParse *parse)
1596{
1597 FcChar8 *s;
1598 const FcChar8 *i;
1599 FcBool ignore_missing = FcFalse;
1600
1601 s = FcStrBufDone (&parse->pstack->str);
1602 if (!s)
1603 {
179c3995 1604 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1605 return;
1606 }
1607 i = FcConfigGetAttribute (parse, "ignore_missing");
ca60d2b5 1608 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
c2e7c611 1609 ignore_missing = FcTrue;
24c90386 1610 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1611 parse->error = FcTrue;
9dac3c59 1612 FcStrFree (s);
c2e7c611
KP
1613}
1614
1615typedef struct _FcOpMap {
67accef4 1616 char name[16];
c2e7c611
KP
1617 FcOp op;
1618} FcOpMap;
1619
1620static FcOp
1621FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1622{
1623 int i;
1624
1625 for (i = 0; i < nmap; i++)
1626 if (!strcmp ((char *) op, map[i].name))
1627 return map[i].op;
1628 return FcOpInvalid;
1629}
1630
1631static const FcOpMap fcCompareOps[] = {
1632 { "eq", FcOpEqual },
1633 { "not_eq", FcOpNotEqual },
1634 { "less", FcOpLess },
1635 { "less_eq", FcOpLessEqual },
1636 { "more", FcOpMore },
47d4f950
KP
1637 { "more_eq", FcOpMoreEqual },
1638 { "contains", FcOpContains },
1639 { "not_contains", FcOpNotContains }
c2e7c611
KP
1640};
1641
67accef4 1642#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
c2e7c611
KP
1643
1644static FcOp
1645FcConfigLexCompare (const FcChar8 *compare)
1646{
1647 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1648}
1649
1650
1651static void
1652FcParseTest (FcConfigParse *parse)
1653{
938bc633
KP
1654 const FcChar8 *kind_string;
1655 FcMatchKind kind;
c2e7c611
KP
1656 const FcChar8 *qual_string;
1657 FcQual qual;
1658 const FcChar8 *name;
1659 const FcChar8 *compare_string;
1660 FcOp compare;
1661 FcExpr *expr;
1662 FcTest *test;
1663
938bc633
KP
1664 kind_string = FcConfigGetAttribute (parse, "target");
1665 if (!kind_string)
1666 kind = FcMatchDefault;
1667 else
1668 {
1669 if (!strcmp ((char *) kind_string, "pattern"))
1670 kind = FcMatchPattern;
1671 else if (!strcmp ((char *) kind_string, "font"))
1672 kind = FcMatchFont;
1673 else if (!strcmp ((char *) kind_string, "default"))
1674 kind = FcMatchDefault;
1675 else
1676 {
1677 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1678 return;
1679 }
1680 }
c2e7c611
KP
1681 qual_string = FcConfigGetAttribute (parse, "qual");
1682 if (!qual_string)
1683 qual = FcQualAny;
1684 else
1685 {
1686 if (!strcmp ((char *) qual_string, "any"))
1687 qual = FcQualAny;
1688 else if (!strcmp ((char *) qual_string, "all"))
1689 qual = FcQualAll;
6f6563ed
KP
1690 else if (!strcmp ((char *) qual_string, "first"))
1691 qual = FcQualFirst;
1692 else if (!strcmp ((char *) qual_string, "not_first"))
1693 qual = FcQualNotFirst;
c2e7c611 1694 else
24330d27 1695 {
179c3995 1696 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1697 return;
24330d27 1698 }
c2e7c611
KP
1699 }
1700 name = FcConfigGetAttribute (parse, "name");
1701 if (!name)
1702 {
179c3995 1703 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1704 return;
c2e7c611
KP
1705 }
1706 compare_string = FcConfigGetAttribute (parse, "compare");
1707 if (!compare_string)
1708 compare = FcOpEqual;
1709 else
1710 {
1711 compare = FcConfigLexCompare (compare_string);
1712 if (compare == FcOpInvalid)
24330d27 1713 {
179c3995 1714 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1715 return;
24330d27 1716 }
c2e7c611 1717 }
3f7653c2 1718 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1719 if (!expr)
1720 {
179c3995 1721 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1722 return;
1723 }
ca60d2b5 1724 test = FcTestCreate (parse, kind, qual, name, compare, expr);
c2e7c611
KP
1725 if (!test)
1726 {
179c3995 1727 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1728 return;
1729 }
1730 FcVStackPushTest (parse, test);
1731}
1732
1733static const FcOpMap fcModeOps[] = {
1734 { "assign", FcOpAssign },
1735 { "assign_replace", FcOpAssignReplace },
1736 { "prepend", FcOpPrepend },
1737 { "prepend_first", FcOpPrependFirst },
1738 { "append", FcOpAppend },
1739 { "append_last", FcOpAppendLast },
1740};
1741
67accef4 1742#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
c2e7c611
KP
1743
1744static FcOp
1745FcConfigLexMode (const FcChar8 *mode)
1746{
1747 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1748}
1749
1750static void
1751FcParseEdit (FcConfigParse *parse)
1752{
1753 const FcChar8 *name;
1754 const FcChar8 *mode_string;
6fff2cda 1755 const FcChar8 *binding_string;
c2e7c611 1756 FcOp mode;
6fff2cda 1757 FcValueBinding binding;
c2e7c611
KP
1758 FcExpr *expr;
1759 FcEdit *edit;
1760
1761 name = FcConfigGetAttribute (parse, "name");
1762 if (!name)
1763 {
179c3995 1764 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1765 return;
c2e7c611
KP
1766 }
1767 mode_string = FcConfigGetAttribute (parse, "mode");
1768 if (!mode_string)
8ec077f2 1769 mode = FcOpAssign;
c2e7c611
KP
1770 else
1771 {
1772 mode = FcConfigLexMode (mode_string);
1773 if (mode == FcOpInvalid)
24330d27 1774 {
179c3995 1775 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1776 return;
24330d27 1777 }
c2e7c611 1778 }
6fff2cda
KP
1779 binding_string = FcConfigGetAttribute (parse, "binding");
1780 if (!binding_string)
1781 binding = FcValueBindingWeak;
1782 else
1783 {
1784 if (!strcmp ((char *) binding_string, "weak"))
1785 binding = FcValueBindingWeak;
1786 else if (!strcmp ((char *) binding_string, "strong"))
1787 binding = FcValueBindingStrong;
dda7794f
KP
1788 else if (!strcmp ((char *) binding_string, "same"))
1789 binding = FcValueBindingSame;
6fff2cda
KP
1790 else
1791 {
1792 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1793 return;
1794 }
1795 }
3f7653c2 1796 expr = FcPopBinary (parse, FcOpComma);
ca60d2b5 1797 edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
c2e7c611
KP
1798 if (!edit)
1799 {
179c3995 1800 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1801 FcExprDestroy (expr);
1802 return;
1803 }
1804 if (!FcVStackPushEdit (parse, edit))
1805 FcEditDestroy (edit);
1806}
1807
1808static void
1809FcParseMatch (FcConfigParse *parse)
1810{
1811 const FcChar8 *kind_name;
1812 FcMatchKind kind;
1813 FcTest *test = 0;
1814 FcEdit *edit = 0;
1815 FcVStack *vstack;
1816
1817 kind_name = FcConfigGetAttribute (parse, "target");
1818 if (!kind_name)
1819 kind = FcMatchPattern;
1820 else
1821 {
1822 if (!strcmp ((char *) kind_name, "pattern"))
1823 kind = FcMatchPattern;
1824 else if (!strcmp ((char *) kind_name, "font"))
1825 kind = FcMatchFont;
1826 else
24330d27 1827 {
179c3995 1828 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1829 return;
24330d27 1830 }
c2e7c611
KP
1831 }
1832 while ((vstack = FcVStackPop (parse)))
1833 {
1834 switch (vstack->tag) {
1835 case FcVStackTest:
1836 vstack->u.test->next = test;
1837 test = vstack->u.test;
1838 vstack->tag = FcVStackNone;
1839 break;
1840 case FcVStackEdit:
1841 vstack->u.edit->next = edit;
1842 edit = vstack->u.edit;
1843 vstack->tag = FcVStackNone;
1844 break;
1845 default:
179c3995 1846 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1847 break;
1848 }
1849 FcVStackDestroy (vstack);
1850 }
1851 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1852 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1853}
1854
d47c9d6e
KP
1855static void
1856FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1857{
1858 FcVStack *vstack;
1859
1860 while ((vstack = FcVStackPop (parse)))
1861 {
1862 switch (vstack->tag) {
1863 case FcVStackGlob:
1864 if (!FcConfigGlobAdd (parse->config,
1865 vstack->u.string,
1866 element == FcElementAcceptfont))
1867 {
1868 FcConfigMessage (parse, FcSevereError, "out of memory");
1869 }
1870 break;
4f27c1c0
KP
1871 case FcVStackPattern:
1872 if (!FcConfigPatternsAdd (parse->config,
1873 vstack->u.pattern,
1874 element == FcElementAcceptfont))
1875 {
1876 FcConfigMessage (parse, FcSevereError, "out of memory");
1877 }
1878 else
1879 vstack->tag = FcVStackNone;
1880 break;
d47c9d6e
KP
1881 default:
1882 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1883 break;
1884 }
1885 FcVStackDestroy (vstack);
1886 }
1887}
1888
4f27c1c0
KP
1889
1890static FcValue
1891FcPopValue (FcConfigParse *parse)
1892{
1893 FcVStack *vstack = FcVStackPop (parse);
1894 FcValue value;
1895
1896 value.type = FcTypeVoid;
1897
1898 if (!vstack)
1899 return value;
1900
1901 switch (vstack->tag) {
1902 case FcVStackString:
4262e0b3
PL
1903 value.u.s = FcStrCopy (vstack->u.string);
1904 if (value.u.s)
4f27c1c0
KP
1905 value.type = FcTypeString;
1906 break;
1907 case FcVStackConstant:
1908 if (FcNameConstant (vstack->u.string, &value.u.i))
1909 value.type = FcTypeInteger;
1910 break;
1911 case FcVStackInteger:
1912 value.u.i = vstack->u.integer;
1913 value.type = FcTypeInteger;
1914 break;
1915 case FcVStackDouble:
1916 value.u.d = vstack->u._double;
1917 value.type = FcTypeInteger;
1918 break;
1919 case FcVStackMatrix:
4262e0b3
PL
1920 value.u.m = FcMatrixCopy (vstack->u.matrix);
1921 if (value.u.m)
4f27c1c0
KP
1922 value.type = FcTypeMatrix;
1923 break;
1924 case FcVStackBool:
1925 value.u.b = vstack->u.bool;
1926 value.type = FcTypeBool;
1927 break;
1928 default:
1929 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1930 vstack->tag);
1931 break;
1932 }
1933 FcVStackDestroy (vstack);
1934
1935 return value;
1936}
1937
1938static void
1939FcParsePatelt (FcConfigParse *parse)
1940{
1941 FcValue value;
1942 FcPattern *pattern = FcPatternCreate ();
1943 const char *name;
1944
1945 if (!pattern)
1946 {
1947 FcConfigMessage (parse, FcSevereError, "out of memory");
1948 return;
1949 }
1950
8245771d 1951 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
1952 if (!name)
1953 {
1954 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1955 return;
1956 }
4f27c1c0
KP
1957
1958 for (;;)
1959 {
1960 value = FcPopValue (parse);
1961 if (value.type == FcTypeVoid)
1962 break;
1963 if (!FcPatternAdd (pattern, name, value, FcTrue))
1964 {
1965 FcConfigMessage (parse, FcSevereError, "out of memory");
1966 break;
1967 }
1968 }
1969
1970 FcVStackPushPattern (parse, pattern);
1971}
1972
1973static void
1974FcParsePattern (FcConfigParse *parse)
1975{
1976 FcVStack *vstack;
1977 FcPattern *pattern = FcPatternCreate ();
1978
1979 if (!pattern)
1980 {
1981 FcConfigMessage (parse, FcSevereError, "out of memory");
1982 return;
1983 }
1984
1985 while ((vstack = FcVStackPop (parse)))
1986 {
1987 switch (vstack->tag) {
1988 case FcVStackPattern:
1989 if (!FcPatternAppend (pattern, vstack->u.pattern))
1990 {
1991 FcConfigMessage (parse, FcSevereError, "out of memory");
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))
2052 FcConfigMessage (parse, FcSevereError, "out of memory");
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
e99f0f0a
PL
2238#if ENABLE_LIBXML2
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;
2358 FILE *f;
2359 int len;
c2e7c611
KP
2360 FcConfigParse parse;
2361 FcBool error = FcTrue;
2362
e99f0f0a
PL
2363#if ENABLE_LIBXML2
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
c2e7c611 2396 f = fopen ((char *) filename, "r");
8f2a8078
PL
2397 if (!f) {
2398 FcStrFree (filename);
c2e7c611 2399 goto bail0;
8f2a8078 2400 }
c2e7c611 2401
e99f0f0a
PL
2402#if ENABLE_LIBXML2
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
e99f0f0a
PL
2423#if !ENABLE_LIBXML2
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 {
e99f0f0a 2434#if !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
c2e7c611
KP
2442 len = fread (buf, 1, BUFSIZ, f);
2443 if (len < 0)
80c053b7 2444 {
179c3995 2445 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2446 goto bail3;
80c053b7 2447 }
e99f0f0a
PL
2448
2449#if ENABLE_LIBXML2
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:
2466 fclose (f);
e1b9d091 2467 f = NULL;
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}