]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
[fcstr,fcxml] Don't copy FcStrBuf contents when we would free it soon
[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;
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;
3ed70071 1117 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 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);
3ed70071 1129 FcStrBufDestroy (&parse->pstack->str);
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;
3ed70071 1198 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 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 1209 FcVStackPushDouble (parse, d);
3ed70071 1210 FcStrBufDestroy (&parse->pstack->str);
c2e7c611 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
fe8e8a1d 1269FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
c2e7c611 1270{
ca60d2b5
KP
1271 FcBool result = FcFalse;
1272
fe8e8a1d 1273 if (!FcNameBool (bool_, &result))
ca60d2b5 1274 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
fe8e8a1d 1275 bool_);
ca60d2b5 1276 return result;
c2e7c611
KP
1277}
1278
1279static void
1280FcParseBool (FcConfigParse *parse)
1281{
1282 FcChar8 *s;
1283
1284 if (!parse->pstack)
1285 return;
3ed70071 1286 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
1287 if (!s)
1288 {
179c3995 1289 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1290 return;
1291 }
ca60d2b5 1292 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
3ed70071 1293 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
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;
3ed70071 1373 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
1374 if (!s)
1375 {
179c3995 1376 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1377 return;
1378 }
1379 expr = FcExprCreateString (s);
3ed70071 1380 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
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:
fe8e8a1d 1543 expr = FcExprCreateBool (vstack->u.bool_);
c2e7c611
KP
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
3ed70071 1639 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
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;
3ed70071 1650 FcStrBufDestroy (&parse->pstack->str);
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:
fe8e8a1d 1958 value.u.b = vstack->u.bool_;
4f27c1c0
KP
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");
799691c9 2000 FcValueDestroy(value);
4f27c1c0
KP
2001 break;
2002 }
799691c9 2003 FcValueDestroy(value);
4f27c1c0
KP
2004 }
2005
529291be 2006 FcVStackPushPattern (parse, pattern);
4f27c1c0
KP
2007}
2008
2009static void
2010FcParsePattern (FcConfigParse *parse)
2011{
2012 FcVStack *vstack;
2013 FcPattern *pattern = FcPatternCreate ();
2014
2015 if (!pattern)
2016 {
2017 FcConfigMessage (parse, FcSevereError, "out of memory");
2018 return;
2019 }
2020
2021 while ((vstack = FcVStackPop (parse)))
2022 {
2023 switch (vstack->tag) {
2024 case FcVStackPattern:
2025 if (!FcPatternAppend (pattern, vstack->u.pattern))
2026 {
2027 FcConfigMessage (parse, FcSevereError, "out of memory");
2de24638 2028 FcPatternDestroy (pattern);
4f27c1c0
KP
2029 return;
2030 }
2031 break;
2032 default:
2033 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2034 break;
2035 }
2036 FcVStackDestroy (vstack);
2037 }
2038
2039 FcVStackPushPattern (parse, pattern);
2040}
2041
c2e7c611
KP
2042static void
2043FcEndElement(void *userData, const XML_Char *name)
2044{
2045 FcConfigParse *parse = userData;
2046 FcChar8 *data;
2047
2048 if (!parse->pstack)
2049 return;
2050 switch (parse->pstack->element) {
2051 case FcElementNone:
2052 break;
2053 case FcElementFontconfig:
2054 break;
2055 case FcElementDir:
3ed70071 2056 data = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 2057 if (!data)
24330d27 2058 {
179c3995 2059 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2060 break;
24330d27 2061 }
daeed6e0 2062#ifdef _WIN32
6d65081e
DS
2063 if (strcmp (data, "CUSTOMFONTDIR") == 0)
2064 {
e04afe83 2065 char *p;
6d65081e
DS
2066 FcStrFree (data);
2067 data = malloc (1000);
2068 if (!data)
2069 {
2070 FcConfigMessage (parse, FcSevereError, "out of memory");
2071 break;
2072 }
2073 FcMemAlloc (FC_MEM_STRING, 1000);
2074 if(!GetModuleFileName(NULL, data, 1000))
2075 {
2076 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2077 FcStrFree (data);
2078 break;
2079 }
e04afe83 2080 p = strrchr (data, '\\');
6d65081e
DS
2081 if (p) *p = '\0';
2082 strcat (data, "\\fonts");
2083 }
1cdf7efb
BE
2084 else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2085 {
2086 char *p;
2087 FcStrFree (data);
2088 data = malloc (1000);
2089 if (!data)
2090 {
2091 FcConfigMessage (parse, FcSevereError, "out of memory");
2092 break;
2093 }
2094 FcMemAlloc (FC_MEM_STRING, 1000);
2095 if(!GetModuleFileName(NULL, data, 1000))
2096 {
2097 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2098 FcStrFree (data);
2099 break;
2100 }
2101 p = strrchr (data, '\\');
2102 if (p) *p = '\0';
2103 strcat (data, "\\..\\share\\fonts");
2104 }
6d65081e 2105 else if (strcmp (data, "WINDOWSFONTDIR") == 0)
daeed6e0
TL
2106 {
2107 int rc;
2108 FcStrFree (data);
2109 data = malloc (1000);
2110 if (!data)
2111 {
2112 FcConfigMessage (parse, FcSevereError, "out of memory");
2113 break;
2114 }
2115 FcMemAlloc (FC_MEM_STRING, 1000);
2116 rc = GetWindowsDirectory (data, 800);
2117 if (rc == 0 || rc > 800)
2118 {
2119 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2120 FcStrFree (data);
2121 break;
2122 }
2123 if (data [strlen (data) - 1] != '\\')
2124 strcat (data, "\\");
2125 strcat (data, "fonts");
2126 }
2127#endif
8ade2369
KP
2128 if (strlen ((char *) data) == 0)
2129 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2130 else if (!FcStrUsesHome (data) || FcConfigHome ())
ff3f1f98
KP
2131 {
2132 if (!FcConfigAddDir (parse->config, data))
f468f568 2133 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
ff3f1f98 2134 }
3ed70071 2135 FcStrBufDestroy (&parse->pstack->str);
c2e7c611 2136 break;
7410e40b
PL
2137 case FcElementCacheDir:
2138 data = FcStrBufDone (&parse->pstack->str);
2139 if (!data)
2140 {
2141 FcConfigMessage (parse, FcSevereError, "out of memory");
2142 break;
2143 }
8a3dc488
TL
2144#ifdef _WIN32
2145 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2146 {
2147 int rc;
2148 FcStrFree (data);
2149 data = malloc (1000);
2150 if (!data)
2151 {
2152 FcConfigMessage (parse, FcSevereError, "out of memory");
2153 break;
2154 }
2155 FcMemAlloc (FC_MEM_STRING, 1000);
2156 rc = GetTempPath (800, data);
2157 if (rc == 0 || rc > 800)
2158 {
2159 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2160 FcStrFree (data);
2161 break;
2162 }
2163 if (data [strlen (data) - 1] != '\\')
2164 strcat (data, "\\");
2165 strcat (data, "fontconfig\\cache");
2166 }
2167#endif
7410e40b
PL
2168 if (!FcStrUsesHome (data) || FcConfigHome ())
2169 {
2170 if (!FcConfigAddCacheDir (parse->config, data))
2171 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2172 }
2173 FcStrFree (data);
2174 break;
2175
c2e7c611 2176 case FcElementCache:
3ed70071 2177 data = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 2178 if (!data)
24330d27 2179 {
179c3995 2180 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2181 break;
c2e7c611 2182 }
2d3387fd 2183 /* discard this data; no longer used */
3ed70071 2184 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
2185 break;
2186 case FcElementInclude:
2187 FcParseInclude (parse);
2188 break;
2189 case FcElementConfig:
2190 break;
2191 case FcElementMatch:
2192 FcParseMatch (parse);
2193 break;
2194 case FcElementAlias:
2195 FcParseAlias (parse);
2196 break;
2197
2198 case FcElementBlank:
2199 FcParseBlank (parse);
2200 break;
179c3995
KP
2201 case FcElementRescan:
2202 FcParseRescan (parse);
2203 break;
c2e7c611
KP
2204
2205 case FcElementPrefer:
2206 FcParseFamilies (parse, FcVStackPrefer);
2207 break;
2208 case FcElementAccept:
2209 FcParseFamilies (parse, FcVStackAccept);
2210 break;
2211 case FcElementDefault:
2212 FcParseFamilies (parse, FcVStackDefault);
2213 break;
2214 case FcElementFamily:
2215 FcParseFamily (parse);
2216 break;
2217
2218 case FcElementTest:
2219 FcParseTest (parse);
2220 break;
2221 case FcElementEdit:
2222 FcParseEdit (parse);
2223 break;
2224
2225 case FcElementInt:
2226 FcParseInt (parse);
2227 break;
2228 case FcElementDouble:
2229 FcParseDouble (parse);
2230 break;
2231 case FcElementString:
2232 FcParseString (parse, FcVStackString);
2233 break;
2234 case FcElementMatrix:
2235 FcParseMatrix (parse);
2236 break;
2237 case FcElementBool:
2238 FcParseBool (parse);
2239 break;
2240 case FcElementCharset:
2241/* FcParseCharset (parse); */
2242 break;
d47c9d6e
KP
2243 case FcElementSelectfont:
2244 break;
2245 case FcElementAcceptfont:
2246 case FcElementRejectfont:
2247 FcParseAcceptRejectFont (parse, parse->pstack->element);
2248 break;
2249 case FcElementGlob:
2250 FcParseString (parse, FcVStackGlob);
2251 break;
4f27c1c0
KP
2252 case FcElementPattern:
2253 FcParsePattern (parse);
2254 break;
2255 case FcElementPatelt:
2256 FcParsePatelt (parse);
2257 break;
c2e7c611
KP
2258 case FcElementName:
2259 FcParseString (parse, FcVStackField);
2260 break;
2261 case FcElementConst:
2262 FcParseString (parse, FcVStackConstant);
2263 break;
2264 case FcElementOr:
3f7653c2 2265 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2266 break;
2267 case FcElementAnd:
3f7653c2 2268 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2269 break;
2270 case FcElementEq:
3f7653c2 2271 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2272 break;
2273 case FcElementNotEq:
3f7653c2 2274 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2275 break;
2276 case FcElementLess:
3f7653c2 2277 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2278 break;
2279 case FcElementLessEq:
3f7653c2 2280 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2281 break;
2282 case FcElementMore:
3f7653c2 2283 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2284 break;
2285 case FcElementMoreEq:
3f7653c2 2286 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2287 break;
47d4f950 2288 case FcElementContains:
3f7653c2 2289 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2290 break;
2291 case FcElementNotContains:
3f7653c2 2292 FcParseBinary (parse, FcOpNotContains);
47d4f950 2293 break;
c2e7c611 2294 case FcElementPlus:
3f7653c2 2295 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2296 break;
2297 case FcElementMinus:
3f7653c2 2298 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2299 break;
2300 case FcElementTimes:
3f7653c2 2301 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2302 break;
2303 case FcElementDivide:
3f7653c2 2304 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2305 break;
2306 case FcElementNot:
3f7653c2 2307 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2308 break;
2309 case FcElementIf:
3f7653c2
KP
2310 FcParseBinary (parse, FcOpQuest);
2311 break;
2312 case FcElementFloor:
2313 FcParseUnary (parse, FcOpFloor);
2314 break;
2315 case FcElementCeil:
2316 FcParseUnary (parse, FcOpCeil);
2317 break;
2318 case FcElementRound:
2319 FcParseUnary (parse, FcOpRound);
2320 break;
2321 case FcElementTrunc:
2322 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2323 break;
2324 case FcElementUnknown:
2325 break;
24330d27 2326 }
c2e7c611
KP
2327 (void) FcPStackPop (parse);
2328}
2329
2330static void
2331FcCharacterData (void *userData, const XML_Char *s, int len)
2332{
2333 FcConfigParse *parse = userData;
2334
2335 if (!parse->pstack)
2336 return;
2337 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2338 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2339}
2340
2341static void
2342FcStartDoctypeDecl (void *userData,
2343 const XML_Char *doctypeName,
2344 const XML_Char *sysid,
2345 const XML_Char *pubid,
2346 int has_internal_subset)
2347{
2348 FcConfigParse *parse = userData;
2349
2350 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2351 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2352}
2353
0d745819 2354#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2355
2356static void
2357FcInternalSubsetDecl (void *userData,
2358 const XML_Char *doctypeName,
2359 const XML_Char *sysid,
2360 const XML_Char *pubid)
2361{
2362 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2363}
2364
2365static void
2366FcExternalSubsetDecl (void *userData,
2367 const XML_Char *doctypeName,
2368 const XML_Char *sysid,
2369 const XML_Char *pubid)
2370{
2371 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2372}
2373
2374#else /* ENABLE_LIBXML2 */
2375
c2e7c611
KP
2376static void
2377FcEndDoctypeDecl (void *userData)
2378{
24330d27
KP
2379}
2380
e99f0f0a
PL
2381#endif /* ENABLE_LIBXML2 */
2382
9419bb34
KP
2383static int
2384FcSortCmpStr (const void *a, const void *b)
2385{
2386 const FcChar8 *as = *((FcChar8 **) a);
2387 const FcChar8 *bs = *((FcChar8 **) b);
2388 return FcStrCmp (as, bs);
2389}
2390
2d9c79c0
KP
2391static FcBool
2392FcConfigParseAndLoadDir (FcConfig *config,
2393 const FcChar8 *name,
2394 const FcChar8 *dir,
2395 FcBool complain)
2396{
2397 DIR *d;
2398 struct dirent *e;
2399 FcBool ret = FcTrue;
2400 FcChar8 *file;
2401 FcChar8 *base;
2402 FcStrSet *files;
2403
2404 d = opendir ((char *) dir);
2405 if (!d)
2406 {
2407 if (complain)
2408 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2409 name);
2410 ret = FcFalse;
2411 goto bail0;
2412 }
2413 /* freed below */
2414 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2415 if (!file)
2416 {
2417 ret = FcFalse;
2418 goto bail1;
2419 }
2420
2421 strcpy ((char *) file, (char *) dir);
2422 strcat ((char *) file, "/");
2423 base = file + strlen ((char *) file);
2424
2425 files = FcStrSetCreate ();
2426 if (!files)
2427 {
2428 ret = FcFalse;
2429 goto bail2;
2430 }
2431
2432 if (FcDebug () & FC_DBG_CONFIG)
2433 printf ("\tScanning config dir %s\n", dir);
2434
2435 while (ret && (e = readdir (d)))
2436 {
8245771d
PL
2437 int d_len;
2438#define TAIL ".conf"
2439#define TAIL_LEN 5
2d9c79c0 2440 /*
8245771d 2441 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2442 */
2443 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2444 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2445 d_len > TAIL_LEN &&
2446 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2447 {
2448 strcpy ((char *) base, (char *) e->d_name);
2449 if (!FcStrSetAdd (files, file))
2450 {
2451 ret = FcFalse;
2452 goto bail3;
2453 }
2454 }
2455 }
2456 if (ret)
2457 {
2458 int i;
4262e0b3 2459 qsort (files->strs, files->num, sizeof (FcChar8 *),
9419bb34 2460 (int (*)(const void *, const void *)) FcSortCmpStr);
2d9c79c0 2461 for (i = 0; ret && i < files->num; i++)
4262e0b3 2462 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2463 }
2464bail3:
2465 FcStrSetDestroy (files);
2466bail2:
2467 free (file);
2468bail1:
2469 closedir (d);
2470bail0:
2471 return ret || !complain;
2472}
2473
24330d27
KP
2474FcBool
2475FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2476 const FcChar8 *name,
24330d27
KP
2477 FcBool complain)
2478{
24330d27 2479
c2e7c611
KP
2480 XML_Parser p;
2481 FcChar8 *filename;
3bfae75d 2482 int fd;
c2e7c611 2483 int len;
c2e7c611
KP
2484 FcConfigParse parse;
2485 FcBool error = FcTrue;
2486
0d745819 2487#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2488 xmlSAXHandler sax;
2489 char buf[BUFSIZ];
2490#else
2491 void *buf;
2492#endif
2493
c2e7c611
KP
2494 filename = FcConfigFilename (name);
2495 if (!filename)
2496 goto bail0;
4aded3e0 2497
cb6d97eb
PL
2498 if (FcStrSetMember (config->configFiles, filename))
2499 {
2500 FcStrFree (filename);
2501 return FcTrue;
2502 }
2503
4aded3e0 2504 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2505 {
2506 FcStrFree (filename);
4aded3e0 2507 goto bail0;
9dac3c59 2508 }
4aded3e0 2509
2d9c79c0
KP
2510 if (FcFileIsDir (filename))
2511 {
2512 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2513 FcStrFree (filename);
2514 return ret;
2515 }
2516
2517 if (FcDebug () & FC_DBG_CONFIG)
2518 printf ("\tLoading config file %s\n", filename);
2519
3bfae75d
PL
2520 fd = open ((char *) filename, O_RDONLY);
2521 if (fd == -1) {
8f2a8078 2522 FcStrFree (filename);
c2e7c611 2523 goto bail0;
8f2a8078 2524 }
c2e7c611 2525
0d745819 2526#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2527 memset(&sax, 0, sizeof(sax));
2528
2529 sax.internalSubset = FcInternalSubsetDecl;
2530 sax.externalSubset = FcExternalSubsetDecl;
2531 sax.startElement = FcStartElement;
2532 sax.endElement = FcEndElement;
2533 sax.characters = FcCharacterData;
2534
8f2a8078 2535 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2536#else
c2e7c611 2537 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2538#endif
8f2a8078 2539 FcStrFree (filename);
e99f0f0a 2540
c2e7c611
KP
2541 if (!p)
2542 goto bail1;
2543
2544 if (!FcConfigInit (&parse, name, config, p))
2545 goto bail2;
2546
0d745819 2547#ifndef ENABLE_LIBXML2
e99f0f0a 2548
c2e7c611
KP
2549 XML_SetUserData (p, &parse);
2550
2551 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2552 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2553 XML_SetCharacterDataHandler (p, FcCharacterData);
2554
e99f0f0a
PL
2555#endif /* ENABLE_LIBXML2 */
2556
c2e7c611 2557 do {
0d745819 2558#ifndef ENABLE_LIBXML2
c2e7c611
KP
2559 buf = XML_GetBuffer (p, BUFSIZ);
2560 if (!buf)
80c053b7 2561 {
179c3995 2562 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2563 goto bail3;
80c053b7 2564 }
e99f0f0a 2565#endif
3bfae75d 2566 len = read (fd, buf, BUFSIZ);
c2e7c611 2567 if (len < 0)
80c053b7 2568 {
179c3995 2569 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2570 goto bail3;
80c053b7 2571 }
e99f0f0a 2572
0d745819 2573#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2574 if (xmlParseChunk (p, buf, len, len == 0))
2575#else
c2e7c611 2576 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2577#endif
80c053b7 2578 {
179c3995 2579 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2580 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2581 goto bail3;
80c053b7 2582 }
c2e7c611
KP
2583 } while (len != 0);
2584 error = parse.error;
2585bail3:
2586 FcConfigCleanup (&parse);
2587bail2:
2588 XML_ParserFree (p);
2589bail1:
3bfae75d
PL
2590 close (fd);
2591 fd = -1;
c2e7c611
KP
2592bail0:
2593 if (error && complain)
24330d27 2594 {
c2e7c611 2595 if (name)
179c3995 2596 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2597 else
179c3995 2598 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2599 return FcFalse;
2600 }
2601 return FcTrue;
2602}
23816bf9
KP
2603#define __fcxml__
2604#include "fcaliastail.h"
2605#undef __fcxml__