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