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