]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Eliminate .so PLT entries for local symbols. (thanks to Arjan van de Ven)
[fontconfig.git] / src / fcxml.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2002 Keith Packard
24330d27
KP
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
f045376c 25#include "fcint.h"
3bfae75d 26#include <fcntl.h>
24330d27 27#include <stdarg.h>
2d9c79c0 28#include <dirent.h>
0ab36ca8 29
0d745819 30#ifdef ENABLE_LIBXML2
e99f0f0a
PL
31
32#include <libxml/parser.h>
33
34#define XML_Char xmlChar
35#define XML_Parser xmlParserCtxtPtr
36#define XML_ParserFree xmlFreeParserCtxt
37#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
38#define XML_GetErrorCode xmlCtxtGetLastError
39#define XML_ErrorString(Error) (Error)->message
40
41#else /* ENABLE_LIBXML2 */
42
d0f07b8d
KP
43#ifndef HAVE_XMLPARSE_H
44#define HAVE_XMLPARSE_H 0
45#endif
fa244f3d 46
179c3995
KP
47#if HAVE_XMLPARSE_H
48#include <xmlparse.h>
49#else
50#include <expat.h>
51#endif
24330d27 52
e99f0f0a
PL
53#endif /* ENABLE_LIBXML2 */
54
daeed6e0
TL
55#ifdef _WIN32
56#define STRICT
57#include <windows.h>
58#undef STRICT
59#endif
60
24330d27
KP
61
62void
63FcTestDestroy (FcTest *test)
64{
65 if (test->next)
66 FcTestDestroy (test->next);
67 FcExprDestroy (test->expr);
9dac3c59 68 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
24330d27
KP
69 free (test);
70}
71
72FcExpr *
73FcExprCreateInteger (int i)
74{
75 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
76
77 if (e)
78 {
9dac3c59 79 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
80 e->op = FcOpInteger;
81 e->u.ival = i;
82 }
83 return e;
84}
85
86FcExpr *
87FcExprCreateDouble (double d)
88{
89 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
90
91 if (e)
92 {
9dac3c59 93 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
94 e->op = FcOpDouble;
95 e->u.dval = d;
96 }
97 return e;
98}
99
100FcExpr *
ccb3e93b 101FcExprCreateString (const FcChar8 *s)
24330d27
KP
102{
103 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
104
105 if (e)
106 {
9dac3c59 107 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
108 e->op = FcOpString;
109 e->u.sval = FcStrCopy (s);
110 }
111 return e;
112}
113
114FcExpr *
115FcExprCreateMatrix (const FcMatrix *m)
116{
117 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119 if (e)
120 {
9dac3c59 121 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
122 e->op = FcOpMatrix;
123 e->u.mval = FcMatrixCopy (m);
124 }
125 return e;
126}
127
128FcExpr *
129FcExprCreateBool (FcBool b)
130{
131 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
132
133 if (e)
134 {
9dac3c59 135 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
136 e->op = FcOpBool;
137 e->u.bval = b;
138 }
139 return e;
140}
141
142FcExpr *
143FcExprCreateNil (void)
144{
145 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
146
147 if (e)
148 {
9dac3c59 149 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
150 e->op = FcOpNil;
151 }
152 return e;
153}
154
155FcExpr *
156FcExprCreateField (const char *field)
157{
158 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
159
160 if (e)
161 {
9dac3c59 162 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27 163 e->op = FcOpField;
7ce19673 164 e->u.object = FcObjectFromName (field);
24330d27
KP
165 }
166 return e;
167}
168
169FcExpr *
ccb3e93b 170FcExprCreateConst (const FcChar8 *constant)
24330d27
KP
171{
172 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174 if (e)
175 {
9dac3c59 176 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
177 e->op = FcOpConst;
178 e->u.constant = FcStrCopy (constant);
179 }
180 return e;
181}
182
183FcExpr *
184FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
185{
186 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
187
188 if (e)
189 {
9dac3c59 190 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
191 e->op = op;
192 e->u.tree.left = left;
193 e->u.tree.right = right;
194 }
195 return e;
196}
197
198void
199FcExprDestroy (FcExpr *e)
200{
3f7653c2
KP
201 if (!e)
202 return;
24330d27
KP
203 switch (e->op) {
204 case FcOpInteger:
205 break;
206 case FcOpDouble:
207 break;
208 case FcOpString:
209 FcStrFree (e->u.sval);
210 break;
211 case FcOpMatrix:
212 FcMatrixFree (e->u.mval);
213 break;
214 case FcOpCharSet:
215 FcCharSetDestroy (e->u.cval);
216 break;
217 case FcOpBool:
218 break;
219 case FcOpField:
24330d27
KP
220 break;
221 case FcOpConst:
222 FcStrFree (e->u.constant);
223 break;
224 case FcOpAssign:
225 case FcOpAssignReplace:
226 case FcOpPrepend:
227 case FcOpPrependFirst:
228 case FcOpAppend:
229 case FcOpAppendLast:
230 break;
231 case FcOpOr:
232 case FcOpAnd:
233 case FcOpEqual:
24330d27
KP
234 case FcOpNotEqual:
235 case FcOpLess:
236 case FcOpLessEqual:
237 case FcOpMore:
238 case FcOpMoreEqual:
47d4f950 239 case FcOpContains:
74a623e0 240 case FcOpListing:
47d4f950 241 case FcOpNotContains:
24330d27
KP
242 case FcOpPlus:
243 case FcOpMinus:
244 case FcOpTimes:
245 case FcOpDivide:
246 case FcOpQuest:
247 case FcOpComma:
248 FcExprDestroy (e->u.tree.right);
249 /* fall through */
250 case FcOpNot:
3f7653c2
KP
251 case FcOpFloor:
252 case FcOpCeil:
253 case FcOpRound:
254 case FcOpTrunc:
24330d27
KP
255 FcExprDestroy (e->u.tree.left);
256 break;
257 case FcOpNil:
258 case FcOpInvalid:
259 break;
260 }
9dac3c59 261 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
262 free (e);
263}
264
24330d27
KP
265void
266FcEditDestroy (FcEdit *e)
267{
268 if (e->next)
269 FcEditDestroy (e->next);
24330d27
KP
270 if (e->expr)
271 FcExprDestroy (e->expr);
34cd0514 272 free (e);
24330d27
KP
273}
274
275char *
276FcConfigSaveField (const char *field)
277{
ccb3e93b 278 return (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
279}
280
c2e7c611
KP
281typedef enum _FcElement {
282 FcElementNone,
283 FcElementFontconfig,
284 FcElementDir,
7410e40b 285 FcElementCacheDir,
c2e7c611
KP
286 FcElementCache,
287 FcElementInclude,
288 FcElementConfig,
289 FcElementMatch,
290 FcElementAlias,
291
292 FcElementBlank,
179c3995 293 FcElementRescan,
c2e7c611
KP
294
295 FcElementPrefer,
296 FcElementAccept,
297 FcElementDefault,
298 FcElementFamily,
299
d47c9d6e
KP
300 FcElementSelectfont,
301 FcElementAcceptfont,
302 FcElementRejectfont,
303 FcElementGlob,
4f27c1c0
KP
304 FcElementPattern,
305 FcElementPatelt,
d47c9d6e 306
c2e7c611
KP
307 FcElementTest,
308 FcElementEdit,
309 FcElementInt,
310 FcElementDouble,
311 FcElementString,
312 FcElementMatrix,
313 FcElementBool,
314 FcElementCharset,
315 FcElementName,
316 FcElementConst,
317 FcElementOr,
318 FcElementAnd,
319 FcElementEq,
320 FcElementNotEq,
321 FcElementLess,
322 FcElementLessEq,
323 FcElementMore,
324 FcElementMoreEq,
47d4f950
KP
325 FcElementContains,
326 FcElementNotContains,
c2e7c611
KP
327 FcElementPlus,
328 FcElementMinus,
329 FcElementTimes,
330 FcElementDivide,
331 FcElementNot,
332 FcElementIf,
3f7653c2
KP
333 FcElementFloor,
334 FcElementCeil,
335 FcElementRound,
336 FcElementTrunc,
c2e7c611
KP
337 FcElementUnknown
338} FcElement;
339
392fa276 340static const struct {
67accef4
PL
341 const char name[16];
342 FcElement element;
343} fcElementMap[] = {
344 { "fontconfig", FcElementFontconfig },
345 { "dir", FcElementDir },
7410e40b 346 { "cachedir", FcElementCacheDir },
67accef4
PL
347 { "cache", FcElementCache },
348 { "include", FcElementInclude },
349 { "config", FcElementConfig },
350 { "match", FcElementMatch },
351 { "alias", FcElementAlias },
352
353 { "blank", FcElementBlank },
354 { "rescan", FcElementRescan },
355
356 { "prefer", FcElementPrefer },
357 { "accept", FcElementAccept },
358 { "default", FcElementDefault },
359 { "family", FcElementFamily },
360
361 { "selectfont", FcElementSelectfont },
362 { "acceptfont", FcElementAcceptfont },
363 { "rejectfont", FcElementRejectfont },
364 { "glob", FcElementGlob },
365 { "pattern", FcElementPattern },
366 { "patelt", FcElementPatelt },
367
368 { "test", FcElementTest },
369 { "edit", FcElementEdit },
370 { "int", FcElementInt },
371 { "double", FcElementDouble },
372 { "string", FcElementString },
373 { "matrix", FcElementMatrix },
374 { "bool", FcElementBool },
375 { "charset", FcElementCharset },
376 { "name", FcElementName },
377 { "const", FcElementConst },
378 { "or", FcElementOr },
379 { "and", FcElementAnd },
380 { "eq", FcElementEq },
381 { "not_eq", FcElementNotEq },
382 { "less", FcElementLess },
383 { "less_eq", FcElementLessEq },
384 { "more", FcElementMore },
385 { "more_eq", FcElementMoreEq },
386 { "contains", FcElementContains },
387 { "not_contains", FcElementNotContains },
388 { "plus", FcElementPlus },
389 { "minus", FcElementMinus },
390 { "times", FcElementTimes },
391 { "divide", FcElementDivide },
392 { "not", FcElementNot },
393 { "if", FcElementIf },
394 { "floor", FcElementFloor },
395 { "ceil", FcElementCeil },
396 { "round", FcElementRound },
397 { "trunc", FcElementTrunc },
398};
399#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
400
c2e7c611
KP
401static FcElement
402FcElementMap (const XML_Char *name)
403{
c2e7c611
KP
404
405 int i;
67accef4 406 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
c2e7c611
KP
407 if (!strcmp ((char *) name, fcElementMap[i].name))
408 return fcElementMap[i].element;
409 return FcElementUnknown;
410}
411
412typedef struct _FcPStack {
413 struct _FcPStack *prev;
414 FcElement element;
415 FcChar8 **attr;
416 FcStrBuf str;
417} FcPStack;
418
419typedef enum _FcVStackTag {
420 FcVStackNone,
421
422 FcVStackString,
423 FcVStackFamily,
424 FcVStackField,
425 FcVStackConstant,
d47c9d6e 426 FcVStackGlob,
4f27c1c0 427 FcVStackPattern,
c2e7c611
KP
428
429 FcVStackPrefer,
430 FcVStackAccept,
431 FcVStackDefault,
432
433 FcVStackInteger,
434 FcVStackDouble,
435 FcVStackMatrix,
436 FcVStackBool,
437
438 FcVStackTest,
439 FcVStackExpr,
440 FcVStackEdit
441} FcVStackTag;
442
443typedef struct _FcVStack {
444 struct _FcVStack *prev;
445 FcPStack *pstack; /* related parse element */
446 FcVStackTag tag;
447 union {
448 FcChar8 *string;
449
450 int integer;
451 double _double;
452 FcMatrix *matrix;
453 FcBool bool;
454
455 FcTest *test;
456 FcQual qual;
457 FcOp op;
458 FcExpr *expr;
459 FcEdit *edit;
4f27c1c0
KP
460
461 FcPattern *pattern;
c2e7c611
KP
462 } u;
463} FcVStack;
464
465typedef struct _FcConfigParse {
466 FcPStack *pstack;
467 FcVStack *vstack;
468 FcBool error;
469 const FcChar8 *name;
470 FcConfig *config;
471 XML_Parser parser;
472} FcConfigParse;
473
179c3995
KP
474typedef enum _FcConfigSeverity {
475 FcSevereInfo, FcSevereWarning, FcSevereError
476} FcConfigSeverity;
477
24330d27 478static void
67accef4 479FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
24330d27 480{
67accef4 481 const char *s = "unknown";
24330d27
KP
482 va_list args;
483
484 va_start (args, fmt);
179c3995
KP
485
486 switch (severe) {
487 case FcSevereInfo: s = "info"; break;
488 case FcSevereWarning: s = "warning"; break;
489 case FcSevereError: s = "error"; break;
490 }
c2e7c611
KP
491 if (parse)
492 {
493 if (parse->name)
179c3995 494 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
68355f38 495 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
c2e7c611 496 else
179c3995 497 fprintf (stderr, "Fontconfig %s: line %d: ", s,
68355f38 498 (int)XML_GetCurrentLineNumber (parse->parser));
179c3995
KP
499 if (severe >= FcSevereError)
500 parse->error = FcTrue;
c2e7c611
KP
501 }
502 else
179c3995 503 fprintf (stderr, "Fontconfig %s: ", s);
24330d27
KP
504 vfprintf (stderr, fmt, args);
505 fprintf (stderr, "\n");
506 va_end (args);
507}
508
ca60d2b5 509
67accef4 510static const char *
ca60d2b5
KP
511FcTypeName (FcType type)
512{
513 switch (type) {
514 case FcTypeVoid:
515 return "void";
516 case FcTypeInteger:
517 case FcTypeDouble:
518 return "number";
519 case FcTypeString:
520 return "string";
521 case FcTypeBool:
522 return "bool";
523 case FcTypeMatrix:
524 return "matrix";
525 case FcTypeCharSet:
526 return "charset";
527 case FcTypeFTFace:
528 return "FT_Face";
529 case FcTypeLangSet:
530 return "langset";
531 default:
532 return "unknown";
533 }
534}
535
536static void
537FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
538{
539 if (value == FcTypeInteger)
540 value = FcTypeDouble;
541 if (type == FcTypeInteger)
542 type = FcTypeDouble;
543 if (value != type)
544 {
545 if ((value == FcTypeLangSet && type == FcTypeString) ||
546 (value == FcTypeString && type == FcTypeLangSet))
547 return;
9a9fd975
KP
548 if (type == (FcType) -1)
549 return;
ca60d2b5
KP
550 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
551 FcTypeName (value), FcTypeName (type));
552 }
553}
554
555static void
556FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
557{
558 const FcObjectType *o;
559 const FcConstant *c;
560
561 switch (expr->op) {
562 case FcOpInteger:
563 case FcOpDouble:
564 FcTypecheckValue (parse, FcTypeDouble, type);
565 break;
566 case FcOpString:
567 FcTypecheckValue (parse, FcTypeString, type);
568 break;
569 case FcOpMatrix:
570 FcTypecheckValue (parse, FcTypeMatrix, type);
571 break;
572 case FcOpBool:
573 FcTypecheckValue (parse, FcTypeBool, type);
574 break;
575 case FcOpCharSet:
576 FcTypecheckValue (parse, FcTypeCharSet, type);
577 break;
578 case FcOpNil:
579 break;
580 case FcOpField:
7ce19673 581 o = FcNameGetObjectType (FcObjectName (expr->u.object));
ca60d2b5
KP
582 if (o)
583 FcTypecheckValue (parse, o->type, type);
584 break;
585 case FcOpConst:
586 c = FcNameGetConstant (expr->u.constant);
587 if (c)
588 {
589 o = FcNameGetObjectType (c->object);
590 if (o)
591 FcTypecheckValue (parse, o->type, type);
592 }
f28472fd
PL
593 else
594 FcConfigMessage (parse, FcSevereWarning,
595 "invalid constant used : %s",
596 expr->u.constant);
ca60d2b5
KP
597 break;
598 case FcOpQuest:
599 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
600 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
601 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
602 break;
603 case FcOpAssign:
604 case FcOpAssignReplace:
605 break;
606 case FcOpEqual:
607 case FcOpNotEqual:
608 case FcOpLess:
609 case FcOpLessEqual:
610 case FcOpMore:
611 case FcOpMoreEqual:
612 case FcOpContains:
613 case FcOpNotContains:
614 case FcOpListing:
615 FcTypecheckValue (parse, FcTypeBool, type);
616 break;
617 case FcOpComma:
618 case FcOpOr:
619 case FcOpAnd:
620 case FcOpPlus:
621 case FcOpMinus:
622 case FcOpTimes:
623 case FcOpDivide:
624 FcTypecheckExpr (parse, expr->u.tree.left, type);
625 FcTypecheckExpr (parse, expr->u.tree.right, type);
626 break;
627 case FcOpNot:
628 FcTypecheckValue (parse, FcTypeBool, type);
629 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
630 break;
631 case FcOpFloor:
632 case FcOpCeil:
633 case FcOpRound:
634 case FcOpTrunc:
635 FcTypecheckValue (parse, FcTypeDouble, type);
636 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
637 break;
638 default:
639 break;
640 }
641}
642
643static FcTest *
644FcTestCreate (FcConfigParse *parse,
645 FcMatchKind kind,
646 FcQual qual,
647 const FcChar8 *field,
648 FcOp compare,
649 FcExpr *expr)
650{
651 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
652
653 if (test)
654 {
655 const FcObjectType *o;
656
657 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
658 test->next = 0;
659 test->kind = kind;
660 test->qual = qual;
7ce19673 661 test->object = FcObjectFromName ((const char *) field);
ca60d2b5
KP
662 test->op = compare;
663 test->expr = expr;
7ce19673 664 o = FcNameGetObjectType (FcObjectName (test->object));
ca60d2b5
KP
665 if (o)
666 FcTypecheckExpr (parse, expr, o->type);
667 }
668 return test;
669}
670
671static FcEdit *
672FcEditCreate (FcConfigParse *parse,
2d3387fd 673 FcObject object,
ca60d2b5
KP
674 FcOp op,
675 FcExpr *expr,
676 FcValueBinding binding)
677{
678 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
679
680 if (e)
681 {
682 const FcObjectType *o;
683
684 e->next = 0;
2d3387fd 685 e->object = object;
ca60d2b5
KP
686 e->op = op;
687 e->expr = expr;
688 e->binding = binding;
7ce19673 689 o = FcNameGetObjectType (FcObjectName (e->object));
ca60d2b5
KP
690 if (o)
691 FcTypecheckExpr (parse, expr, o->type);
692 }
693 return e;
694}
695
c2e7c611
KP
696static void
697FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
24330d27 698{
c2e7c611
KP
699 vstack->prev = parse->vstack;
700 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
701 parse->vstack = vstack;
24330d27
KP
702}
703
c2e7c611
KP
704static FcVStack *
705FcVStackCreate (void)
24330d27 706{
c2e7c611 707 FcVStack *new;
24330d27 708
c2e7c611
KP
709 new = malloc (sizeof (FcVStack));
710 if (!new)
711 return 0;
9dac3c59 712 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
713 new->tag = FcVStackNone;
714 new->prev = 0;
715 return new;
716}
24330d27 717
c2e7c611
KP
718static void
719FcVStackDestroy (FcVStack *vstack)
24330d27 720{
c2e7c611 721 FcVStack *prev;
24330d27 722
c2e7c611
KP
723 for (; vstack; vstack = prev)
724 {
725 prev = vstack->prev;
726 switch (vstack->tag) {
727 case FcVStackNone:
728 break;
729 case FcVStackString:
730 case FcVStackFamily:
731 case FcVStackField:
732 case FcVStackConstant:
d47c9d6e 733 case FcVStackGlob:
c2e7c611
KP
734 FcStrFree (vstack->u.string);
735 break;
4f27c1c0
KP
736 case FcVStackPattern:
737 FcPatternDestroy (vstack->u.pattern);
738 break;
c2e7c611
KP
739 case FcVStackInteger:
740 case FcVStackDouble:
741 break;
742 case FcVStackMatrix:
743 FcMatrixFree (vstack->u.matrix);
744 break;
745 case FcVStackBool:
746 break;
747 case FcVStackTest:
748 FcTestDestroy (vstack->u.test);
749 break;
750 case FcVStackExpr:
751 case FcVStackPrefer:
752 case FcVStackAccept:
753 case FcVStackDefault:
754 FcExprDestroy (vstack->u.expr);
755 break;
756 case FcVStackEdit:
757 FcEditDestroy (vstack->u.edit);
758 break;
759 }
9dac3c59 760 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
761 free (vstack);
762 }
24330d27
KP
763}
764
765static FcBool
c2e7c611 766FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 767{
c2e7c611
KP
768 FcVStack *vstack = FcVStackCreate ();
769 if (!vstack)
770 return FcFalse;
771 vstack->u.string = string;
772 vstack->tag = tag;
773 FcVStackPush (parse, vstack);
774 return FcTrue;
24330d27
KP
775}
776
777static FcBool
c2e7c611 778FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 779{
c2e7c611
KP
780 FcVStack *vstack = FcVStackCreate ();
781 if (!vstack)
24330d27 782 return FcFalse;
c2e7c611
KP
783 vstack->u.integer = integer;
784 vstack->tag = FcVStackInteger;
785 FcVStackPush (parse, vstack);
786 return FcTrue;
24330d27
KP
787}
788
789static FcBool
c2e7c611 790FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 791{
c2e7c611
KP
792 FcVStack *vstack = FcVStackCreate ();
793 if (!vstack)
24330d27 794 return FcFalse;
c2e7c611
KP
795 vstack->u._double = _double;
796 vstack->tag = FcVStackDouble;
797 FcVStackPush (parse, vstack);
798 return FcTrue;
24330d27
KP
799}
800
801static FcBool
c2e7c611 802FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 803{
c2e7c611
KP
804 FcVStack *vstack = FcVStackCreate ();
805 if (!vstack)
24330d27 806 return FcFalse;
c2e7c611
KP
807 matrix = FcMatrixCopy (matrix);
808 if (!matrix)
24330d27 809 {
c2e7c611
KP
810 FcVStackDestroy (vstack);
811 return FcFalse;
24330d27 812 }
c2e7c611
KP
813 vstack->u.matrix = matrix;
814 vstack->tag = FcVStackMatrix;
815 FcVStackPush (parse, vstack);
816 return FcTrue;
24330d27
KP
817}
818
819static FcBool
c2e7c611 820FcVStackPushBool (FcConfigParse *parse, FcBool bool)
24330d27 821{
c2e7c611
KP
822 FcVStack *vstack = FcVStackCreate ();
823 if (!vstack)
824 return FcFalse;
825 vstack->u.bool = bool;
826 vstack->tag = FcVStackBool;
827 FcVStackPush (parse, vstack);
828 return FcTrue;
829}
24330d27 830
c2e7c611
KP
831static FcBool
832FcVStackPushTest (FcConfigParse *parse, FcTest *test)
833{
834 FcVStack *vstack = FcVStackCreate ();
835 if (!vstack)
24330d27 836 return FcFalse;
c2e7c611
KP
837 vstack->u.test = test;
838 vstack->tag = FcVStackTest;
839 FcVStackPush (parse, vstack);
24330d27
KP
840 return FcTrue;
841}
842
843static FcBool
c2e7c611 844FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 845{
c2e7c611
KP
846 FcVStack *vstack = FcVStackCreate ();
847 if (!vstack)
848 return FcFalse;
849 vstack->u.expr = expr;
850 vstack->tag = tag;
851 FcVStackPush (parse, vstack);
852 return FcTrue;
853}
24330d27 854
c2e7c611
KP
855static FcBool
856FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
857{
858 FcVStack *vstack = FcVStackCreate ();
859 if (!vstack)
24330d27 860 return FcFalse;
c2e7c611
KP
861 vstack->u.edit = edit;
862 vstack->tag = FcVStackEdit;
863 FcVStackPush (parse, vstack);
24330d27
KP
864 return FcTrue;
865}
866
4f27c1c0
KP
867static FcBool
868FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
869{
870 FcVStack *vstack = FcVStackCreate ();
871 if (!vstack)
872 return FcFalse;
873 vstack->u.pattern = pattern;
874 vstack->tag = FcVStackPattern;
875 FcVStackPush (parse, vstack);
876 return FcTrue;
877}
878
c2e7c611
KP
879static FcVStack *
880FcVStackFetch (FcConfigParse *parse, int off)
24330d27 881{
c2e7c611 882 FcVStack *vstack;
24330d27 883
c2e7c611
KP
884 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
885 return vstack;
886}
887
888static void
889FcVStackClear (FcConfigParse *parse)
890{
891 while (parse->vstack && parse->vstack->pstack == parse->pstack)
24330d27 892 {
c2e7c611
KP
893 FcVStack *vstack = parse->vstack;
894 parse->vstack = vstack->prev;
895 vstack->prev = 0;
896 FcVStackDestroy (vstack);
24330d27 897 }
24330d27
KP
898}
899
c2e7c611
KP
900static FcVStack *
901FcVStackPop (FcConfigParse *parse)
24330d27 902{
c2e7c611 903 FcVStack *vstack = parse->vstack;
24330d27 904
c2e7c611 905 if (!vstack || vstack->pstack != parse->pstack)
24330d27 906 return 0;
c2e7c611
KP
907 parse->vstack = vstack->prev;
908 vstack->prev = 0;
909 return vstack;
910}
911
912static int
913FcVStackElements (FcConfigParse *parse)
914{
915 int h = 0;
916 FcVStack *vstack = parse->vstack;
917 while (vstack && vstack->pstack == parse->pstack)
918 {
919 h++;
920 vstack = vstack->prev;
24330d27 921 }
c2e7c611 922 return h;
24330d27
KP
923}
924
c2e7c611
KP
925static FcChar8 **
926FcConfigSaveAttr (const XML_Char **attr)
24330d27 927{
c2e7c611
KP
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 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");
f2fb985c 1324 FcExprDestroy (expr);
c2e7c611
KP
1325 }
1326 }
1327}
1328
1329static void
1330FcParseFamily (FcConfigParse *parse)
1331{
1332 FcChar8 *s;
1333 FcExpr *expr;
1334
1335 if (!parse->pstack)
1336 return;
1337 s = FcStrBufDone (&parse->pstack->str);
1338 if (!s)
1339 {
179c3995 1340 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1341 return;
1342 }
1343 expr = FcExprCreateString (s);
1344 FcStrFree (s);
1345 if (expr)
1346 FcVStackPushExpr (parse, FcVStackFamily, expr);
1347}
1348
1349static void
1350FcParseAlias (FcConfigParse *parse)
1351{
179c3995 1352 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1353 FcEdit *edit = 0, *next;
c2e7c611 1354 FcVStack *vstack;
24330d27
KP
1355 FcTest *test;
1356
c2e7c611 1357 while ((vstack = FcVStackPop (parse)))
24330d27 1358 {
c2e7c611
KP
1359 switch (vstack->tag) {
1360 case FcVStackFamily:
1361 if (family)
179c3995
KP
1362 {
1363 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1364 if (!new)
1365 FcConfigMessage (parse, FcSevereError, "out of memory");
1366 else
1367 family = new;
1368 }
1369 else
1370 new = vstack->u.expr;
1371 if (new)
1372 {
1373 family = new;
1374 vstack->tag = FcVStackNone;
1375 }
c2e7c611
KP
1376 break;
1377 case FcVStackPrefer:
1378 if (prefer)
1379 FcExprDestroy (prefer);
1380 prefer = vstack->u.expr;
1381 vstack->tag = FcVStackNone;
1382 break;
1383 case FcVStackAccept:
1384 if (accept)
1385 FcExprDestroy (accept);
1386 accept = vstack->u.expr;
1387 vstack->tag = FcVStackNone;
1388 break;
1389 case FcVStackDefault:
1390 if (def)
1391 FcExprDestroy (def);
1392 def = vstack->u.expr;
1393 vstack->tag = FcVStackNone;
1394 break;
1395 default:
179c3995 1396 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1397 break;
1398 }
1399 FcVStackDestroy (vstack);
24330d27 1400 }
ccb3e93b 1401 if (!family)
c2e7c611 1402 {
179c3995
KP
1403 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1404 if (prefer)
1405 FcExprDestroy (prefer);
1406 if (accept)
1407 FcExprDestroy (accept);
1408 if (def)
1409 FcExprDestroy (def);
c2e7c611
KP
1410 return;
1411 }
24330d27
KP
1412 if (prefer)
1413 {
ca60d2b5 1414 edit = FcEditCreate (parse,
2d3387fd 1415 FC_FAMILY_OBJECT,
24330d27 1416 FcOpPrepend,
6fff2cda
KP
1417 prefer,
1418 FcValueBindingWeak);
24330d27
KP
1419 if (edit)
1420 edit->next = 0;
c2e7c611
KP
1421 else
1422 FcExprDestroy (prefer);
24330d27
KP
1423 }
1424 if (accept)
1425 {
1426 next = edit;
ca60d2b5 1427 edit = FcEditCreate (parse,
2d3387fd 1428 FC_FAMILY_OBJECT,
24330d27 1429 FcOpAppend,
6fff2cda
KP
1430 accept,
1431 FcValueBindingWeak);
24330d27
KP
1432 if (edit)
1433 edit->next = next;
c2e7c611
KP
1434 else
1435 FcExprDestroy (accept);
24330d27
KP
1436 }
1437 if (def)
1438 {
1439 next = edit;
ca60d2b5 1440 edit = FcEditCreate (parse,
2d3387fd 1441 FC_FAMILY_OBJECT,
6fff2cda
KP
1442 FcOpAppendLast,
1443 def,
1444 FcValueBindingWeak);
24330d27
KP
1445 if (edit)
1446 edit->next = next;
c2e7c611
KP
1447 else
1448 FcExprDestroy (def);
24330d27
KP
1449 }
1450 if (edit)
1451 {
ca60d2b5 1452 test = FcTestCreate (parse, FcMatchPattern,
938bc633 1453 FcQualAny,
2623c1eb 1454 (FcChar8 *) FC_FAMILY,
24330d27
KP
1455 FcOpEqual,
1456 family);
1457 if (test)
c2e7c611
KP
1458 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1459 FcTestDestroy (test);
24330d27 1460 }
c2e7c611
KP
1461 else
1462 FcExprDestroy (family);
24330d27
KP
1463}
1464
c2e7c611
KP
1465static FcExpr *
1466FcPopExpr (FcConfigParse *parse)
24330d27 1467{
c2e7c611
KP
1468 FcVStack *vstack = FcVStackPop (parse);
1469 FcExpr *expr = 0;
1470 if (!vstack)
1471 return 0;
1472 switch (vstack->tag) {
1473 case FcVStackNone:
1474 break;
1475 case FcVStackString:
1476 case FcVStackFamily:
bbbaac36
KP
1477 expr = FcExprCreateString (vstack->u.string);
1478 break;
c2e7c611 1479 case FcVStackField:
bbbaac36
KP
1480 expr = FcExprCreateField ((char *) vstack->u.string);
1481 break;
c2e7c611 1482 case FcVStackConstant:
bbbaac36 1483 expr = FcExprCreateConst (vstack->u.string);
c2e7c611 1484 break;
34cd0514
CW
1485 case FcVStackGlob:
1486 /* XXX: What's the correct action here? (CDW) */
1487 break;
c2e7c611
KP
1488 case FcVStackPrefer:
1489 case FcVStackAccept:
1490 case FcVStackDefault:
1491 expr = vstack->u.expr;
1492 vstack->tag = FcVStackNone;
1493 break;
1494 case FcVStackInteger:
1495 expr = FcExprCreateInteger (vstack->u.integer);
1496 break;
1497 case FcVStackDouble:
1498 expr = FcExprCreateDouble (vstack->u._double);
1499 break;
1500 case FcVStackMatrix:
1501 expr = FcExprCreateMatrix (vstack->u.matrix);
1502 break;
1503 case FcVStackBool:
1504 expr = FcExprCreateBool (vstack->u.bool);
1505 break;
1506 case FcVStackTest:
1507 break;
1508 case FcVStackExpr:
1509 expr = vstack->u.expr;
8ec077f2 1510 vstack->tag = FcVStackNone;
c2e7c611
KP
1511 break;
1512 case FcVStackEdit:
1513 break;
4f27c1c0
KP
1514 default:
1515 break;
c2e7c611
KP
1516 }
1517 FcVStackDestroy (vstack);
1518 return expr;
1519}
1520
3f7653c2
KP
1521/*
1522 * This builds a tree of binary operations. Note
1523 * that every operator is defined so that if only
1524 * a single operand is contained, the value of the
1525 * whole expression is the value of the operand.
1526 *
1527 * This code reduces in that case to returning that
1528 * operand.
1529 */
c2e7c611 1530static FcExpr *
3f7653c2 1531FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1532{
1533 FcExpr *left, *expr = 0, *new;
24330d27 1534
c2e7c611 1535 while ((left = FcPopExpr (parse)))
24330d27 1536 {
c2e7c611 1537 if (expr)
24330d27 1538 {
c2e7c611
KP
1539 new = FcExprCreateOp (left, op, expr);
1540 if (!new)
1541 {
179c3995 1542 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1543 FcExprDestroy (left);
1544 FcExprDestroy (expr);
2de24638 1545 return 0;
c2e7c611
KP
1546 }
1547 expr = new;
24330d27 1548 }
c2e7c611
KP
1549 else
1550 expr = left;
1551 }
1552 return expr;
1553}
1554
1555static void
3f7653c2
KP
1556FcParseBinary (FcConfigParse *parse, FcOp op)
1557{
1558 FcExpr *expr = FcPopBinary (parse, op);
1559 if (expr)
1560 FcVStackPushExpr (parse, FcVStackExpr, expr);
1561}
1562
1563/*
1564 * This builds a a unary operator, it consumes only
1565 * a single operand
1566 */
1567
1568static FcExpr *
1569FcPopUnary (FcConfigParse *parse, FcOp op)
1570{
1571 FcExpr *operand, *new = 0;
1572
1573 if ((operand = FcPopExpr (parse)))
1574 {
1575 new = FcExprCreateOp (operand, op, 0);
1576 if (!new)
1577 {
1578 FcExprDestroy (operand);
1579 FcConfigMessage (parse, FcSevereError, "out of memory");
1580 }
1581 }
1582 return new;
1583}
1584
1585static void
1586FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1587{
3f7653c2 1588 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1589 if (expr)
1590 FcVStackPushExpr (parse, FcVStackExpr, expr);
1591}
1592
1593static void
1594FcParseInclude (FcConfigParse *parse)
1595{
1596 FcChar8 *s;
1597 const FcChar8 *i;
1598 FcBool ignore_missing = FcFalse;
1599
1600 s = FcStrBufDone (&parse->pstack->str);
1601 if (!s)
1602 {
179c3995 1603 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1604 return;
1605 }
1606 i = FcConfigGetAttribute (parse, "ignore_missing");
ca60d2b5 1607 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
c2e7c611 1608 ignore_missing = FcTrue;
24c90386 1609 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1610 parse->error = FcTrue;
9dac3c59 1611 FcStrFree (s);
c2e7c611
KP
1612}
1613
1614typedef struct _FcOpMap {
67accef4 1615 char name[16];
c2e7c611
KP
1616 FcOp op;
1617} FcOpMap;
1618
1619static FcOp
1620FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1621{
1622 int i;
1623
1624 for (i = 0; i < nmap; i++)
1625 if (!strcmp ((char *) op, map[i].name))
1626 return map[i].op;
1627 return FcOpInvalid;
1628}
1629
1630static const FcOpMap fcCompareOps[] = {
1631 { "eq", FcOpEqual },
1632 { "not_eq", FcOpNotEqual },
1633 { "less", FcOpLess },
1634 { "less_eq", FcOpLessEqual },
1635 { "more", FcOpMore },
47d4f950
KP
1636 { "more_eq", FcOpMoreEqual },
1637 { "contains", FcOpContains },
1638 { "not_contains", FcOpNotContains }
c2e7c611
KP
1639};
1640
67accef4 1641#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
c2e7c611
KP
1642
1643static FcOp
1644FcConfigLexCompare (const FcChar8 *compare)
1645{
1646 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1647}
1648
1649
1650static void
1651FcParseTest (FcConfigParse *parse)
1652{
938bc633
KP
1653 const FcChar8 *kind_string;
1654 FcMatchKind kind;
c2e7c611
KP
1655 const FcChar8 *qual_string;
1656 FcQual qual;
1657 const FcChar8 *name;
1658 const FcChar8 *compare_string;
1659 FcOp compare;
1660 FcExpr *expr;
1661 FcTest *test;
1662
938bc633
KP
1663 kind_string = FcConfigGetAttribute (parse, "target");
1664 if (!kind_string)
1665 kind = FcMatchDefault;
1666 else
1667 {
1668 if (!strcmp ((char *) kind_string, "pattern"))
1669 kind = FcMatchPattern;
1670 else if (!strcmp ((char *) kind_string, "font"))
1671 kind = FcMatchFont;
c2c6976d
KP
1672 else if (!strcmp ((char *) kind_string, "scan"))
1673 kind = FcMatchScan;
938bc633
KP
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);
2d3387fd
KP
1798 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1799 mode, expr, binding);
c2e7c611
KP
1800 if (!edit)
1801 {
179c3995 1802 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1803 FcExprDestroy (expr);
1804 return;
1805 }
1806 if (!FcVStackPushEdit (parse, edit))
1807 FcEditDestroy (edit);
1808}
1809
1810static void
1811FcParseMatch (FcConfigParse *parse)
1812{
1813 const FcChar8 *kind_name;
1814 FcMatchKind kind;
1815 FcTest *test = 0;
1816 FcEdit *edit = 0;
1817 FcVStack *vstack;
1818
1819 kind_name = FcConfigGetAttribute (parse, "target");
1820 if (!kind_name)
1821 kind = FcMatchPattern;
1822 else
1823 {
1824 if (!strcmp ((char *) kind_name, "pattern"))
1825 kind = FcMatchPattern;
1826 else if (!strcmp ((char *) kind_name, "font"))
1827 kind = FcMatchFont;
c2c6976d
KP
1828 else if (!strcmp ((char *) kind_name, "scan"))
1829 kind = FcMatchScan;
c2e7c611 1830 else
24330d27 1831 {
179c3995 1832 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1833 return;
24330d27 1834 }
c2e7c611
KP
1835 }
1836 while ((vstack = FcVStackPop (parse)))
1837 {
1838 switch (vstack->tag) {
1839 case FcVStackTest:
1840 vstack->u.test->next = test;
1841 test = vstack->u.test;
1842 vstack->tag = FcVStackNone;
1843 break;
1844 case FcVStackEdit:
1845 vstack->u.edit->next = edit;
1846 edit = vstack->u.edit;
1847 vstack->tag = FcVStackNone;
1848 break;
1849 default:
179c3995 1850 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1851 break;
1852 }
1853 FcVStackDestroy (vstack);
1854 }
1855 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1856 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1857}
1858
d47c9d6e
KP
1859static void
1860FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1861{
1862 FcVStack *vstack;
1863
1864 while ((vstack = FcVStackPop (parse)))
1865 {
1866 switch (vstack->tag) {
1867 case FcVStackGlob:
1868 if (!FcConfigGlobAdd (parse->config,
1869 vstack->u.string,
1870 element == FcElementAcceptfont))
1871 {
1872 FcConfigMessage (parse, FcSevereError, "out of memory");
1873 }
1874 break;
4f27c1c0
KP
1875 case FcVStackPattern:
1876 if (!FcConfigPatternsAdd (parse->config,
1877 vstack->u.pattern,
1878 element == FcElementAcceptfont))
1879 {
1880 FcConfigMessage (parse, FcSevereError, "out of memory");
1881 }
1882 else
1883 vstack->tag = FcVStackNone;
1884 break;
d47c9d6e
KP
1885 default:
1886 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1887 break;
1888 }
1889 FcVStackDestroy (vstack);
1890 }
1891}
1892
4f27c1c0
KP
1893
1894static FcValue
1895FcPopValue (FcConfigParse *parse)
1896{
1897 FcVStack *vstack = FcVStackPop (parse);
1898 FcValue value;
1899
1900 value.type = FcTypeVoid;
1901
1902 if (!vstack)
1903 return value;
1904
1905 switch (vstack->tag) {
1906 case FcVStackString:
4262e0b3
PL
1907 value.u.s = FcStrCopy (vstack->u.string);
1908 if (value.u.s)
4f27c1c0
KP
1909 value.type = FcTypeString;
1910 break;
1911 case FcVStackConstant:
1912 if (FcNameConstant (vstack->u.string, &value.u.i))
1913 value.type = FcTypeInteger;
1914 break;
1915 case FcVStackInteger:
1916 value.u.i = vstack->u.integer;
1917 value.type = FcTypeInteger;
1918 break;
1919 case FcVStackDouble:
1920 value.u.d = vstack->u._double;
1921 value.type = FcTypeInteger;
1922 break;
1923 case FcVStackMatrix:
4262e0b3
PL
1924 value.u.m = FcMatrixCopy (vstack->u.matrix);
1925 if (value.u.m)
4f27c1c0
KP
1926 value.type = FcTypeMatrix;
1927 break;
1928 case FcVStackBool:
1929 value.u.b = vstack->u.bool;
1930 value.type = FcTypeBool;
1931 break;
1932 default:
1933 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1934 vstack->tag);
1935 break;
1936 }
1937 FcVStackDestroy (vstack);
1938
1939 return value;
1940}
1941
1942static void
1943FcParsePatelt (FcConfigParse *parse)
1944{
1945 FcValue value;
1946 FcPattern *pattern = FcPatternCreate ();
1947 const char *name;
1948
1949 if (!pattern)
1950 {
1951 FcConfigMessage (parse, FcSevereError, "out of memory");
1952 return;
1953 }
1954
8245771d 1955 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
1956 if (!name)
1957 {
1958 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2de24638 1959 FcPatternDestroy (pattern);
4f27c1c0
KP
1960 return;
1961 }
4f27c1c0
KP
1962
1963 for (;;)
1964 {
1965 value = FcPopValue (parse);
1966 if (value.type == FcTypeVoid)
1967 break;
1968 if (!FcPatternAdd (pattern, name, value, FcTrue))
1969 {
1970 FcConfigMessage (parse, FcSevereError, "out of memory");
1971 break;
1972 }
1973 }
1974
529291be 1975 FcVStackPushPattern (parse, pattern);
4f27c1c0
KP
1976}
1977
1978static void
1979FcParsePattern (FcConfigParse *parse)
1980{
1981 FcVStack *vstack;
1982 FcPattern *pattern = FcPatternCreate ();
1983
1984 if (!pattern)
1985 {
1986 FcConfigMessage (parse, FcSevereError, "out of memory");
1987 return;
1988 }
1989
1990 while ((vstack = FcVStackPop (parse)))
1991 {
1992 switch (vstack->tag) {
1993 case FcVStackPattern:
1994 if (!FcPatternAppend (pattern, vstack->u.pattern))
1995 {
1996 FcConfigMessage (parse, FcSevereError, "out of memory");
2de24638 1997 FcPatternDestroy (pattern);
4f27c1c0
KP
1998 return;
1999 }
2000 break;
2001 default:
2002 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2003 break;
2004 }
2005 FcVStackDestroy (vstack);
2006 }
2007
2008 FcVStackPushPattern (parse, pattern);
2009}
2010
c2e7c611
KP
2011static void
2012FcEndElement(void *userData, const XML_Char *name)
2013{
2014 FcConfigParse *parse = userData;
2015 FcChar8 *data;
2016
2017 if (!parse->pstack)
2018 return;
2019 switch (parse->pstack->element) {
2020 case FcElementNone:
2021 break;
2022 case FcElementFontconfig:
2023 break;
2024 case FcElementDir:
2025 data = FcStrBufDone (&parse->pstack->str);
2026 if (!data)
24330d27 2027 {
179c3995 2028 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2029 break;
24330d27 2030 }
daeed6e0
TL
2031#ifdef _WIN32
2032 if (strcmp (data, "WINDOWSFONTDIR") == 0)
2033 {
2034 int rc;
2035 FcStrFree (data);
2036 data = malloc (1000);
2037 if (!data)
2038 {
2039 FcConfigMessage (parse, FcSevereError, "out of memory");
2040 break;
2041 }
2042 FcMemAlloc (FC_MEM_STRING, 1000);
2043 rc = GetWindowsDirectory (data, 800);
2044 if (rc == 0 || rc > 800)
2045 {
2046 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2047 FcStrFree (data);
2048 break;
2049 }
2050 if (data [strlen (data) - 1] != '\\')
2051 strcat (data, "\\");
2052 strcat (data, "fonts");
2053 }
2054#endif
ff3f1f98
KP
2055 if (!FcStrUsesHome (data) || FcConfigHome ())
2056 {
2057 if (!FcConfigAddDir (parse->config, data))
f468f568 2058 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
ff3f1f98 2059 }
9dac3c59 2060 FcStrFree (data);
c2e7c611 2061 break;
7410e40b
PL
2062 case FcElementCacheDir:
2063 data = FcStrBufDone (&parse->pstack->str);
2064 if (!data)
2065 {
2066 FcConfigMessage (parse, FcSevereError, "out of memory");
2067 break;
2068 }
2069 if (!FcStrUsesHome (data) || FcConfigHome ())
2070 {
2071 if (!FcConfigAddCacheDir (parse->config, data))
2072 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2073 }
2074 FcStrFree (data);
2075 break;
2076
c2e7c611
KP
2077 case FcElementCache:
2078 data = FcStrBufDone (&parse->pstack->str);
2079 if (!data)
24330d27 2080 {
179c3995 2081 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2082 break;
c2e7c611 2083 }
2d3387fd 2084 /* discard this data; no longer used */
9dac3c59 2085 FcStrFree (data);
c2e7c611
KP
2086 break;
2087 case FcElementInclude:
2088 FcParseInclude (parse);
2089 break;
2090 case FcElementConfig:
2091 break;
2092 case FcElementMatch:
2093 FcParseMatch (parse);
2094 break;
2095 case FcElementAlias:
2096 FcParseAlias (parse);
2097 break;
2098
2099 case FcElementBlank:
2100 FcParseBlank (parse);
2101 break;
179c3995
KP
2102 case FcElementRescan:
2103 FcParseRescan (parse);
2104 break;
c2e7c611
KP
2105
2106 case FcElementPrefer:
2107 FcParseFamilies (parse, FcVStackPrefer);
2108 break;
2109 case FcElementAccept:
2110 FcParseFamilies (parse, FcVStackAccept);
2111 break;
2112 case FcElementDefault:
2113 FcParseFamilies (parse, FcVStackDefault);
2114 break;
2115 case FcElementFamily:
2116 FcParseFamily (parse);
2117 break;
2118
2119 case FcElementTest:
2120 FcParseTest (parse);
2121 break;
2122 case FcElementEdit:
2123 FcParseEdit (parse);
2124 break;
2125
2126 case FcElementInt:
2127 FcParseInt (parse);
2128 break;
2129 case FcElementDouble:
2130 FcParseDouble (parse);
2131 break;
2132 case FcElementString:
2133 FcParseString (parse, FcVStackString);
2134 break;
2135 case FcElementMatrix:
2136 FcParseMatrix (parse);
2137 break;
2138 case FcElementBool:
2139 FcParseBool (parse);
2140 break;
2141 case FcElementCharset:
2142/* FcParseCharset (parse); */
2143 break;
d47c9d6e
KP
2144 case FcElementSelectfont:
2145 break;
2146 case FcElementAcceptfont:
2147 case FcElementRejectfont:
2148 FcParseAcceptRejectFont (parse, parse->pstack->element);
2149 break;
2150 case FcElementGlob:
2151 FcParseString (parse, FcVStackGlob);
2152 break;
4f27c1c0
KP
2153 case FcElementPattern:
2154 FcParsePattern (parse);
2155 break;
2156 case FcElementPatelt:
2157 FcParsePatelt (parse);
2158 break;
c2e7c611
KP
2159 case FcElementName:
2160 FcParseString (parse, FcVStackField);
2161 break;
2162 case FcElementConst:
2163 FcParseString (parse, FcVStackConstant);
2164 break;
2165 case FcElementOr:
3f7653c2 2166 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2167 break;
2168 case FcElementAnd:
3f7653c2 2169 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2170 break;
2171 case FcElementEq:
3f7653c2 2172 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2173 break;
2174 case FcElementNotEq:
3f7653c2 2175 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2176 break;
2177 case FcElementLess:
3f7653c2 2178 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2179 break;
2180 case FcElementLessEq:
3f7653c2 2181 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2182 break;
2183 case FcElementMore:
3f7653c2 2184 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2185 break;
2186 case FcElementMoreEq:
3f7653c2 2187 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2188 break;
47d4f950 2189 case FcElementContains:
3f7653c2 2190 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2191 break;
2192 case FcElementNotContains:
3f7653c2 2193 FcParseBinary (parse, FcOpNotContains);
47d4f950 2194 break;
c2e7c611 2195 case FcElementPlus:
3f7653c2 2196 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2197 break;
2198 case FcElementMinus:
3f7653c2 2199 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2200 break;
2201 case FcElementTimes:
3f7653c2 2202 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2203 break;
2204 case FcElementDivide:
3f7653c2 2205 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2206 break;
2207 case FcElementNot:
3f7653c2 2208 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2209 break;
2210 case FcElementIf:
3f7653c2
KP
2211 FcParseBinary (parse, FcOpQuest);
2212 break;
2213 case FcElementFloor:
2214 FcParseUnary (parse, FcOpFloor);
2215 break;
2216 case FcElementCeil:
2217 FcParseUnary (parse, FcOpCeil);
2218 break;
2219 case FcElementRound:
2220 FcParseUnary (parse, FcOpRound);
2221 break;
2222 case FcElementTrunc:
2223 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2224 break;
2225 case FcElementUnknown:
2226 break;
24330d27 2227 }
c2e7c611
KP
2228 (void) FcPStackPop (parse);
2229}
2230
2231static void
2232FcCharacterData (void *userData, const XML_Char *s, int len)
2233{
2234 FcConfigParse *parse = userData;
2235
2236 if (!parse->pstack)
2237 return;
2238 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2239 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2240}
2241
2242static void
2243FcStartDoctypeDecl (void *userData,
2244 const XML_Char *doctypeName,
2245 const XML_Char *sysid,
2246 const XML_Char *pubid,
2247 int has_internal_subset)
2248{
2249 FcConfigParse *parse = userData;
2250
2251 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2252 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2253}
2254
0d745819 2255#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2256
2257static void
2258FcInternalSubsetDecl (void *userData,
2259 const XML_Char *doctypeName,
2260 const XML_Char *sysid,
2261 const XML_Char *pubid)
2262{
2263 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2264}
2265
2266static void
2267FcExternalSubsetDecl (void *userData,
2268 const XML_Char *doctypeName,
2269 const XML_Char *sysid,
2270 const XML_Char *pubid)
2271{
2272 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2273}
2274
2275#else /* ENABLE_LIBXML2 */
2276
c2e7c611
KP
2277static void
2278FcEndDoctypeDecl (void *userData)
2279{
24330d27
KP
2280}
2281
e99f0f0a
PL
2282#endif /* ENABLE_LIBXML2 */
2283
2d9c79c0
KP
2284static FcBool
2285FcConfigParseAndLoadDir (FcConfig *config,
2286 const FcChar8 *name,
2287 const FcChar8 *dir,
2288 FcBool complain)
2289{
2290 DIR *d;
2291 struct dirent *e;
2292 FcBool ret = FcTrue;
2293 FcChar8 *file;
2294 FcChar8 *base;
2295 FcStrSet *files;
2296
2297 d = opendir ((char *) dir);
2298 if (!d)
2299 {
2300 if (complain)
2301 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2302 name);
2303 ret = FcFalse;
2304 goto bail0;
2305 }
2306 /* freed below */
2307 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2308 if (!file)
2309 {
2310 ret = FcFalse;
2311 goto bail1;
2312 }
2313
2314 strcpy ((char *) file, (char *) dir);
2315 strcat ((char *) file, "/");
2316 base = file + strlen ((char *) file);
2317
2318 files = FcStrSetCreate ();
2319 if (!files)
2320 {
2321 ret = FcFalse;
2322 goto bail2;
2323 }
2324
2325 if (FcDebug () & FC_DBG_CONFIG)
2326 printf ("\tScanning config dir %s\n", dir);
2327
2328 while (ret && (e = readdir (d)))
2329 {
8245771d
PL
2330 int d_len;
2331#define TAIL ".conf"
2332#define TAIL_LEN 5
2d9c79c0 2333 /*
8245771d 2334 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2335 */
2336 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2337 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2338 d_len > TAIL_LEN &&
2339 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2340 {
2341 strcpy ((char *) base, (char *) e->d_name);
2342 if (!FcStrSetAdd (files, file))
2343 {
2344 ret = FcFalse;
2345 goto bail3;
2346 }
2347 }
2348 }
2349 if (ret)
2350 {
2351 int i;
4262e0b3
PL
2352 qsort (files->strs, files->num, sizeof (FcChar8 *),
2353 (int (*)(const void *, const void *)) FcStrCmp);
2d9c79c0 2354 for (i = 0; ret && i < files->num; i++)
4262e0b3 2355 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2356 }
2357bail3:
2358 FcStrSetDestroy (files);
2359bail2:
2360 free (file);
2361bail1:
2362 closedir (d);
2363bail0:
2364 return ret || !complain;
2365}
2366
24330d27
KP
2367FcBool
2368FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2369 const FcChar8 *name,
24330d27
KP
2370 FcBool complain)
2371{
24330d27 2372
c2e7c611
KP
2373 XML_Parser p;
2374 FcChar8 *filename;
3bfae75d 2375 int fd;
c2e7c611 2376 int len;
c2e7c611
KP
2377 FcConfigParse parse;
2378 FcBool error = FcTrue;
2379
0d745819 2380#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2381 xmlSAXHandler sax;
2382 char buf[BUFSIZ];
2383#else
2384 void *buf;
2385#endif
2386
c2e7c611
KP
2387 filename = FcConfigFilename (name);
2388 if (!filename)
2389 goto bail0;
4aded3e0 2390
cb6d97eb
PL
2391 if (FcStrSetMember (config->configFiles, filename))
2392 {
2393 FcStrFree (filename);
2394 return FcTrue;
2395 }
2396
4aded3e0 2397 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2398 {
2399 FcStrFree (filename);
4aded3e0 2400 goto bail0;
9dac3c59 2401 }
4aded3e0 2402
2d9c79c0
KP
2403 if (FcFileIsDir (filename))
2404 {
2405 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2406 FcStrFree (filename);
2407 return ret;
2408 }
2409
2410 if (FcDebug () & FC_DBG_CONFIG)
2411 printf ("\tLoading config file %s\n", filename);
2412
3bfae75d
PL
2413 fd = open ((char *) filename, O_RDONLY);
2414 if (fd == -1) {
8f2a8078 2415 FcStrFree (filename);
c2e7c611 2416 goto bail0;
8f2a8078 2417 }
c2e7c611 2418
0d745819 2419#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2420 memset(&sax, 0, sizeof(sax));
2421
2422 sax.internalSubset = FcInternalSubsetDecl;
2423 sax.externalSubset = FcExternalSubsetDecl;
2424 sax.startElement = FcStartElement;
2425 sax.endElement = FcEndElement;
2426 sax.characters = FcCharacterData;
2427
8f2a8078 2428 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2429#else
c2e7c611 2430 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2431#endif
8f2a8078 2432 FcStrFree (filename);
e99f0f0a 2433
c2e7c611
KP
2434 if (!p)
2435 goto bail1;
2436
2437 if (!FcConfigInit (&parse, name, config, p))
2438 goto bail2;
2439
0d745819 2440#ifndef ENABLE_LIBXML2
e99f0f0a 2441
c2e7c611
KP
2442 XML_SetUserData (p, &parse);
2443
2444 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2445 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2446 XML_SetCharacterDataHandler (p, FcCharacterData);
2447
e99f0f0a
PL
2448#endif /* ENABLE_LIBXML2 */
2449
c2e7c611 2450 do {
0d745819 2451#ifndef ENABLE_LIBXML2
c2e7c611
KP
2452 buf = XML_GetBuffer (p, BUFSIZ);
2453 if (!buf)
80c053b7 2454 {
179c3995 2455 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2456 goto bail3;
80c053b7 2457 }
e99f0f0a 2458#endif
3bfae75d 2459 len = read (fd, buf, BUFSIZ);
c2e7c611 2460 if (len < 0)
80c053b7 2461 {
179c3995 2462 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2463 goto bail3;
80c053b7 2464 }
e99f0f0a 2465
0d745819 2466#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2467 if (xmlParseChunk (p, buf, len, len == 0))
2468#else
c2e7c611 2469 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2470#endif
80c053b7 2471 {
179c3995 2472 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2473 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2474 goto bail3;
80c053b7 2475 }
c2e7c611
KP
2476 } while (len != 0);
2477 error = parse.error;
2478bail3:
2479 FcConfigCleanup (&parse);
2480bail2:
2481 XML_ParserFree (p);
2482bail1:
3bfae75d
PL
2483 close (fd);
2484 fd = -1;
c2e7c611
KP
2485bail0:
2486 if (error && complain)
24330d27 2487 {
c2e7c611 2488 if (name)
179c3995 2489 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2490 else
179c3995 2491 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2492 return FcFalse;
2493 }
2494 return FcTrue;
2495}
23816bf9
KP
2496#define __fcxml__
2497#include "fcaliastail.h"
2498#undef __fcxml__