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