]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Have --with-expat set EXPAT_CFLAGS (bug 2278)
[fontconfig.git] / src / fcxml.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2002 Keith Packard
24330d27
KP
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#include <stdarg.h>
26#include "fcint.h"
2d9c79c0 27#include <dirent.h>
0ab36ca8 28
d0f07b8d
KP
29#ifndef HAVE_XMLPARSE_H
30#define HAVE_XMLPARSE_H 0
31#endif
fa244f3d 32
179c3995
KP
33#if HAVE_XMLPARSE_H
34#include <xmlparse.h>
35#else
36#include <expat.h>
37#endif
24330d27 38
daeed6e0
TL
39#ifdef _WIN32
40#define STRICT
41#include <windows.h>
42#undef STRICT
43#endif
44
24330d27 45FcTest *
938bc633
KP
46FcTestCreate (FcMatchKind kind,
47 FcQual qual,
48 const FcChar8 *field,
49 FcOp compare,
50 FcExpr *expr)
24330d27 51{
c2e7c611 52 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
24330d27
KP
53
54 if (test)
55 {
9dac3c59 56 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
24330d27 57 test->next = 0;
938bc633 58 test->kind = kind;
24330d27 59 test->qual = qual;
c2e7c611 60 test->field = (char *) FcStrCopy (field);
24330d27
KP
61 test->op = compare;
62 test->expr = expr;
63 }
64 return test;
65}
66
67void
68FcTestDestroy (FcTest *test)
69{
70 if (test->next)
71 FcTestDestroy (test->next);
72 FcExprDestroy (test->expr);
73 FcStrFree ((FcChar8 *) test->field);
9dac3c59 74 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
24330d27
KP
75 free (test);
76}
77
78FcExpr *
79FcExprCreateInteger (int i)
80{
81 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
82
83 if (e)
84 {
9dac3c59 85 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
86 e->op = FcOpInteger;
87 e->u.ival = i;
88 }
89 return e;
90}
91
92FcExpr *
93FcExprCreateDouble (double d)
94{
95 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
96
97 if (e)
98 {
9dac3c59 99 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
100 e->op = FcOpDouble;
101 e->u.dval = d;
102 }
103 return e;
104}
105
106FcExpr *
ccb3e93b 107FcExprCreateString (const FcChar8 *s)
24330d27
KP
108{
109 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
110
111 if (e)
112 {
9dac3c59 113 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
114 e->op = FcOpString;
115 e->u.sval = FcStrCopy (s);
116 }
117 return e;
118}
119
120FcExpr *
121FcExprCreateMatrix (const FcMatrix *m)
122{
123 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
124
125 if (e)
126 {
9dac3c59 127 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
128 e->op = FcOpMatrix;
129 e->u.mval = FcMatrixCopy (m);
130 }
131 return e;
132}
133
134FcExpr *
135FcExprCreateBool (FcBool b)
136{
137 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
138
139 if (e)
140 {
9dac3c59 141 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
142 e->op = FcOpBool;
143 e->u.bval = b;
144 }
145 return e;
146}
147
148FcExpr *
149FcExprCreateNil (void)
150{
151 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
152
153 if (e)
154 {
9dac3c59 155 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
156 e->op = FcOpNil;
157 }
158 return e;
159}
160
161FcExpr *
162FcExprCreateField (const char *field)
163{
164 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
165
166 if (e)
167 {
9dac3c59 168 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27 169 e->op = FcOpField;
ccb3e93b 170 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
171 }
172 return e;
173}
174
175FcExpr *
ccb3e93b 176FcExprCreateConst (const FcChar8 *constant)
24330d27
KP
177{
178 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
179
180 if (e)
181 {
9dac3c59 182 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
183 e->op = FcOpConst;
184 e->u.constant = FcStrCopy (constant);
185 }
186 return e;
187}
188
189FcExpr *
190FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
191{
192 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
193
194 if (e)
195 {
9dac3c59 196 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
197 e->op = op;
198 e->u.tree.left = left;
199 e->u.tree.right = right;
200 }
201 return e;
202}
203
204void
205FcExprDestroy (FcExpr *e)
206{
3f7653c2
KP
207 if (!e)
208 return;
24330d27
KP
209 switch (e->op) {
210 case FcOpInteger:
211 break;
212 case FcOpDouble:
213 break;
214 case FcOpString:
215 FcStrFree (e->u.sval);
216 break;
217 case FcOpMatrix:
218 FcMatrixFree (e->u.mval);
219 break;
220 case FcOpCharSet:
221 FcCharSetDestroy (e->u.cval);
222 break;
223 case FcOpBool:
224 break;
225 case FcOpField:
ccb3e93b 226 FcStrFree ((FcChar8 *) e->u.field);
24330d27
KP
227 break;
228 case FcOpConst:
229 FcStrFree (e->u.constant);
230 break;
231 case FcOpAssign:
232 case FcOpAssignReplace:
233 case FcOpPrepend:
234 case FcOpPrependFirst:
235 case FcOpAppend:
236 case FcOpAppendLast:
237 break;
238 case FcOpOr:
239 case FcOpAnd:
240 case FcOpEqual:
24330d27
KP
241 case FcOpNotEqual:
242 case FcOpLess:
243 case FcOpLessEqual:
244 case FcOpMore:
245 case FcOpMoreEqual:
47d4f950 246 case FcOpContains:
74a623e0 247 case FcOpListing:
47d4f950 248 case FcOpNotContains:
24330d27
KP
249 case FcOpPlus:
250 case FcOpMinus:
251 case FcOpTimes:
252 case FcOpDivide:
253 case FcOpQuest:
254 case FcOpComma:
255 FcExprDestroy (e->u.tree.right);
256 /* fall through */
257 case FcOpNot:
3f7653c2
KP
258 case FcOpFloor:
259 case FcOpCeil:
260 case FcOpRound:
261 case FcOpTrunc:
24330d27
KP
262 FcExprDestroy (e->u.tree.left);
263 break;
264 case FcOpNil:
265 case FcOpInvalid:
266 break;
267 }
9dac3c59 268 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
24330d27
KP
269 free (e);
270}
271
272FcEdit *
6fff2cda 273FcEditCreate (const char *field, FcOp op, FcExpr *expr, FcValueBinding binding)
24330d27
KP
274{
275 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
276
277 if (e)
278 {
279 e->next = 0;
280 e->field = field; /* already saved in grammar */
281 e->op = op;
282 e->expr = expr;
6fff2cda 283 e->binding = binding;
24330d27
KP
284 }
285 return e;
286}
287
288void
289FcEditDestroy (FcEdit *e)
290{
291 if (e->next)
292 FcEditDestroy (e->next);
293 FcStrFree ((FcChar8 *) e->field);
294 if (e->expr)
295 FcExprDestroy (e->expr);
34cd0514 296 free (e);
24330d27
KP
297}
298
299char *
300FcConfigSaveField (const char *field)
301{
ccb3e93b 302 return (char *) FcStrCopy ((FcChar8 *) field);
24330d27
KP
303}
304
c2e7c611
KP
305typedef enum _FcElement {
306 FcElementNone,
307 FcElementFontconfig,
308 FcElementDir,
309 FcElementCache,
310 FcElementInclude,
311 FcElementConfig,
312 FcElementMatch,
313 FcElementAlias,
314
315 FcElementBlank,
179c3995 316 FcElementRescan,
c2e7c611
KP
317
318 FcElementPrefer,
319 FcElementAccept,
320 FcElementDefault,
321 FcElementFamily,
322
d47c9d6e
KP
323 FcElementSelectfont,
324 FcElementAcceptfont,
325 FcElementRejectfont,
326 FcElementGlob,
4f27c1c0
KP
327 FcElementPattern,
328 FcElementPatelt,
d47c9d6e 329
c2e7c611
KP
330 FcElementTest,
331 FcElementEdit,
332 FcElementInt,
333 FcElementDouble,
334 FcElementString,
335 FcElementMatrix,
336 FcElementBool,
337 FcElementCharset,
338 FcElementName,
339 FcElementConst,
340 FcElementOr,
341 FcElementAnd,
342 FcElementEq,
343 FcElementNotEq,
344 FcElementLess,
345 FcElementLessEq,
346 FcElementMore,
347 FcElementMoreEq,
47d4f950
KP
348 FcElementContains,
349 FcElementNotContains,
c2e7c611
KP
350 FcElementPlus,
351 FcElementMinus,
352 FcElementTimes,
353 FcElementDivide,
354 FcElementNot,
355 FcElementIf,
3f7653c2
KP
356 FcElementFloor,
357 FcElementCeil,
358 FcElementRound,
359 FcElementTrunc,
c2e7c611
KP
360 FcElementUnknown
361} FcElement;
362
363static FcElement
364FcElementMap (const XML_Char *name)
365{
366 static struct {
367 char *name;
368 FcElement element;
369 } fcElementMap[] = {
370 { "fontconfig", FcElementFontconfig },
371 { "dir", FcElementDir },
372 { "cache", FcElementCache },
373 { "include", FcElementInclude },
374 { "config", FcElementConfig },
375 { "match", FcElementMatch },
376 { "alias", FcElementAlias },
377
378 { "blank", FcElementBlank },
179c3995 379 { "rescan", FcElementRescan },
c2e7c611
KP
380
381 { "prefer", FcElementPrefer },
382 { "accept", FcElementAccept },
383 { "default", FcElementDefault },
384 { "family", FcElementFamily },
385
d47c9d6e
KP
386 { "selectfont", FcElementSelectfont },
387 { "acceptfont", FcElementAcceptfont },
388 { "rejectfont", FcElementRejectfont },
389 { "glob", FcElementGlob },
4f27c1c0
KP
390 { "pattern", FcElementPattern },
391 { "patelt", FcElementPatelt },
d47c9d6e 392
c2e7c611
KP
393 { "test", FcElementTest },
394 { "edit", FcElementEdit },
395 { "int", FcElementInt },
396 { "double", FcElementDouble },
397 { "string", FcElementString },
398 { "matrix", FcElementMatrix },
399 { "bool", FcElementBool },
400 { "charset", FcElementCharset },
401 { "name", FcElementName },
402 { "const", FcElementConst },
403 { "or", FcElementOr },
404 { "and", FcElementAnd },
405 { "eq", FcElementEq },
406 { "not_eq", FcElementNotEq },
407 { "less", FcElementLess },
408 { "less_eq", FcElementLessEq },
409 { "more", FcElementMore },
410 { "more_eq", FcElementMoreEq },
47d4f950
KP
411 { "contains", FcElementContains },
412 { "not_contains",FcElementNotContains },
c2e7c611
KP
413 { "plus", FcElementPlus },
414 { "minus", FcElementMinus },
415 { "times", FcElementTimes },
416 { "divide", FcElementDivide },
417 { "not", FcElementNot },
418 { "if", FcElementIf },
3f7653c2
KP
419 { "floor", FcElementFloor },
420 { "ceil", FcElementCeil },
421 { "round", FcElementRound },
422 { "trunc", FcElementTrunc },
c2e7c611
KP
423
424 { 0, 0 }
425 };
426
427 int i;
428 for (i = 0; fcElementMap[i].name; i++)
429 if (!strcmp ((char *) name, fcElementMap[i].name))
430 return fcElementMap[i].element;
431 return FcElementUnknown;
432}
433
434typedef struct _FcPStack {
435 struct _FcPStack *prev;
436 FcElement element;
437 FcChar8 **attr;
438 FcStrBuf str;
439} FcPStack;
440
441typedef enum _FcVStackTag {
442 FcVStackNone,
443
444 FcVStackString,
445 FcVStackFamily,
446 FcVStackField,
447 FcVStackConstant,
d47c9d6e 448 FcVStackGlob,
4f27c1c0 449 FcVStackPattern,
c2e7c611
KP
450
451 FcVStackPrefer,
452 FcVStackAccept,
453 FcVStackDefault,
454
455 FcVStackInteger,
456 FcVStackDouble,
457 FcVStackMatrix,
458 FcVStackBool,
459
460 FcVStackTest,
461 FcVStackExpr,
462 FcVStackEdit
463} FcVStackTag;
464
465typedef struct _FcVStack {
466 struct _FcVStack *prev;
467 FcPStack *pstack; /* related parse element */
468 FcVStackTag tag;
469 union {
470 FcChar8 *string;
471
472 int integer;
473 double _double;
474 FcMatrix *matrix;
475 FcBool bool;
476
477 FcTest *test;
478 FcQual qual;
479 FcOp op;
480 FcExpr *expr;
481 FcEdit *edit;
4f27c1c0
KP
482
483 FcPattern *pattern;
c2e7c611
KP
484 } u;
485} FcVStack;
486
487typedef struct _FcConfigParse {
488 FcPStack *pstack;
489 FcVStack *vstack;
490 FcBool error;
491 const FcChar8 *name;
492 FcConfig *config;
493 XML_Parser parser;
494} FcConfigParse;
495
179c3995
KP
496typedef enum _FcConfigSeverity {
497 FcSevereInfo, FcSevereWarning, FcSevereError
498} FcConfigSeverity;
499
24330d27 500static void
179c3995 501FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
24330d27 502{
179c3995 503 char *s = "unknown";
24330d27
KP
504 va_list args;
505
506 va_start (args, fmt);
179c3995
KP
507
508 switch (severe) {
509 case FcSevereInfo: s = "info"; break;
510 case FcSevereWarning: s = "warning"; break;
511 case FcSevereError: s = "error"; break;
512 }
c2e7c611
KP
513 if (parse)
514 {
515 if (parse->name)
179c3995 516 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
c2e7c611
KP
517 parse->name, XML_GetCurrentLineNumber (parse->parser));
518 else
179c3995 519 fprintf (stderr, "Fontconfig %s: line %d: ", s,
c2e7c611 520 XML_GetCurrentLineNumber (parse->parser));
179c3995
KP
521 if (severe >= FcSevereError)
522 parse->error = FcTrue;
c2e7c611
KP
523 }
524 else
179c3995 525 fprintf (stderr, "Fontconfig %s: ", s);
24330d27
KP
526 vfprintf (stderr, fmt, args);
527 fprintf (stderr, "\n");
528 va_end (args);
529}
530
c2e7c611
KP
531static void
532FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
24330d27 533{
c2e7c611
KP
534 vstack->prev = parse->vstack;
535 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
536 parse->vstack = vstack;
24330d27
KP
537}
538
c2e7c611
KP
539static FcVStack *
540FcVStackCreate (void)
24330d27 541{
c2e7c611 542 FcVStack *new;
24330d27 543
c2e7c611
KP
544 new = malloc (sizeof (FcVStack));
545 if (!new)
546 return 0;
9dac3c59 547 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
548 new->tag = FcVStackNone;
549 new->prev = 0;
550 return new;
551}
24330d27 552
c2e7c611
KP
553static void
554FcVStackDestroy (FcVStack *vstack)
24330d27 555{
c2e7c611 556 FcVStack *prev;
24330d27 557
c2e7c611
KP
558 for (; vstack; vstack = prev)
559 {
560 prev = vstack->prev;
561 switch (vstack->tag) {
562 case FcVStackNone:
563 break;
564 case FcVStackString:
565 case FcVStackFamily:
566 case FcVStackField:
567 case FcVStackConstant:
d47c9d6e 568 case FcVStackGlob:
c2e7c611
KP
569 FcStrFree (vstack->u.string);
570 break;
4f27c1c0
KP
571 case FcVStackPattern:
572 FcPatternDestroy (vstack->u.pattern);
573 break;
c2e7c611
KP
574 case FcVStackInteger:
575 case FcVStackDouble:
576 break;
577 case FcVStackMatrix:
578 FcMatrixFree (vstack->u.matrix);
579 break;
580 case FcVStackBool:
581 break;
582 case FcVStackTest:
583 FcTestDestroy (vstack->u.test);
584 break;
585 case FcVStackExpr:
586 case FcVStackPrefer:
587 case FcVStackAccept:
588 case FcVStackDefault:
589 FcExprDestroy (vstack->u.expr);
590 break;
591 case FcVStackEdit:
592 FcEditDestroy (vstack->u.edit);
593 break;
594 }
9dac3c59 595 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
c2e7c611
KP
596 free (vstack);
597 }
24330d27
KP
598}
599
600static FcBool
c2e7c611 601FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 602{
c2e7c611
KP
603 FcVStack *vstack = FcVStackCreate ();
604 if (!vstack)
605 return FcFalse;
606 vstack->u.string = string;
607 vstack->tag = tag;
608 FcVStackPush (parse, vstack);
609 return FcTrue;
24330d27
KP
610}
611
612static FcBool
c2e7c611 613FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 614{
c2e7c611
KP
615 FcVStack *vstack = FcVStackCreate ();
616 if (!vstack)
24330d27 617 return FcFalse;
c2e7c611
KP
618 vstack->u.integer = integer;
619 vstack->tag = FcVStackInteger;
620 FcVStackPush (parse, vstack);
621 return FcTrue;
24330d27
KP
622}
623
624static FcBool
c2e7c611 625FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 626{
c2e7c611
KP
627 FcVStack *vstack = FcVStackCreate ();
628 if (!vstack)
24330d27 629 return FcFalse;
c2e7c611
KP
630 vstack->u._double = _double;
631 vstack->tag = FcVStackDouble;
632 FcVStackPush (parse, vstack);
633 return FcTrue;
24330d27
KP
634}
635
636static FcBool
c2e7c611 637FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 638{
c2e7c611
KP
639 FcVStack *vstack = FcVStackCreate ();
640 if (!vstack)
24330d27 641 return FcFalse;
c2e7c611
KP
642 matrix = FcMatrixCopy (matrix);
643 if (!matrix)
24330d27 644 {
c2e7c611
KP
645 FcVStackDestroy (vstack);
646 return FcFalse;
24330d27 647 }
c2e7c611
KP
648 vstack->u.matrix = matrix;
649 vstack->tag = FcVStackMatrix;
650 FcVStackPush (parse, vstack);
651 return FcTrue;
24330d27
KP
652}
653
654static FcBool
c2e7c611 655FcVStackPushBool (FcConfigParse *parse, FcBool bool)
24330d27 656{
c2e7c611
KP
657 FcVStack *vstack = FcVStackCreate ();
658 if (!vstack)
659 return FcFalse;
660 vstack->u.bool = bool;
661 vstack->tag = FcVStackBool;
662 FcVStackPush (parse, vstack);
663 return FcTrue;
664}
24330d27 665
c2e7c611
KP
666static FcBool
667FcVStackPushTest (FcConfigParse *parse, FcTest *test)
668{
669 FcVStack *vstack = FcVStackCreate ();
670 if (!vstack)
24330d27 671 return FcFalse;
c2e7c611
KP
672 vstack->u.test = test;
673 vstack->tag = FcVStackTest;
674 FcVStackPush (parse, vstack);
24330d27
KP
675 return FcTrue;
676}
677
678static FcBool
c2e7c611 679FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 680{
c2e7c611
KP
681 FcVStack *vstack = FcVStackCreate ();
682 if (!vstack)
683 return FcFalse;
684 vstack->u.expr = expr;
685 vstack->tag = tag;
686 FcVStackPush (parse, vstack);
687 return FcTrue;
688}
24330d27 689
c2e7c611
KP
690static FcBool
691FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
692{
693 FcVStack *vstack = FcVStackCreate ();
694 if (!vstack)
24330d27 695 return FcFalse;
c2e7c611
KP
696 vstack->u.edit = edit;
697 vstack->tag = FcVStackEdit;
698 FcVStackPush (parse, vstack);
24330d27
KP
699 return FcTrue;
700}
701
4f27c1c0
KP
702static FcBool
703FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
704{
705 FcVStack *vstack = FcVStackCreate ();
706 if (!vstack)
707 return FcFalse;
708 vstack->u.pattern = pattern;
709 vstack->tag = FcVStackPattern;
710 FcVStackPush (parse, vstack);
711 return FcTrue;
712}
713
c2e7c611
KP
714static FcVStack *
715FcVStackFetch (FcConfigParse *parse, int off)
24330d27 716{
c2e7c611 717 FcVStack *vstack;
24330d27 718
c2e7c611
KP
719 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
720 return vstack;
721}
722
723static void
724FcVStackClear (FcConfigParse *parse)
725{
726 while (parse->vstack && parse->vstack->pstack == parse->pstack)
24330d27 727 {
c2e7c611
KP
728 FcVStack *vstack = parse->vstack;
729 parse->vstack = vstack->prev;
730 vstack->prev = 0;
731 FcVStackDestroy (vstack);
24330d27 732 }
24330d27
KP
733}
734
c2e7c611
KP
735static FcVStack *
736FcVStackPop (FcConfigParse *parse)
24330d27 737{
c2e7c611 738 FcVStack *vstack = parse->vstack;
24330d27 739
c2e7c611 740 if (!vstack || vstack->pstack != parse->pstack)
24330d27 741 return 0;
c2e7c611
KP
742 parse->vstack = vstack->prev;
743 vstack->prev = 0;
744 return vstack;
745}
746
747static int
748FcVStackElements (FcConfigParse *parse)
749{
750 int h = 0;
751 FcVStack *vstack = parse->vstack;
752 while (vstack && vstack->pstack == parse->pstack)
753 {
754 h++;
755 vstack = vstack->prev;
24330d27 756 }
c2e7c611 757 return h;
24330d27
KP
758}
759
c2e7c611
KP
760static FcChar8 **
761FcConfigSaveAttr (const XML_Char **attr)
24330d27 762{
c2e7c611
KP
763 int n;
764 int slen;
765 int i;
766 FcChar8 **new;
767 FcChar8 *s;
24330d27 768
c2e7c611
KP
769 if (!attr)
770 return 0;
771 slen = 0;
772 for (i = 0; attr[i]; i++)
773 slen += strlen (attr[i]) + 1;
774 n = i;
775 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
776 if (!new)
777 return 0;
9dac3c59 778 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
c2e7c611
KP
779 s = (FcChar8 *) (new + (i + 1));
780 for (i = 0; attr[i]; i++)
24330d27 781 {
c2e7c611
KP
782 new[i] = s;
783 strcpy ((char *) s, (char *) attr[i]);
784 s += strlen ((char *) s) + 1;
24330d27 785 }
c2e7c611
KP
786 new[i] = 0;
787 return new;
788}
24330d27 789
c2e7c611
KP
790static FcBool
791FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
792{
793 FcPStack *new = malloc (sizeof (FcPStack));
794
795 if (!new)
796 return FcFalse;
9dac3c59 797 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
798 new->prev = parse->pstack;
799 new->element = element;
800 if (attr)
24330d27 801 {
c2e7c611
KP
802 new->attr = FcConfigSaveAttr (attr);
803 if (!new->attr)
179c3995 804 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 805 }
c2e7c611
KP
806 else
807 new->attr = 0;
808 FcStrBufInit (&new->str, 0, 0);
809 parse->pstack = new;
810 return FcTrue;
811}
24330d27 812
c2e7c611
KP
813static FcBool
814FcPStackPop (FcConfigParse *parse)
815{
816 FcPStack *old;
817
818 if (!parse->pstack)
24330d27 819 {
179c3995 820 FcConfigMessage (parse, FcSevereError, "mismatching element");
c2e7c611 821 return FcFalse;
24330d27 822 }
c2e7c611
KP
823 FcVStackClear (parse);
824 old = parse->pstack;
825 parse->pstack = old->prev;
826 FcStrBufDestroy (&old->str);
827 if (old->attr)
9dac3c59
KP
828 {
829 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
c2e7c611 830 free (old->attr);
9dac3c59
KP
831 }
832 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
c2e7c611
KP
833 free (old);
834 return FcTrue;
24330d27
KP
835}
836
c2e7c611
KP
837static FcBool
838FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
24330d27 839{
c2e7c611
KP
840 parse->pstack = 0;
841 parse->vstack = 0;
842 parse->error = FcFalse;
843 parse->name = name;
844 parse->config = config;
845 parse->parser = parser;
846 return FcTrue;
847}
848
849static void
850FcConfigCleanup (FcConfigParse *parse)
851{
852 while (parse->pstack)
853 FcPStackPop (parse);
854}
855
856static const FcChar8 *
857FcConfigGetAttribute (FcConfigParse *parse, char *attr)
858{
859 FcChar8 **attrs;
860 if (!parse->pstack)
24330d27 861 return 0;
24330d27 862
c2e7c611
KP
863 attrs = parse->pstack->attr;
864 while (*attrs)
24330d27 865 {
c2e7c611
KP
866 if (!strcmp ((char *) *attrs, attr))
867 return attrs[1];
868 attrs += 2;
24330d27 869 }
24330d27
KP
870 return 0;
871}
872
c2e7c611
KP
873static void
874FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
24330d27 875{
c2e7c611
KP
876 FcConfigParse *parse = userData;
877 FcElement element;
878
879 element = FcElementMap (name);
880 if (element == FcElementUnknown)
179c3995 881 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
c2e7c611
KP
882
883 if (!FcPStackPush (parse, element, attr))
24330d27 884 {
179c3995 885 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 886 return;
24330d27 887 }
c2e7c611
KP
888 return;
889}
24330d27 890
c2e7c611
KP
891static void
892FcParseBlank (FcConfigParse *parse)
893{
894 int n = FcVStackElements (parse);
895 while (n-- > 0)
24330d27 896 {
c2e7c611
KP
897 FcVStack *v = FcVStackFetch (parse, n);
898 if (v->tag != FcVStackInteger)
179c3995 899 FcConfigMessage (parse, FcSevereError, "non-integer blank");
c2e7c611 900 else
24330d27 901 {
c2e7c611 902 if (!parse->config->blanks)
24330d27 903 {
c2e7c611
KP
904 parse->config->blanks = FcBlanksCreate ();
905 if (!parse->config->blanks)
906 {
179c3995 907 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
908 break;
909 }
24330d27 910 }
c2e7c611 911 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
24330d27 912 {
179c3995 913 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 914 break;
24330d27
KP
915 }
916 }
917 }
c2e7c611 918}
24330d27 919
179c3995
KP
920static void
921FcParseRescan (FcConfigParse *parse)
922{
923 int n = FcVStackElements (parse);
924 while (n-- > 0)
925 {
926 FcVStack *v = FcVStackFetch (parse, n);
927 if (v->tag != FcVStackInteger)
928 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
929 else
930 parse->config->rescanInterval = v->u.integer;
931 }
932}
933
c2e7c611
KP
934static void
935FcParseInt (FcConfigParse *parse)
936{
937 FcChar8 *s, *end;
938 int l;
939
940 if (!parse->pstack)
941 return;
942 s = FcStrBufDone (&parse->pstack->str);
943 if (!s)
24330d27 944 {
179c3995 945 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 946 return;
24330d27 947 }
c2e7c611
KP
948 end = 0;
949 l = (int) strtol ((char *) s, (char **)&end, 0);
950 if (end != s + strlen ((char *) s))
179c3995 951 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
c2e7c611
KP
952 else
953 FcVStackPushInteger (parse, l);
954 FcStrFree (s);
24330d27
KP
955}
956
223c0289
KP
957/*
958 * idea copied from glib g_ascii_strtod with
959 * permission of the author (Alexander Larsson)
960 */
961
962#include <locale.h>
963
964static double
965FcStrtod (char *s, char **end)
966{
967 struct lconv *locale_data;
968 char *dot;
969 double v;
970
971 /*
972 * Have to swap the decimal point to match the current locale
973 * if that locale doesn't use 0x2e
974 */
975 if ((dot = strchr (s, 0x2e)) &&
976 (locale_data = localeconv ()) &&
977 (locale_data->decimal_point[0] != 0x2e ||
978 locale_data->decimal_point[1] != 0))
979 {
980 char buf[128];
981 int slen = strlen (s);
982 int dlen = strlen (locale_data->decimal_point);
983
984 if (slen + dlen > sizeof (buf))
985 {
986 if (end)
987 *end = s;
988 v = 0;
989 }
990 else
991 {
992 char *buf_end;
993 /* mantissa */
994 strncpy (buf, s, dot - s);
995 /* decimal point */
996 strcpy (buf + (dot - s), locale_data->decimal_point);
997 /* rest of number */
998 strcpy (buf + (dot - s) + dlen, dot + 1);
999 buf_end = 0;
1000 v = strtod (buf, &buf_end);
344a0e33
RP
1001 if (buf_end) {
1002 buf_end = s + (buf_end - buf);
1003 if (buf_end > dot)
1004 buf_end -= dlen - 1;
1005 }
223c0289
KP
1006 if (end)
1007 *end = buf_end;
1008 }
1009 }
1010 else
1011 v = strtod (s, end);
1012 return v;
1013}
1014
c2e7c611
KP
1015static void
1016FcParseDouble (FcConfigParse *parse)
24330d27 1017{
c2e7c611
KP
1018 FcChar8 *s, *end;
1019 double d;
24330d27 1020
c2e7c611
KP
1021 if (!parse->pstack)
1022 return;
1023 s = FcStrBufDone (&parse->pstack->str);
1024 if (!s)
24330d27 1025 {
179c3995 1026 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1027 return;
24330d27 1028 }
c2e7c611 1029 end = 0;
223c0289 1030 d = FcStrtod ((char *) s, (char **)&end);
c2e7c611 1031 if (end != s + strlen ((char *) s))
179c3995 1032 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
24330d27 1033 else
c2e7c611
KP
1034 FcVStackPushDouble (parse, d);
1035 FcStrFree (s);
1036}
24330d27 1037
c2e7c611
KP
1038static void
1039FcParseString (FcConfigParse *parse, FcVStackTag tag)
1040{
1041 FcChar8 *s;
1042
1043 if (!parse->pstack)
1044 return;
1045 s = FcStrBufDone (&parse->pstack->str);
1046 if (!s)
1047 {
179c3995 1048 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1049 return;
1050 }
1051 if (!FcVStackPushString (parse, tag, s))
1052 FcStrFree (s);
1053}
1054
1055static void
1056FcParseMatrix (FcConfigParse *parse)
1057{
1058 FcVStack *vstack;
1059 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1060 FcMatrix m;
1061
1062 while ((vstack = FcVStackPop (parse)))
1063 {
179c3995
KP
1064 double v;
1065 switch (vstack->tag) {
1066 case FcVStackInteger:
1067 v = vstack->u.integer;
1068 break;
1069 case FcVStackDouble:
1070 v = vstack->u._double;
1071 break;
1072 default:
1073 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1074 v = 1.0;
1075 break;
1076 }
1077 switch (matrix_state) {
1078 case m_xx: m.xx = v; break;
1079 case m_xy: m.xy = v; break;
1080 case m_yx: m.yx = v; break;
1081 case m_yy: m.yy = v; break;
1082 default: break;
c2e7c611 1083 }
f4fe447f 1084 FcVStackDestroy (vstack);
179c3995 1085 matrix_state--;
c2e7c611
KP
1086 }
1087 if (matrix_state != m_done)
179c3995 1088 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
c2e7c611
KP
1089 else
1090 FcVStackPushMatrix (parse, &m);
24330d27
KP
1091}
1092
1093static FcBool
c2e7c611
KP
1094FcConfigLexBool (const FcChar8 *bool)
1095{
1096 if (*bool == 't' || *bool == 'T')
1097 return FcTrue;
1098 if (*bool == 'y' || *bool == 'Y')
1099 return FcTrue;
1100 if (*bool == '1')
1101 return FcTrue;
1102 return FcFalse;
1103}
1104
1105static void
1106FcParseBool (FcConfigParse *parse)
1107{
1108 FcChar8 *s;
1109
1110 if (!parse->pstack)
1111 return;
1112 s = FcStrBufDone (&parse->pstack->str);
1113 if (!s)
1114 {
179c3995 1115 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1116 return;
1117 }
1118 FcVStackPushBool (parse, FcConfigLexBool (s));
1119 FcStrFree (s);
1120}
1121
1122static void
1123FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1124{
c2e7c611
KP
1125 FcVStack *vstack;
1126 FcExpr *left, *expr = 0, *new;
1127
1128 while ((vstack = FcVStackPop (parse)))
1129 {
1130 if (vstack->tag != FcVStackFamily)
1131 {
179c3995
KP
1132 FcConfigMessage (parse, FcSevereWarning, "non-family");
1133 FcVStackDestroy (vstack);
1134 continue;
c2e7c611
KP
1135 }
1136 left = vstack->u.expr;
1137 vstack->tag = FcVStackNone;
1138 FcVStackDestroy (vstack);
1139 if (expr)
1140 {
1141 new = FcExprCreateOp (left, FcOpComma, expr);
1142 if (!new)
1143 {
179c3995 1144 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1145 FcExprDestroy (left);
1146 FcExprDestroy (expr);
1147 break;
1148 }
1149 expr = new;
1150 }
1151 else
1152 expr = left;
1153 }
1154 if (expr)
1155 {
1156 if (!FcVStackPushExpr (parse, tag, expr))
1157 {
179c3995 1158 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1159 if (expr)
1160 FcExprDestroy (expr);
1161 }
1162 }
1163}
1164
1165static void
1166FcParseFamily (FcConfigParse *parse)
1167{
1168 FcChar8 *s;
1169 FcExpr *expr;
1170
1171 if (!parse->pstack)
1172 return;
1173 s = FcStrBufDone (&parse->pstack->str);
1174 if (!s)
1175 {
179c3995 1176 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1177 return;
1178 }
1179 expr = FcExprCreateString (s);
1180 FcStrFree (s);
1181 if (expr)
1182 FcVStackPushExpr (parse, FcVStackFamily, expr);
1183}
1184
1185static void
1186FcParseAlias (FcConfigParse *parse)
1187{
179c3995 1188 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1189 FcEdit *edit = 0, *next;
c2e7c611 1190 FcVStack *vstack;
24330d27
KP
1191 FcTest *test;
1192
c2e7c611 1193 while ((vstack = FcVStackPop (parse)))
24330d27 1194 {
c2e7c611
KP
1195 switch (vstack->tag) {
1196 case FcVStackFamily:
1197 if (family)
179c3995
KP
1198 {
1199 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1200 if (!new)
1201 FcConfigMessage (parse, FcSevereError, "out of memory");
1202 else
1203 family = new;
1204 }
1205 else
1206 new = vstack->u.expr;
1207 if (new)
1208 {
1209 family = new;
1210 vstack->tag = FcVStackNone;
1211 }
c2e7c611
KP
1212 break;
1213 case FcVStackPrefer:
1214 if (prefer)
1215 FcExprDestroy (prefer);
1216 prefer = vstack->u.expr;
1217 vstack->tag = FcVStackNone;
1218 break;
1219 case FcVStackAccept:
1220 if (accept)
1221 FcExprDestroy (accept);
1222 accept = vstack->u.expr;
1223 vstack->tag = FcVStackNone;
1224 break;
1225 case FcVStackDefault:
1226 if (def)
1227 FcExprDestroy (def);
1228 def = vstack->u.expr;
1229 vstack->tag = FcVStackNone;
1230 break;
1231 default:
179c3995 1232 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1233 break;
1234 }
1235 FcVStackDestroy (vstack);
24330d27 1236 }
ccb3e93b 1237 if (!family)
c2e7c611 1238 {
179c3995
KP
1239 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1240 if (prefer)
1241 FcExprDestroy (prefer);
1242 if (accept)
1243 FcExprDestroy (accept);
1244 if (def)
1245 FcExprDestroy (def);
c2e7c611
KP
1246 return;
1247 }
24330d27
KP
1248 if (prefer)
1249 {
1250 edit = FcEditCreate (FcConfigSaveField ("family"),
1251 FcOpPrepend,
6fff2cda
KP
1252 prefer,
1253 FcValueBindingWeak);
24330d27
KP
1254 if (edit)
1255 edit->next = 0;
c2e7c611
KP
1256 else
1257 FcExprDestroy (prefer);
24330d27
KP
1258 }
1259 if (accept)
1260 {
1261 next = edit;
1262 edit = FcEditCreate (FcConfigSaveField ("family"),
1263 FcOpAppend,
6fff2cda
KP
1264 accept,
1265 FcValueBindingWeak);
24330d27
KP
1266 if (edit)
1267 edit->next = next;
c2e7c611
KP
1268 else
1269 FcExprDestroy (accept);
24330d27
KP
1270 }
1271 if (def)
1272 {
1273 next = edit;
1274 edit = FcEditCreate (FcConfigSaveField ("family"),
6fff2cda
KP
1275 FcOpAppendLast,
1276 def,
1277 FcValueBindingWeak);
24330d27
KP
1278 if (edit)
1279 edit->next = next;
c2e7c611
KP
1280 else
1281 FcExprDestroy (def);
24330d27
KP
1282 }
1283 if (edit)
1284 {
938bc633
KP
1285 test = FcTestCreate (FcMatchPattern,
1286 FcQualAny,
2623c1eb 1287 (FcChar8 *) FC_FAMILY,
24330d27
KP
1288 FcOpEqual,
1289 family);
1290 if (test)
c2e7c611
KP
1291 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1292 FcTestDestroy (test);
24330d27 1293 }
c2e7c611
KP
1294 else
1295 FcExprDestroy (family);
24330d27
KP
1296}
1297
c2e7c611
KP
1298static FcExpr *
1299FcPopExpr (FcConfigParse *parse)
24330d27 1300{
c2e7c611
KP
1301 FcVStack *vstack = FcVStackPop (parse);
1302 FcExpr *expr = 0;
1303 if (!vstack)
1304 return 0;
1305 switch (vstack->tag) {
1306 case FcVStackNone:
1307 break;
1308 case FcVStackString:
1309 case FcVStackFamily:
bbbaac36
KP
1310 expr = FcExprCreateString (vstack->u.string);
1311 break;
c2e7c611 1312 case FcVStackField:
bbbaac36
KP
1313 expr = FcExprCreateField ((char *) vstack->u.string);
1314 break;
c2e7c611 1315 case FcVStackConstant:
bbbaac36 1316 expr = FcExprCreateConst (vstack->u.string);
c2e7c611 1317 break;
34cd0514
CW
1318 case FcVStackGlob:
1319 /* XXX: What's the correct action here? (CDW) */
1320 break;
c2e7c611
KP
1321 case FcVStackPrefer:
1322 case FcVStackAccept:
1323 case FcVStackDefault:
1324 expr = vstack->u.expr;
1325 vstack->tag = FcVStackNone;
1326 break;
1327 case FcVStackInteger:
1328 expr = FcExprCreateInteger (vstack->u.integer);
1329 break;
1330 case FcVStackDouble:
1331 expr = FcExprCreateDouble (vstack->u._double);
1332 break;
1333 case FcVStackMatrix:
1334 expr = FcExprCreateMatrix (vstack->u.matrix);
1335 break;
1336 case FcVStackBool:
1337 expr = FcExprCreateBool (vstack->u.bool);
1338 break;
1339 case FcVStackTest:
1340 break;
1341 case FcVStackExpr:
1342 expr = vstack->u.expr;
8ec077f2 1343 vstack->tag = FcVStackNone;
c2e7c611
KP
1344 break;
1345 case FcVStackEdit:
1346 break;
4f27c1c0
KP
1347 default:
1348 break;
c2e7c611
KP
1349 }
1350 FcVStackDestroy (vstack);
1351 return expr;
1352}
1353
3f7653c2
KP
1354/*
1355 * This builds a tree of binary operations. Note
1356 * that every operator is defined so that if only
1357 * a single operand is contained, the value of the
1358 * whole expression is the value of the operand.
1359 *
1360 * This code reduces in that case to returning that
1361 * operand.
1362 */
c2e7c611 1363static FcExpr *
3f7653c2 1364FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1365{
1366 FcExpr *left, *expr = 0, *new;
24330d27 1367
c2e7c611 1368 while ((left = FcPopExpr (parse)))
24330d27 1369 {
c2e7c611 1370 if (expr)
24330d27 1371 {
c2e7c611
KP
1372 new = FcExprCreateOp (left, op, expr);
1373 if (!new)
1374 {
179c3995 1375 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1376 FcExprDestroy (left);
1377 FcExprDestroy (expr);
24330d27 1378 break;
c2e7c611
KP
1379 }
1380 expr = new;
24330d27 1381 }
c2e7c611
KP
1382 else
1383 expr = left;
1384 }
1385 return expr;
1386}
1387
1388static void
3f7653c2
KP
1389FcParseBinary (FcConfigParse *parse, FcOp op)
1390{
1391 FcExpr *expr = FcPopBinary (parse, op);
1392 if (expr)
1393 FcVStackPushExpr (parse, FcVStackExpr, expr);
1394}
1395
1396/*
1397 * This builds a a unary operator, it consumes only
1398 * a single operand
1399 */
1400
1401static FcExpr *
1402FcPopUnary (FcConfigParse *parse, FcOp op)
1403{
1404 FcExpr *operand, *new = 0;
1405
1406 if ((operand = FcPopExpr (parse)))
1407 {
1408 new = FcExprCreateOp (operand, op, 0);
1409 if (!new)
1410 {
1411 FcExprDestroy (operand);
1412 FcConfigMessage (parse, FcSevereError, "out of memory");
1413 }
1414 }
1415 return new;
1416}
1417
1418static void
1419FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1420{
3f7653c2 1421 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1422 if (expr)
1423 FcVStackPushExpr (parse, FcVStackExpr, expr);
1424}
1425
1426static void
1427FcParseInclude (FcConfigParse *parse)
1428{
1429 FcChar8 *s;
1430 const FcChar8 *i;
1431 FcBool ignore_missing = FcFalse;
1432
1433 s = FcStrBufDone (&parse->pstack->str);
1434 if (!s)
1435 {
179c3995 1436 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1437 return;
1438 }
1439 i = FcConfigGetAttribute (parse, "ignore_missing");
1440 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1441 ignore_missing = FcTrue;
24c90386 1442 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1443 parse->error = FcTrue;
9dac3c59 1444 FcStrFree (s);
c2e7c611
KP
1445}
1446
1447typedef struct _FcOpMap {
1448 char *name;
1449 FcOp op;
1450} FcOpMap;
1451
1452static FcOp
1453FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1454{
1455 int i;
1456
1457 for (i = 0; i < nmap; i++)
1458 if (!strcmp ((char *) op, map[i].name))
1459 return map[i].op;
1460 return FcOpInvalid;
1461}
1462
1463static const FcOpMap fcCompareOps[] = {
1464 { "eq", FcOpEqual },
1465 { "not_eq", FcOpNotEqual },
1466 { "less", FcOpLess },
1467 { "less_eq", FcOpLessEqual },
1468 { "more", FcOpMore },
47d4f950
KP
1469 { "more_eq", FcOpMoreEqual },
1470 { "contains", FcOpContains },
1471 { "not_contains", FcOpNotContains }
c2e7c611
KP
1472};
1473
1474#define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1475
1476static FcOp
1477FcConfigLexCompare (const FcChar8 *compare)
1478{
1479 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1480}
1481
1482
1483static void
1484FcParseTest (FcConfigParse *parse)
1485{
938bc633
KP
1486 const FcChar8 *kind_string;
1487 FcMatchKind kind;
c2e7c611
KP
1488 const FcChar8 *qual_string;
1489 FcQual qual;
1490 const FcChar8 *name;
1491 const FcChar8 *compare_string;
1492 FcOp compare;
1493 FcExpr *expr;
1494 FcTest *test;
1495
938bc633
KP
1496 kind_string = FcConfigGetAttribute (parse, "target");
1497 if (!kind_string)
1498 kind = FcMatchDefault;
1499 else
1500 {
1501 if (!strcmp ((char *) kind_string, "pattern"))
1502 kind = FcMatchPattern;
1503 else if (!strcmp ((char *) kind_string, "font"))
1504 kind = FcMatchFont;
1505 else if (!strcmp ((char *) kind_string, "default"))
1506 kind = FcMatchDefault;
1507 else
1508 {
1509 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1510 return;
1511 }
1512 }
c2e7c611
KP
1513 qual_string = FcConfigGetAttribute (parse, "qual");
1514 if (!qual_string)
1515 qual = FcQualAny;
1516 else
1517 {
1518 if (!strcmp ((char *) qual_string, "any"))
1519 qual = FcQualAny;
1520 else if (!strcmp ((char *) qual_string, "all"))
1521 qual = FcQualAll;
6f6563ed
KP
1522 else if (!strcmp ((char *) qual_string, "first"))
1523 qual = FcQualFirst;
1524 else if (!strcmp ((char *) qual_string, "not_first"))
1525 qual = FcQualNotFirst;
c2e7c611 1526 else
24330d27 1527 {
179c3995 1528 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1529 return;
24330d27 1530 }
c2e7c611
KP
1531 }
1532 name = FcConfigGetAttribute (parse, "name");
1533 if (!name)
1534 {
179c3995 1535 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1536 return;
c2e7c611
KP
1537 }
1538 compare_string = FcConfigGetAttribute (parse, "compare");
1539 if (!compare_string)
1540 compare = FcOpEqual;
1541 else
1542 {
1543 compare = FcConfigLexCompare (compare_string);
1544 if (compare == FcOpInvalid)
24330d27 1545 {
179c3995 1546 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1547 return;
24330d27 1548 }
c2e7c611 1549 }
3f7653c2 1550 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1551 if (!expr)
1552 {
179c3995 1553 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1554 return;
1555 }
938bc633 1556 test = FcTestCreate (kind, qual, name, compare, expr);
c2e7c611
KP
1557 if (!test)
1558 {
179c3995 1559 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1560 return;
1561 }
1562 FcVStackPushTest (parse, test);
1563}
1564
1565static const FcOpMap fcModeOps[] = {
1566 { "assign", FcOpAssign },
1567 { "assign_replace", FcOpAssignReplace },
1568 { "prepend", FcOpPrepend },
1569 { "prepend_first", FcOpPrependFirst },
1570 { "append", FcOpAppend },
1571 { "append_last", FcOpAppendLast },
1572};
1573
1574#define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1575
1576static FcOp
1577FcConfigLexMode (const FcChar8 *mode)
1578{
1579 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1580}
1581
1582static void
1583FcParseEdit (FcConfigParse *parse)
1584{
1585 const FcChar8 *name;
1586 const FcChar8 *mode_string;
6fff2cda 1587 const FcChar8 *binding_string;
c2e7c611 1588 FcOp mode;
6fff2cda 1589 FcValueBinding binding;
c2e7c611
KP
1590 FcExpr *expr;
1591 FcEdit *edit;
1592
1593 name = FcConfigGetAttribute (parse, "name");
1594 if (!name)
1595 {
179c3995 1596 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1597 return;
c2e7c611
KP
1598 }
1599 mode_string = FcConfigGetAttribute (parse, "mode");
1600 if (!mode_string)
8ec077f2 1601 mode = FcOpAssign;
c2e7c611
KP
1602 else
1603 {
1604 mode = FcConfigLexMode (mode_string);
1605 if (mode == FcOpInvalid)
24330d27 1606 {
179c3995 1607 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1608 return;
24330d27 1609 }
c2e7c611 1610 }
6fff2cda
KP
1611 binding_string = FcConfigGetAttribute (parse, "binding");
1612 if (!binding_string)
1613 binding = FcValueBindingWeak;
1614 else
1615 {
1616 if (!strcmp ((char *) binding_string, "weak"))
1617 binding = FcValueBindingWeak;
1618 else if (!strcmp ((char *) binding_string, "strong"))
1619 binding = FcValueBindingStrong;
dda7794f
KP
1620 else if (!strcmp ((char *) binding_string, "same"))
1621 binding = FcValueBindingSame;
6fff2cda
KP
1622 else
1623 {
1624 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1625 return;
1626 }
1627 }
3f7653c2 1628 expr = FcPopBinary (parse, FcOpComma);
6fff2cda 1629 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
c2e7c611
KP
1630 if (!edit)
1631 {
179c3995 1632 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1633 FcExprDestroy (expr);
1634 return;
1635 }
1636 if (!FcVStackPushEdit (parse, edit))
1637 FcEditDestroy (edit);
1638}
1639
1640static void
1641FcParseMatch (FcConfigParse *parse)
1642{
1643 const FcChar8 *kind_name;
1644 FcMatchKind kind;
1645 FcTest *test = 0;
1646 FcEdit *edit = 0;
1647 FcVStack *vstack;
1648
1649 kind_name = FcConfigGetAttribute (parse, "target");
1650 if (!kind_name)
1651 kind = FcMatchPattern;
1652 else
1653 {
1654 if (!strcmp ((char *) kind_name, "pattern"))
1655 kind = FcMatchPattern;
1656 else if (!strcmp ((char *) kind_name, "font"))
1657 kind = FcMatchFont;
1658 else
24330d27 1659 {
179c3995 1660 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1661 return;
24330d27 1662 }
c2e7c611
KP
1663 }
1664 while ((vstack = FcVStackPop (parse)))
1665 {
1666 switch (vstack->tag) {
1667 case FcVStackTest:
1668 vstack->u.test->next = test;
1669 test = vstack->u.test;
1670 vstack->tag = FcVStackNone;
1671 break;
1672 case FcVStackEdit:
1673 vstack->u.edit->next = edit;
1674 edit = vstack->u.edit;
1675 vstack->tag = FcVStackNone;
1676 break;
1677 default:
179c3995 1678 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
1679 break;
1680 }
1681 FcVStackDestroy (vstack);
1682 }
1683 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 1684 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1685}
1686
d47c9d6e
KP
1687static void
1688FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1689{
1690 FcVStack *vstack;
1691
1692 while ((vstack = FcVStackPop (parse)))
1693 {
1694 switch (vstack->tag) {
1695 case FcVStackGlob:
1696 if (!FcConfigGlobAdd (parse->config,
1697 vstack->u.string,
1698 element == FcElementAcceptfont))
1699 {
1700 FcConfigMessage (parse, FcSevereError, "out of memory");
1701 }
1702 break;
4f27c1c0
KP
1703 case FcVStackPattern:
1704 if (!FcConfigPatternsAdd (parse->config,
1705 vstack->u.pattern,
1706 element == FcElementAcceptfont))
1707 {
1708 FcConfigMessage (parse, FcSevereError, "out of memory");
1709 }
1710 else
1711 vstack->tag = FcVStackNone;
1712 break;
d47c9d6e
KP
1713 default:
1714 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1715 break;
1716 }
1717 FcVStackDestroy (vstack);
1718 }
1719}
1720
4f27c1c0
KP
1721
1722static FcValue
1723FcPopValue (FcConfigParse *parse)
1724{
1725 FcVStack *vstack = FcVStackPop (parse);
1726 FcValue value;
1727
1728 value.type = FcTypeVoid;
1729
1730 if (!vstack)
1731 return value;
1732
1733 switch (vstack->tag) {
1734 case FcVStackString:
1735 value.u.s = FcStrCopy (vstack->u.string);
1736 if (value.u.s)
1737 value.type = FcTypeString;
1738 break;
1739 case FcVStackConstant:
1740 if (FcNameConstant (vstack->u.string, &value.u.i))
1741 value.type = FcTypeInteger;
1742 break;
1743 case FcVStackInteger:
1744 value.u.i = vstack->u.integer;
1745 value.type = FcTypeInteger;
1746 break;
1747 case FcVStackDouble:
1748 value.u.d = vstack->u._double;
1749 value.type = FcTypeInteger;
1750 break;
1751 case FcVStackMatrix:
1752 value.u.m = FcMatrixCopy (vstack->u.matrix);
1753 if (value.u.m)
1754 value.type = FcTypeMatrix;
1755 break;
1756 case FcVStackBool:
1757 value.u.b = vstack->u.bool;
1758 value.type = FcTypeBool;
1759 break;
1760 default:
1761 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
1762 vstack->tag);
1763 break;
1764 }
1765 FcVStackDestroy (vstack);
1766
1767 return value;
1768}
1769
1770static void
1771FcParsePatelt (FcConfigParse *parse)
1772{
1773 FcValue value;
1774 FcPattern *pattern = FcPatternCreate ();
1775 const char *name;
1776
1777 if (!pattern)
1778 {
1779 FcConfigMessage (parse, FcSevereError, "out of memory");
1780 return;
1781 }
1782
1783 name = FcConfigGetAttribute (parse, "name");
1784 if (!name)
1785 {
1786 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1787 return;
1788 }
4f27c1c0
KP
1789
1790 for (;;)
1791 {
1792 value = FcPopValue (parse);
1793 if (value.type == FcTypeVoid)
1794 break;
1795 if (!FcPatternAdd (pattern, name, value, FcTrue))
1796 {
1797 FcConfigMessage (parse, FcSevereError, "out of memory");
1798 break;
1799 }
1800 }
1801
1802 FcVStackPushPattern (parse, pattern);
1803}
1804
1805static void
1806FcParsePattern (FcConfigParse *parse)
1807{
1808 FcVStack *vstack;
1809 FcPattern *pattern = FcPatternCreate ();
1810
1811 if (!pattern)
1812 {
1813 FcConfigMessage (parse, FcSevereError, "out of memory");
1814 return;
1815 }
1816
1817 while ((vstack = FcVStackPop (parse)))
1818 {
1819 switch (vstack->tag) {
1820 case FcVStackPattern:
1821 if (!FcPatternAppend (pattern, vstack->u.pattern))
1822 {
1823 FcConfigMessage (parse, FcSevereError, "out of memory");
1824 return;
1825 }
1826 break;
1827 default:
1828 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1829 break;
1830 }
1831 FcVStackDestroy (vstack);
1832 }
1833
1834 FcVStackPushPattern (parse, pattern);
1835}
1836
c2e7c611
KP
1837static void
1838FcEndElement(void *userData, const XML_Char *name)
1839{
1840 FcConfigParse *parse = userData;
1841 FcChar8 *data;
1842
1843 if (!parse->pstack)
1844 return;
1845 switch (parse->pstack->element) {
1846 case FcElementNone:
1847 break;
1848 case FcElementFontconfig:
1849 break;
1850 case FcElementDir:
1851 data = FcStrBufDone (&parse->pstack->str);
1852 if (!data)
24330d27 1853 {
179c3995 1854 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1855 break;
24330d27 1856 }
daeed6e0
TL
1857#ifdef _WIN32
1858 if (strcmp (data, "WINDOWSFONTDIR") == 0)
1859 {
1860 int rc;
1861 FcStrFree (data);
1862 data = malloc (1000);
1863 if (!data)
1864 {
1865 FcConfigMessage (parse, FcSevereError, "out of memory");
1866 break;
1867 }
1868 FcMemAlloc (FC_MEM_STRING, 1000);
1869 rc = GetWindowsDirectory (data, 800);
1870 if (rc == 0 || rc > 800)
1871 {
1872 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
1873 FcStrFree (data);
1874 break;
1875 }
1876 if (data [strlen (data) - 1] != '\\')
1877 strcat (data, "\\");
1878 strcat (data, "fonts");
1879 }
1880#endif
ff3f1f98
KP
1881 if (!FcStrUsesHome (data) || FcConfigHome ())
1882 {
1883 if (!FcConfigAddDir (parse->config, data))
1884 FcConfigMessage (parse, FcSevereError, "out of memory");
1885 }
9dac3c59 1886 FcStrFree (data);
c2e7c611
KP
1887 break;
1888 case FcElementCache:
1889 data = FcStrBufDone (&parse->pstack->str);
1890 if (!data)
24330d27 1891 {
179c3995 1892 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 1893 break;
c2e7c611 1894 }
ff3f1f98
KP
1895 if (!FcStrUsesHome (data) || FcConfigHome ())
1896 {
1897 if (!FcConfigSetCache (parse->config, data))
1898 FcConfigMessage (parse, FcSevereError, "out of memory");
1899 }
9dac3c59 1900 FcStrFree (data);
c2e7c611
KP
1901 break;
1902 case FcElementInclude:
1903 FcParseInclude (parse);
1904 break;
1905 case FcElementConfig:
1906 break;
1907 case FcElementMatch:
1908 FcParseMatch (parse);
1909 break;
1910 case FcElementAlias:
1911 FcParseAlias (parse);
1912 break;
1913
1914 case FcElementBlank:
1915 FcParseBlank (parse);
1916 break;
179c3995
KP
1917 case FcElementRescan:
1918 FcParseRescan (parse);
1919 break;
c2e7c611
KP
1920
1921 case FcElementPrefer:
1922 FcParseFamilies (parse, FcVStackPrefer);
1923 break;
1924 case FcElementAccept:
1925 FcParseFamilies (parse, FcVStackAccept);
1926 break;
1927 case FcElementDefault:
1928 FcParseFamilies (parse, FcVStackDefault);
1929 break;
1930 case FcElementFamily:
1931 FcParseFamily (parse);
1932 break;
1933
1934 case FcElementTest:
1935 FcParseTest (parse);
1936 break;
1937 case FcElementEdit:
1938 FcParseEdit (parse);
1939 break;
1940
1941 case FcElementInt:
1942 FcParseInt (parse);
1943 break;
1944 case FcElementDouble:
1945 FcParseDouble (parse);
1946 break;
1947 case FcElementString:
1948 FcParseString (parse, FcVStackString);
1949 break;
1950 case FcElementMatrix:
1951 FcParseMatrix (parse);
1952 break;
1953 case FcElementBool:
1954 FcParseBool (parse);
1955 break;
1956 case FcElementCharset:
1957/* FcParseCharset (parse); */
1958 break;
d47c9d6e
KP
1959 case FcElementSelectfont:
1960 break;
1961 case FcElementAcceptfont:
1962 case FcElementRejectfont:
1963 FcParseAcceptRejectFont (parse, parse->pstack->element);
1964 break;
1965 case FcElementGlob:
1966 FcParseString (parse, FcVStackGlob);
1967 break;
4f27c1c0
KP
1968 case FcElementPattern:
1969 FcParsePattern (parse);
1970 break;
1971 case FcElementPatelt:
1972 FcParsePatelt (parse);
1973 break;
c2e7c611
KP
1974 case FcElementName:
1975 FcParseString (parse, FcVStackField);
1976 break;
1977 case FcElementConst:
1978 FcParseString (parse, FcVStackConstant);
1979 break;
1980 case FcElementOr:
3f7653c2 1981 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
1982 break;
1983 case FcElementAnd:
3f7653c2 1984 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
1985 break;
1986 case FcElementEq:
3f7653c2 1987 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
1988 break;
1989 case FcElementNotEq:
3f7653c2 1990 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
1991 break;
1992 case FcElementLess:
3f7653c2 1993 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
1994 break;
1995 case FcElementLessEq:
3f7653c2 1996 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
1997 break;
1998 case FcElementMore:
3f7653c2 1999 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2000 break;
2001 case FcElementMoreEq:
3f7653c2 2002 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2003 break;
47d4f950 2004 case FcElementContains:
3f7653c2 2005 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2006 break;
2007 case FcElementNotContains:
3f7653c2 2008 FcParseBinary (parse, FcOpNotContains);
47d4f950 2009 break;
c2e7c611 2010 case FcElementPlus:
3f7653c2 2011 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2012 break;
2013 case FcElementMinus:
3f7653c2 2014 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2015 break;
2016 case FcElementTimes:
3f7653c2 2017 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2018 break;
2019 case FcElementDivide:
3f7653c2 2020 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2021 break;
2022 case FcElementNot:
3f7653c2 2023 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2024 break;
2025 case FcElementIf:
3f7653c2
KP
2026 FcParseBinary (parse, FcOpQuest);
2027 break;
2028 case FcElementFloor:
2029 FcParseUnary (parse, FcOpFloor);
2030 break;
2031 case FcElementCeil:
2032 FcParseUnary (parse, FcOpCeil);
2033 break;
2034 case FcElementRound:
2035 FcParseUnary (parse, FcOpRound);
2036 break;
2037 case FcElementTrunc:
2038 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2039 break;
2040 case FcElementUnknown:
2041 break;
24330d27 2042 }
c2e7c611
KP
2043 (void) FcPStackPop (parse);
2044}
2045
2046static void
2047FcCharacterData (void *userData, const XML_Char *s, int len)
2048{
2049 FcConfigParse *parse = userData;
2050
2051 if (!parse->pstack)
2052 return;
2053 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2054 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2055}
2056
2057static void
2058FcStartDoctypeDecl (void *userData,
2059 const XML_Char *doctypeName,
2060 const XML_Char *sysid,
2061 const XML_Char *pubid,
2062 int has_internal_subset)
2063{
2064 FcConfigParse *parse = userData;
2065
2066 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2067 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2068}
2069
2070static void
2071FcEndDoctypeDecl (void *userData)
2072{
24330d27
KP
2073}
2074
2d9c79c0
KP
2075static FcBool
2076FcConfigParseAndLoadDir (FcConfig *config,
2077 const FcChar8 *name,
2078 const FcChar8 *dir,
2079 FcBool complain)
2080{
2081 DIR *d;
2082 struct dirent *e;
2083 FcBool ret = FcTrue;
2084 FcChar8 *file;
2085 FcChar8 *base;
2086 FcStrSet *files;
2087
2088 d = opendir ((char *) dir);
2089 if (!d)
2090 {
2091 if (complain)
2092 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2093 name);
2094 ret = FcFalse;
2095 goto bail0;
2096 }
2097 /* freed below */
2098 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2099 if (!file)
2100 {
2101 ret = FcFalse;
2102 goto bail1;
2103 }
2104
2105 strcpy ((char *) file, (char *) dir);
2106 strcat ((char *) file, "/");
2107 base = file + strlen ((char *) file);
2108
2109 files = FcStrSetCreate ();
2110 if (!files)
2111 {
2112 ret = FcFalse;
2113 goto bail2;
2114 }
2115
2116 if (FcDebug () & FC_DBG_CONFIG)
2117 printf ("\tScanning config dir %s\n", dir);
2118
2119 while (ret && (e = readdir (d)))
2120 {
2121 /*
2122 * Add all files of the form [0-9]*
2123 */
2124 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2125 strlen (e->d_name) < FC_MAX_FILE_LEN)
2126 {
2127 strcpy ((char *) base, (char *) e->d_name);
2128 if (!FcStrSetAdd (files, file))
2129 {
2130 ret = FcFalse;
2131 goto bail3;
2132 }
2133 }
2134 }
2135 if (ret)
2136 {
2137 int i;
2138 qsort (files->strs, files->num, sizeof (FcChar8 *),
2139 (int (*)(const void *, const void *)) FcStrCmp);
2140 for (i = 0; ret && i < files->num; i++)
2141 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2142 }
2143bail3:
2144 FcStrSetDestroy (files);
2145bail2:
2146 free (file);
2147bail1:
2148 closedir (d);
2149bail0:
2150 return ret || !complain;
2151}
2152
24330d27
KP
2153FcBool
2154FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2155 const FcChar8 *name,
24330d27
KP
2156 FcBool complain)
2157{
24330d27 2158
c2e7c611
KP
2159 XML_Parser p;
2160 FcChar8 *filename;
2161 FILE *f;
2162 int len;
2163 void *buf;
2164 FcConfigParse parse;
2165 FcBool error = FcTrue;
2166
2167 filename = FcConfigFilename (name);
2168 if (!filename)
2169 goto bail0;
4aded3e0
KP
2170
2171 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2172 {
2173 FcStrFree (filename);
4aded3e0 2174 goto bail0;
9dac3c59 2175 }
4aded3e0 2176
2d9c79c0
KP
2177 if (FcFileIsDir (filename))
2178 {
2179 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2180 FcStrFree (filename);
2181 return ret;
2182 }
2183
2184 if (FcDebug () & FC_DBG_CONFIG)
2185 printf ("\tLoading config file %s\n", filename);
2186
c2e7c611 2187 f = fopen ((char *) filename, "r");
9dac3c59 2188 FcStrFree (filename);
c2e7c611
KP
2189 if (!f)
2190 goto bail0;
2191
2192 p = XML_ParserCreate ("UTF-8");
2193 if (!p)
2194 goto bail1;
2195
2196 if (!FcConfigInit (&parse, name, config, p))
2197 goto bail2;
2198
2199 XML_SetUserData (p, &parse);
2200
2201 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2202 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2203 XML_SetCharacterDataHandler (p, FcCharacterData);
2204
2205 do {
2206 buf = XML_GetBuffer (p, BUFSIZ);
2207 if (!buf)
80c053b7 2208 {
179c3995 2209 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2210 goto bail3;
80c053b7 2211 }
c2e7c611
KP
2212 len = fread (buf, 1, BUFSIZ, f);
2213 if (len < 0)
80c053b7 2214 {
179c3995 2215 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2216 goto bail3;
80c053b7 2217 }
c2e7c611 2218 if (!XML_ParseBuffer (p, len, len == 0))
80c053b7 2219 {
179c3995 2220 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2221 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2222 goto bail3;
80c053b7 2223 }
c2e7c611
KP
2224 } while (len != 0);
2225 error = parse.error;
2226bail3:
2227 FcConfigCleanup (&parse);
2228bail2:
2229 XML_ParserFree (p);
2230bail1:
2231 fclose (f);
2232bail0:
2233 if (error && complain)
24330d27 2234 {
c2e7c611 2235 if (name)
179c3995 2236 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2237 else
179c3995 2238 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2239 return FcFalse;
2240 }
2241 return FcTrue;
2242}