]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Add the range support in blank element
[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
5aaf466d 10 * documentation, and that the name of the author(s) not be used in
24330d27 11 * advertising or publicity pertaining to distribution of the software without
5aaf466d 12 * specific, written prior permission. The authors make no
24330d27
KP
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24330d27 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3074a73b 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24330d27
KP
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 55#ifdef _WIN32
a1b6e34a 56#define _WIN32_WINNT 0x0500
daeed6e0
TL
57#define STRICT
58#include <windows.h>
59#undef STRICT
8b1ceef0 60#include <mbstring.h>
daeed6e0
TL
61#endif
62
398d4364
BE
63static void
64FcExprDestroy (FcExpr *e);
24330d27
KP
65
66void
67FcTestDestroy (FcTest *test)
68{
69 if (test->next)
70 FcTestDestroy (test->next);
71 FcExprDestroy (test->expr);
9dac3c59 72 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
24330d27
KP
73 free (test);
74}
75
a96ecbfa 76static FcExpr *
390c05e6 77FcExprCreateInteger (FcConfig *config, int i)
24330d27 78{
390c05e6 79 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
80 if (e)
81 {
82 e->op = FcOpInteger;
83 e->u.ival = i;
84 }
85 return e;
86}
87
398d4364 88static FcExpr *
390c05e6 89FcExprCreateDouble (FcConfig *config, double d)
24330d27 90{
390c05e6 91 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
92 if (e)
93 {
94 e->op = FcOpDouble;
95 e->u.dval = d;
96 }
97 return e;
98}
99
398d4364 100static FcExpr *
390c05e6 101FcExprCreateString (FcConfig *config, const FcChar8 *s)
24330d27 102{
390c05e6 103 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
104 if (e)
105 {
106 e->op = FcOpString;
3164ac76 107 e->u.sval = FcStrStaticName (s);
24330d27
KP
108 }
109 return e;
110}
111
398d4364 112static FcExpr *
390c05e6 113FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
24330d27 114{
390c05e6 115 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
116 if (e)
117 {
118 e->op = FcOpMatrix;
119 e->u.mval = FcMatrixCopy (m);
120 }
121 return e;
122}
123
398d4364 124static FcExpr *
390c05e6 125FcExprCreateBool (FcConfig *config, FcBool b)
24330d27 126{
390c05e6 127 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
128 if (e)
129 {
130 e->op = FcOpBool;
131 e->u.bval = b;
132 }
133 return e;
134}
135
857b7efe
AT
136static FcExpr *
137FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
138{
139 FcExpr *e = FcConfigAllocExpr (config);
140 if (e)
141 {
142 e->op = FcOpCharSet;
143 e->u.cval = FcCharSetCopy (charset);
144 }
145 return e;
146}
147
398d4364 148static FcExpr *
390c05e6 149FcExprCreateField (FcConfig *config, const char *field)
24330d27 150{
390c05e6 151 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
152 if (e)
153 {
154 e->op = FcOpField;
7ce19673 155 e->u.object = FcObjectFromName (field);
24330d27
KP
156 }
157 return e;
158}
159
398d4364 160static FcExpr *
390c05e6 161FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
24330d27 162{
390c05e6 163 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
164 if (e)
165 {
166 e->op = FcOpConst;
3164ac76 167 e->u.constant = FcStrStaticName (constant);
24330d27
KP
168 }
169 return e;
170}
171
398d4364 172static FcExpr *
390c05e6 173FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
24330d27 174{
390c05e6 175 FcExpr *e = FcConfigAllocExpr (config);
24330d27
KP
176 if (e)
177 {
178 e->op = op;
179 e->u.tree.left = left;
180 e->u.tree.right = right;
181 }
182 return e;
183}
184
398d4364 185static void
24330d27
KP
186FcExprDestroy (FcExpr *e)
187{
3f7653c2
KP
188 if (!e)
189 return;
24330d27
KP
190 switch (e->op) {
191 case FcOpInteger:
192 break;
193 case FcOpDouble:
194 break;
195 case FcOpString:
24330d27
KP
196 break;
197 case FcOpMatrix:
198 FcMatrixFree (e->u.mval);
199 break;
857b7efe
AT
200 case FcOpRange:
201 break;
24330d27
KP
202 case FcOpCharSet:
203 FcCharSetDestroy (e->u.cval);
204 break;
205 case FcOpBool:
206 break;
207 case FcOpField:
24330d27
KP
208 break;
209 case FcOpConst:
24330d27
KP
210 break;
211 case FcOpAssign:
212 case FcOpAssignReplace:
213 case FcOpPrepend:
214 case FcOpPrependFirst:
215 case FcOpAppend:
216 case FcOpAppendLast:
217 break;
218 case FcOpOr:
219 case FcOpAnd:
220 case FcOpEqual:
24330d27
KP
221 case FcOpNotEqual:
222 case FcOpLess:
223 case FcOpLessEqual:
224 case FcOpMore:
225 case FcOpMoreEqual:
47d4f950 226 case FcOpContains:
74a623e0 227 case FcOpListing:
47d4f950 228 case FcOpNotContains:
24330d27
KP
229 case FcOpPlus:
230 case FcOpMinus:
231 case FcOpTimes:
232 case FcOpDivide:
233 case FcOpQuest:
234 case FcOpComma:
235 FcExprDestroy (e->u.tree.right);
236 /* fall through */
237 case FcOpNot:
3f7653c2
KP
238 case FcOpFloor:
239 case FcOpCeil:
240 case FcOpRound:
241 case FcOpTrunc:
24330d27
KP
242 FcExprDestroy (e->u.tree.left);
243 break;
244 case FcOpNil:
245 case FcOpInvalid:
246 break;
247 }
390c05e6
BE
248
249 e->op = FcOpNil;
24330d27
KP
250}
251
24330d27
KP
252void
253FcEditDestroy (FcEdit *e)
254{
255 if (e->next)
256 FcEditDestroy (e->next);
24330d27
KP
257 if (e->expr)
258 FcExprDestroy (e->expr);
34cd0514 259 free (e);
24330d27
KP
260}
261
c2e7c611
KP
262typedef enum _FcElement {
263 FcElementNone,
264 FcElementFontconfig,
265 FcElementDir,
7410e40b 266 FcElementCacheDir,
c2e7c611
KP
267 FcElementCache,
268 FcElementInclude,
269 FcElementConfig,
270 FcElementMatch,
271 FcElementAlias,
272
273 FcElementBlank,
179c3995 274 FcElementRescan,
c2e7c611
KP
275
276 FcElementPrefer,
277 FcElementAccept,
278 FcElementDefault,
279 FcElementFamily,
280
d47c9d6e
KP
281 FcElementSelectfont,
282 FcElementAcceptfont,
283 FcElementRejectfont,
284 FcElementGlob,
4f27c1c0
KP
285 FcElementPattern,
286 FcElementPatelt,
d47c9d6e 287
c2e7c611
KP
288 FcElementTest,
289 FcElementEdit,
290 FcElementInt,
291 FcElementDouble,
292 FcElementString,
293 FcElementMatrix,
857b7efe 294 FcElementRange,
c2e7c611 295 FcElementBool,
857b7efe 296 FcElementCharSet,
c2e7c611
KP
297 FcElementName,
298 FcElementConst,
299 FcElementOr,
300 FcElementAnd,
301 FcElementEq,
302 FcElementNotEq,
303 FcElementLess,
304 FcElementLessEq,
305 FcElementMore,
306 FcElementMoreEq,
47d4f950
KP
307 FcElementContains,
308 FcElementNotContains,
c2e7c611
KP
309 FcElementPlus,
310 FcElementMinus,
311 FcElementTimes,
312 FcElementDivide,
313 FcElementNot,
314 FcElementIf,
3f7653c2
KP
315 FcElementFloor,
316 FcElementCeil,
317 FcElementRound,
318 FcElementTrunc,
c2e7c611
KP
319 FcElementUnknown
320} FcElement;
321
392fa276 322static const struct {
67accef4
PL
323 const char name[16];
324 FcElement element;
325} fcElementMap[] = {
326 { "fontconfig", FcElementFontconfig },
327 { "dir", FcElementDir },
7410e40b 328 { "cachedir", FcElementCacheDir },
67accef4
PL
329 { "cache", FcElementCache },
330 { "include", FcElementInclude },
331 { "config", FcElementConfig },
332 { "match", FcElementMatch },
333 { "alias", FcElementAlias },
2b0f3f11 334
67accef4
PL
335 { "blank", FcElementBlank },
336 { "rescan", FcElementRescan },
337
338 { "prefer", FcElementPrefer },
339 { "accept", FcElementAccept },
340 { "default", FcElementDefault },
341 { "family", FcElementFamily },
342
343 { "selectfont", FcElementSelectfont },
344 { "acceptfont", FcElementAcceptfont },
345 { "rejectfont", FcElementRejectfont },
346 { "glob", FcElementGlob },
347 { "pattern", FcElementPattern },
348 { "patelt", FcElementPatelt },
349
350 { "test", FcElementTest },
351 { "edit", FcElementEdit },
352 { "int", FcElementInt },
353 { "double", FcElementDouble },
354 { "string", FcElementString },
355 { "matrix", FcElementMatrix },
857b7efe 356 { "range", FcElementRange },
67accef4 357 { "bool", FcElementBool },
857b7efe 358 { "charset", FcElementCharSet },
67accef4
PL
359 { "name", FcElementName },
360 { "const", FcElementConst },
361 { "or", FcElementOr },
362 { "and", FcElementAnd },
363 { "eq", FcElementEq },
364 { "not_eq", FcElementNotEq },
365 { "less", FcElementLess },
366 { "less_eq", FcElementLessEq },
367 { "more", FcElementMore },
368 { "more_eq", FcElementMoreEq },
369 { "contains", FcElementContains },
370 { "not_contains", FcElementNotContains },
371 { "plus", FcElementPlus },
372 { "minus", FcElementMinus },
373 { "times", FcElementTimes },
374 { "divide", FcElementDivide },
375 { "not", FcElementNot },
376 { "if", FcElementIf },
377 { "floor", FcElementFloor },
378 { "ceil", FcElementCeil },
379 { "round", FcElementRound },
380 { "trunc", FcElementTrunc },
381};
382#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
383
c2e7c611
KP
384static FcElement
385FcElementMap (const XML_Char *name)
386{
c2e7c611
KP
387
388 int i;
67accef4 389 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
c2e7c611
KP
390 if (!strcmp ((char *) name, fcElementMap[i].name))
391 return fcElementMap[i].element;
392 return FcElementUnknown;
393}
394
395typedef struct _FcPStack {
396 struct _FcPStack *prev;
397 FcElement element;
398 FcChar8 **attr;
399 FcStrBuf str;
de69ee14 400 FcChar8 *attr_buf_static[16];
c2e7c611 401} FcPStack;
d0d1f390 402
c2e7c611
KP
403typedef enum _FcVStackTag {
404 FcVStackNone,
405
406 FcVStackString,
407 FcVStackFamily,
408 FcVStackField,
409 FcVStackConstant,
d47c9d6e 410 FcVStackGlob,
4f27c1c0 411 FcVStackPattern,
d0d1f390 412
c2e7c611
KP
413 FcVStackPrefer,
414 FcVStackAccept,
415 FcVStackDefault,
d0d1f390 416
c2e7c611
KP
417 FcVStackInteger,
418 FcVStackDouble,
419 FcVStackMatrix,
857b7efe 420 FcVStackRange,
c2e7c611 421 FcVStackBool,
857b7efe 422 FcVStackCharSet,
d0d1f390 423
c2e7c611
KP
424 FcVStackTest,
425 FcVStackExpr,
426 FcVStackEdit
427} FcVStackTag;
428
429typedef struct _FcVStack {
430 struct _FcVStack *prev;
431 FcPStack *pstack; /* related parse element */
432 FcVStackTag tag;
433 union {
434 FcChar8 *string;
435
436 int integer;
437 double _double;
438 FcMatrix *matrix;
857b7efe 439 FcRange range;
fe8e8a1d 440 FcBool bool_;
857b7efe 441 FcCharSet *charset;
c2e7c611
KP
442
443 FcTest *test;
444 FcQual qual;
445 FcOp op;
446 FcExpr *expr;
447 FcEdit *edit;
4f27c1c0
KP
448
449 FcPattern *pattern;
c2e7c611
KP
450 } u;
451} FcVStack;
452
453typedef struct _FcConfigParse {
454 FcPStack *pstack;
455 FcVStack *vstack;
456 FcBool error;
457 const FcChar8 *name;
458 FcConfig *config;
459 XML_Parser parser;
1d7b47da
BE
460 int pstack_static_used;
461 FcPStack pstack_static[8];
39861b7d
BE
462 int vstack_static_used;
463 FcVStack vstack_static[64];
c2e7c611
KP
464} FcConfigParse;
465
179c3995
KP
466typedef enum _FcConfigSeverity {
467 FcSevereInfo, FcSevereWarning, FcSevereError
468} FcConfigSeverity;
469
24330d27 470static void
67accef4 471FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
24330d27 472{
67accef4 473 const char *s = "unknown";
24330d27
KP
474 va_list args;
475
476 va_start (args, fmt);
179c3995
KP
477
478 switch (severe) {
479 case FcSevereInfo: s = "info"; break;
480 case FcSevereWarning: s = "warning"; break;
481 case FcSevereError: s = "error"; break;
482 }
c2e7c611
KP
483 if (parse)
484 {
485 if (parse->name)
179c3995 486 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
68355f38 487 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
c2e7c611 488 else
179c3995 489 fprintf (stderr, "Fontconfig %s: line %d: ", s,
68355f38 490 (int)XML_GetCurrentLineNumber (parse->parser));
179c3995
KP
491 if (severe >= FcSevereError)
492 parse->error = FcTrue;
c2e7c611
KP
493 }
494 else
179c3995 495 fprintf (stderr, "Fontconfig %s: ", s);
24330d27
KP
496 vfprintf (stderr, fmt, args);
497 fprintf (stderr, "\n");
498 va_end (args);
499}
500
ca60d2b5 501
67accef4 502static const char *
ca60d2b5
KP
503FcTypeName (FcType type)
504{
505 switch (type) {
506 case FcTypeVoid:
507 return "void";
508 case FcTypeInteger:
509 case FcTypeDouble:
510 return "number";
511 case FcTypeString:
512 return "string";
513 case FcTypeBool:
514 return "bool";
515 case FcTypeMatrix:
516 return "matrix";
517 case FcTypeCharSet:
518 return "charset";
519 case FcTypeFTFace:
520 return "FT_Face";
521 case FcTypeLangSet:
522 return "langset";
523 default:
524 return "unknown";
525 }
526}
527
528static void
529FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
530{
531 if (value == FcTypeInteger)
532 value = FcTypeDouble;
533 if (type == FcTypeInteger)
534 type = FcTypeDouble;
535 if (value != type)
536 {
537 if ((value == FcTypeLangSet && type == FcTypeString) ||
538 (value == FcTypeString && type == FcTypeLangSet))
539 return;
9a9fd975
KP
540 if (type == (FcType) -1)
541 return;
ca60d2b5
KP
542 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
543 FcTypeName (value), FcTypeName (type));
544 }
545}
546
547static void
548FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
549{
550 const FcObjectType *o;
551 const FcConstant *c;
d0d1f390 552
07e646cc
MF
553 /* If parsing the expression failed, some nodes may be NULL */
554 if (!expr)
555 return;
556
ca60d2b5
KP
557 switch (expr->op) {
558 case FcOpInteger:
559 case FcOpDouble:
560 FcTypecheckValue (parse, FcTypeDouble, type);
561 break;
562 case FcOpString:
563 FcTypecheckValue (parse, FcTypeString, type);
564 break;
565 case FcOpMatrix:
566 FcTypecheckValue (parse, FcTypeMatrix, type);
567 break;
568 case FcOpBool:
569 FcTypecheckValue (parse, FcTypeBool, type);
570 break;
571 case FcOpCharSet:
572 FcTypecheckValue (parse, FcTypeCharSet, type);
573 break;
574 case FcOpNil:
575 break;
576 case FcOpField:
7ce19673 577 o = FcNameGetObjectType (FcObjectName (expr->u.object));
ca60d2b5
KP
578 if (o)
579 FcTypecheckValue (parse, o->type, type);
580 break;
581 case FcOpConst:
582 c = FcNameGetConstant (expr->u.constant);
583 if (c)
584 {
585 o = FcNameGetObjectType (c->object);
586 if (o)
587 FcTypecheckValue (parse, o->type, type);
588 }
d0d1f390
BE
589 else
590 FcConfigMessage (parse, FcSevereWarning,
f28472fd
PL
591 "invalid constant used : %s",
592 expr->u.constant);
ca60d2b5
KP
593 break;
594 case FcOpQuest:
595 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
596 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
597 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
598 break;
599 case FcOpAssign:
600 case FcOpAssignReplace:
601 break;
602 case FcOpEqual:
603 case FcOpNotEqual:
604 case FcOpLess:
605 case FcOpLessEqual:
606 case FcOpMore:
607 case FcOpMoreEqual:
608 case FcOpContains:
609 case FcOpNotContains:
610 case FcOpListing:
611 FcTypecheckValue (parse, FcTypeBool, type);
612 break;
613 case FcOpComma:
614 case FcOpOr:
615 case FcOpAnd:
616 case FcOpPlus:
617 case FcOpMinus:
618 case FcOpTimes:
619 case FcOpDivide:
620 FcTypecheckExpr (parse, expr->u.tree.left, type);
621 FcTypecheckExpr (parse, expr->u.tree.right, type);
622 break;
623 case FcOpNot:
624 FcTypecheckValue (parse, FcTypeBool, type);
625 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
626 break;
627 case FcOpFloor:
628 case FcOpCeil:
629 case FcOpRound:
630 case FcOpTrunc:
631 FcTypecheckValue (parse, FcTypeDouble, type);
632 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
633 break;
634 default:
635 break;
636 }
637}
638
639static FcTest *
640FcTestCreate (FcConfigParse *parse,
d0d1f390 641 FcMatchKind kind,
ca60d2b5
KP
642 FcQual qual,
643 const FcChar8 *field,
644 FcOp compare,
645 FcExpr *expr)
646{
647 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
648
649 if (test)
650 {
651 const FcObjectType *o;
652
653 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
654 test->next = 0;
655 test->kind = kind;
656 test->qual = qual;
7ce19673 657 test->object = FcObjectFromName ((const char *) field);
ca60d2b5
KP
658 test->op = compare;
659 test->expr = expr;
7ce19673 660 o = FcNameGetObjectType (FcObjectName (test->object));
ca60d2b5
KP
661 if (o)
662 FcTypecheckExpr (parse, expr, o->type);
663 }
664 return test;
665}
666
667static FcEdit *
668FcEditCreate (FcConfigParse *parse,
2d3387fd 669 FcObject object,
ca60d2b5
KP
670 FcOp op,
671 FcExpr *expr,
672 FcValueBinding binding)
673{
674 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
675
676 if (e)
677 {
678 const FcObjectType *o;
679
680 e->next = 0;
2d3387fd 681 e->object = object;
ca60d2b5
KP
682 e->op = op;
683 e->expr = expr;
684 e->binding = binding;
7ce19673 685 o = FcNameGetObjectType (FcObjectName (e->object));
ca60d2b5
KP
686 if (o)
687 FcTypecheckExpr (parse, expr, o->type);
688 }
689 return e;
690}
691
c2e7c611 692static FcVStack *
39861b7d 693FcVStackCreateAndPush (FcConfigParse *parse)
24330d27 694{
c2e7c611 695 FcVStack *new;
24330d27 696
39861b7d
BE
697 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
698 new = &parse->vstack_static[parse->vstack_static_used++];
699 else
700 {
701 new = malloc (sizeof (FcVStack));
702 if (!new)
703 return 0;
704 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
705 }
c2e7c611
KP
706 new->tag = FcVStackNone;
707 new->prev = 0;
24330d27 708
39861b7d
BE
709 new->prev = parse->vstack;
710 new->pstack = parse->pstack ? parse->pstack->prev : 0;
711 parse->vstack = new;
24330d27 712
39861b7d 713 return new;
24330d27
KP
714}
715
716static FcBool
c2e7c611 717FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
24330d27 718{
39861b7d 719 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
720 if (!vstack)
721 return FcFalse;
722 vstack->u.string = string;
723 vstack->tag = tag;
c2e7c611 724 return FcTrue;
24330d27
KP
725}
726
727static FcBool
c2e7c611 728FcVStackPushInteger (FcConfigParse *parse, int integer)
24330d27 729{
39861b7d 730 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 731 if (!vstack)
24330d27 732 return FcFalse;
c2e7c611
KP
733 vstack->u.integer = integer;
734 vstack->tag = FcVStackInteger;
c2e7c611 735 return FcTrue;
24330d27
KP
736}
737
738static FcBool
c2e7c611 739FcVStackPushDouble (FcConfigParse *parse, double _double)
24330d27 740{
39861b7d 741 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 742 if (!vstack)
24330d27 743 return FcFalse;
c2e7c611
KP
744 vstack->u._double = _double;
745 vstack->tag = FcVStackDouble;
c2e7c611 746 return FcTrue;
24330d27
KP
747}
748
749static FcBool
c2e7c611 750FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
24330d27 751{
39861b7d 752 FcVStack *vstack;
c2e7c611
KP
753 matrix = FcMatrixCopy (matrix);
754 if (!matrix)
c2e7c611 755 return FcFalse;
39861b7d
BE
756 vstack = FcVStackCreateAndPush (parse);
757 if (!vstack)
758 return FcFalse;
c2e7c611
KP
759 vstack->u.matrix = matrix;
760 vstack->tag = FcVStackMatrix;
c2e7c611 761 return FcTrue;
24330d27
KP
762}
763
857b7efe
AT
764static FcBool
765FcVStackPushRange (FcConfigParse *parse, FcRange *range)
766{
767 FcVStack *vstack = FcVStackCreateAndPush (parse);
768 if (!vstack)
769 return FcFalse;
770 vstack->u.range.begin = range->begin;
771 vstack->u.range.end = range->end;
772 vstack->tag = FcVStackRange;
773 return FcTrue;
774}
775
24330d27 776static FcBool
fe8e8a1d 777FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
24330d27 778{
39861b7d 779 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
780 if (!vstack)
781 return FcFalse;
fe8e8a1d 782 vstack->u.bool_ = bool_;
c2e7c611 783 vstack->tag = FcVStackBool;
c2e7c611
KP
784 return FcTrue;
785}
24330d27 786
857b7efe
AT
787static FcBool
788FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
789{
790 FcVStack *vstack;
791 if (!charset)
792 return FcFalse;
793 vstack = FcVStackCreateAndPush (parse);
794 if (!vstack)
795 return FcFalse;
796 vstack->u.charset = charset;
797 vstack->tag = FcVStackCharSet;
798 return FcTrue;
799}
800
c2e7c611
KP
801static FcBool
802FcVStackPushTest (FcConfigParse *parse, FcTest *test)
803{
39861b7d 804 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 805 if (!vstack)
24330d27 806 return FcFalse;
c2e7c611
KP
807 vstack->u.test = test;
808 vstack->tag = FcVStackTest;
24330d27
KP
809 return FcTrue;
810}
811
812static FcBool
c2e7c611 813FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
24330d27 814{
39861b7d 815 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611
KP
816 if (!vstack)
817 return FcFalse;
818 vstack->u.expr = expr;
819 vstack->tag = tag;
c2e7c611
KP
820 return FcTrue;
821}
24330d27 822
c2e7c611
KP
823static FcBool
824FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
825{
39861b7d 826 FcVStack *vstack = FcVStackCreateAndPush (parse);
c2e7c611 827 if (!vstack)
24330d27 828 return FcFalse;
c2e7c611
KP
829 vstack->u.edit = edit;
830 vstack->tag = FcVStackEdit;
24330d27
KP
831 return FcTrue;
832}
833
4f27c1c0
KP
834static FcBool
835FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
836{
39861b7d 837 FcVStack *vstack = FcVStackCreateAndPush (parse);
4f27c1c0
KP
838 if (!vstack)
839 return FcFalse;
840 vstack->u.pattern = pattern;
841 vstack->tag = FcVStackPattern;
4f27c1c0
KP
842 return FcTrue;
843}
844
c2e7c611
KP
845static FcVStack *
846FcVStackFetch (FcConfigParse *parse, int off)
24330d27 847{
c2e7c611 848 FcVStack *vstack;
24330d27 849
c2e7c611
KP
850 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
851 return vstack;
852}
853
39861b7d
BE
854static FcVStack *
855FcVStackPeek (FcConfigParse *parse)
c2e7c611 856{
39861b7d
BE
857 FcVStack *vstack = parse->vstack;
858
859 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
24330d27
KP
860}
861
39861b7d
BE
862static void
863FcVStackPopAndDestroy (FcConfigParse *parse)
24330d27 864{
c2e7c611 865 FcVStack *vstack = parse->vstack;
d0d1f390 866
c2e7c611 867 if (!vstack || vstack->pstack != parse->pstack)
39861b7d
BE
868 return;
869
c2e7c611 870 parse->vstack = vstack->prev;
39861b7d
BE
871
872 switch (vstack->tag) {
873 case FcVStackNone:
874 break;
39861b7d 875 case FcVStackFamily:
3164ac76 876 break;
16e55c7c 877 case FcVStackString:
39861b7d
BE
878 case FcVStackField:
879 case FcVStackConstant:
880 case FcVStackGlob:
881 FcStrFree (vstack->u.string);
882 break;
883 case FcVStackPattern:
884 FcPatternDestroy (vstack->u.pattern);
885 break;
886 case FcVStackInteger:
887 case FcVStackDouble:
888 break;
889 case FcVStackMatrix:
890 FcMatrixFree (vstack->u.matrix);
891 break;
857b7efe 892 case FcVStackRange:
39861b7d
BE
893 case FcVStackBool:
894 break;
857b7efe
AT
895 case FcVStackCharSet:
896 FcCharSetDestroy (vstack->u.charset);
897 break;
39861b7d
BE
898 case FcVStackTest:
899 FcTestDestroy (vstack->u.test);
900 break;
901 case FcVStackExpr:
902 case FcVStackPrefer:
903 case FcVStackAccept:
904 case FcVStackDefault:
905 FcExprDestroy (vstack->u.expr);
906 break;
907 case FcVStackEdit:
908 FcEditDestroy (vstack->u.edit);
909 break;
910 }
911
912 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
913 parse->vstack_static_used--;
914 else
915 {
916 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
917 free (vstack);
918 }
919}
920
921static void
922FcVStackClear (FcConfigParse *parse)
923{
924 while (FcVStackPeek (parse))
925 FcVStackPopAndDestroy (parse);
c2e7c611
KP
926}
927
928static int
929FcVStackElements (FcConfigParse *parse)
930{
931 int h = 0;
932 FcVStack *vstack = parse->vstack;
933 while (vstack && vstack->pstack == parse->pstack)
934 {
935 h++;
936 vstack = vstack->prev;
24330d27 937 }
c2e7c611 938 return h;
24330d27
KP
939}
940
c2e7c611 941static FcChar8 **
de69ee14 942FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
24330d27 943{
c2e7c611
KP
944 int slen;
945 int i;
946 FcChar8 **new;
947 FcChar8 *s;
24330d27 948
c2e7c611
KP
949 if (!attr)
950 return 0;
951 slen = 0;
952 for (i = 0; attr[i]; i++)
8f2a8078 953 slen += strlen ((char *) attr[i]) + 1;
532d8a1d
BE
954 if (i == 0)
955 return 0;
de69ee14
BE
956 slen += (i + 1) * sizeof (FcChar8 *);
957 if (slen <= size_bytes)
958 new = buf;
959 else
532d8a1d 960 {
de69ee14
BE
961 new = malloc (slen);
962 if (!new)
963 {
964 FcConfigMessage (0, FcSevereError, "out of memory");
965 return 0;
966 }
967 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
532d8a1d 968 }
c2e7c611
KP
969 s = (FcChar8 *) (new + (i + 1));
970 for (i = 0; attr[i]; i++)
24330d27 971 {
c2e7c611
KP
972 new[i] = s;
973 strcpy ((char *) s, (char *) attr[i]);
974 s += strlen ((char *) s) + 1;
24330d27 975 }
c2e7c611
KP
976 new[i] = 0;
977 return new;
978}
24330d27 979
c2e7c611
KP
980static FcBool
981FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
982{
1d7b47da
BE
983 FcPStack *new;
984
985 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
986 new = &parse->pstack_static[parse->pstack_static_used++];
987 else
988 {
989 new = malloc (sizeof (FcPStack));
990 if (!new)
991 return FcFalse;
992 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
993 }
c2e7c611 994
c2e7c611
KP
995 new->prev = parse->pstack;
996 new->element = element;
de69ee14 997 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
c2e7c611
KP
998 FcStrBufInit (&new->str, 0, 0);
999 parse->pstack = new;
1000 return FcTrue;
1001}
24330d27 1002
c2e7c611
KP
1003static FcBool
1004FcPStackPop (FcConfigParse *parse)
1005{
1006 FcPStack *old;
d0d1f390
BE
1007
1008 if (!parse->pstack)
24330d27 1009 {
179c3995 1010 FcConfigMessage (parse, FcSevereError, "mismatching element");
c2e7c611 1011 return FcFalse;
24330d27 1012 }
c2e7c611
KP
1013 FcVStackClear (parse);
1014 old = parse->pstack;
1015 parse->pstack = old->prev;
1016 FcStrBufDestroy (&old->str);
de69ee14 1017 if (old->attr && old->attr != old->attr_buf_static)
9dac3c59
KP
1018 {
1019 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
c2e7c611 1020 free (old->attr);
9dac3c59 1021 }
1d7b47da
BE
1022
1023 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1024 parse->pstack_static_used--;
1025 else
1026 {
1027 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
1028 free (old);
1029 }
c2e7c611 1030 return FcTrue;
24330d27
KP
1031}
1032
c2e7c611
KP
1033static FcBool
1034FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
24330d27 1035{
c2e7c611 1036 parse->pstack = 0;
1d7b47da 1037 parse->pstack_static_used = 0;
c2e7c611 1038 parse->vstack = 0;
39861b7d 1039 parse->vstack_static_used = 0;
c2e7c611
KP
1040 parse->error = FcFalse;
1041 parse->name = name;
1042 parse->config = config;
1043 parse->parser = parser;
1044 return FcTrue;
1045}
1046
1047static void
1048FcConfigCleanup (FcConfigParse *parse)
1049{
1050 while (parse->pstack)
1051 FcPStackPop (parse);
1052}
1053
1054static const FcChar8 *
67accef4 1055FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
c2e7c611
KP
1056{
1057 FcChar8 **attrs;
1058 if (!parse->pstack)
24330d27 1059 return 0;
24330d27 1060
c2e7c611 1061 attrs = parse->pstack->attr;
368104c3
PL
1062 if (!attrs)
1063 return 0;
1064
c2e7c611 1065 while (*attrs)
24330d27 1066 {
c2e7c611
KP
1067 if (!strcmp ((char *) *attrs, attr))
1068 return attrs[1];
1069 attrs += 2;
24330d27 1070 }
24330d27
KP
1071 return 0;
1072}
1073
c2e7c611
KP
1074static void
1075FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
24330d27 1076{
c2e7c611
KP
1077 FcConfigParse *parse = userData;
1078 FcElement element;
d0d1f390 1079
c2e7c611
KP
1080 element = FcElementMap (name);
1081 if (element == FcElementUnknown)
179c3995 1082 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
d0d1f390 1083
c2e7c611 1084 if (!FcPStackPush (parse, element, attr))
24330d27 1085 {
179c3995 1086 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1087 return;
24330d27 1088 }
c2e7c611
KP
1089 return;
1090}
24330d27 1091
c2e7c611
KP
1092static void
1093FcParseBlank (FcConfigParse *parse)
1094{
d975cdda
AT
1095 int n = FcVStackElements (parse);
1096 FcChar32 i;
c2e7c611 1097 while (n-- > 0)
24330d27 1098 {
c2e7c611 1099 FcVStack *v = FcVStackFetch (parse, n);
d975cdda 1100 if (!parse->config->blanks)
24330d27 1101 {
d975cdda 1102 parse->config->blanks = FcBlanksCreate ();
c2e7c611 1103 if (!parse->config->blanks)
d975cdda
AT
1104 goto bail;
1105 }
1106 switch (v->tag) {
1107 case FcVStackInteger:
c2e7c611 1108 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
d975cdda
AT
1109 goto bail;
1110 break;
1111 case FcVStackRange:
1112 for (i = v->u.range.begin; i <= v->u.range.end; i++)
24330d27 1113 {
d975cdda
AT
1114 if (!FcBlanksAdd (parse->config->blanks, i))
1115 goto bail;
24330d27 1116 }
d975cdda
AT
1117 break;
1118 default:
1119 FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1120 break;
24330d27
KP
1121 }
1122 }
d975cdda
AT
1123 return;
1124 bail:
1125 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1126}
24330d27 1127
179c3995
KP
1128static void
1129FcParseRescan (FcConfigParse *parse)
1130{
1131 int n = FcVStackElements (parse);
1132 while (n-- > 0)
1133 {
1134 FcVStack *v = FcVStackFetch (parse, n);
1135 if (v->tag != FcVStackInteger)
1136 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1137 else
1138 parse->config->rescanInterval = v->u.integer;
1139 }
1140}
1141
c2e7c611
KP
1142static void
1143FcParseInt (FcConfigParse *parse)
1144{
1145 FcChar8 *s, *end;
1146 int l;
d0d1f390 1147
c2e7c611
KP
1148 if (!parse->pstack)
1149 return;
3ed70071 1150 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 1151 if (!s)
24330d27 1152 {
179c3995 1153 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1154 return;
24330d27 1155 }
c2e7c611
KP
1156 end = 0;
1157 l = (int) strtol ((char *) s, (char **)&end, 0);
1158 if (end != s + strlen ((char *) s))
179c3995 1159 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
c2e7c611
KP
1160 else
1161 FcVStackPushInteger (parse, l);
3ed70071 1162 FcStrBufDestroy (&parse->pstack->str);
24330d27
KP
1163}
1164
223c0289 1165/*
d0d1f390
BE
1166 * idea copied from glib g_ascii_strtod with
1167 * permission of the author (Alexander Larsson)
223c0289
KP
1168 */
1169
1170#include <locale.h>
1171
d0d1f390 1172static double
223c0289
KP
1173FcStrtod (char *s, char **end)
1174{
1175 struct lconv *locale_data;
1176 char *dot;
1177 double v;
1178
1179 /*
1180 * Have to swap the decimal point to match the current locale
1181 * if that locale doesn't use 0x2e
1182 */
1183 if ((dot = strchr (s, 0x2e)) &&
1184 (locale_data = localeconv ()) &&
1185 (locale_data->decimal_point[0] != 0x2e ||
1186 locale_data->decimal_point[1] != 0))
1187 {
1188 char buf[128];
1189 int slen = strlen (s);
1190 int dlen = strlen (locale_data->decimal_point);
1191
67accef4 1192 if (slen + dlen > (int) sizeof (buf))
223c0289
KP
1193 {
1194 if (end)
1195 *end = s;
1196 v = 0;
1197 }
1198 else
1199 {
1200 char *buf_end;
1201 /* mantissa */
1202 strncpy (buf, s, dot - s);
1203 /* decimal point */
1204 strcpy (buf + (dot - s), locale_data->decimal_point);
1205 /* rest of number */
1206 strcpy (buf + (dot - s) + dlen, dot + 1);
1207 buf_end = 0;
1208 v = strtod (buf, &buf_end);
344a0e33
RP
1209 if (buf_end) {
1210 buf_end = s + (buf_end - buf);
1211 if (buf_end > dot)
1212 buf_end -= dlen - 1;
1213 }
223c0289
KP
1214 if (end)
1215 *end = buf_end;
1216 }
1217 }
1218 else
1219 v = strtod (s, end);
1220 return v;
1221}
1222
c2e7c611
KP
1223static void
1224FcParseDouble (FcConfigParse *parse)
24330d27 1225{
c2e7c611
KP
1226 FcChar8 *s, *end;
1227 double d;
d0d1f390 1228
c2e7c611
KP
1229 if (!parse->pstack)
1230 return;
3ed70071 1231 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 1232 if (!s)
24330d27 1233 {
179c3995 1234 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 1235 return;
24330d27 1236 }
c2e7c611 1237 end = 0;
223c0289 1238 d = FcStrtod ((char *) s, (char **)&end);
c2e7c611 1239 if (end != s + strlen ((char *) s))
179c3995 1240 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
24330d27 1241 else
c2e7c611 1242 FcVStackPushDouble (parse, d);
3ed70071 1243 FcStrBufDestroy (&parse->pstack->str);
c2e7c611 1244}
24330d27 1245
c2e7c611
KP
1246static void
1247FcParseString (FcConfigParse *parse, FcVStackTag tag)
1248{
1249 FcChar8 *s;
d0d1f390 1250
c2e7c611
KP
1251 if (!parse->pstack)
1252 return;
1253 s = FcStrBufDone (&parse->pstack->str);
1254 if (!s)
1255 {
179c3995 1256 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1257 return;
1258 }
1259 if (!FcVStackPushString (parse, tag, s))
1260 FcStrFree (s);
1261}
1262
1263static void
1264FcParseMatrix (FcConfigParse *parse)
1265{
1266 FcVStack *vstack;
1267 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1268 FcMatrix m;
d0d1f390 1269
39861b7d 1270 while ((vstack = FcVStackPeek (parse)))
c2e7c611 1271 {
179c3995
KP
1272 double v;
1273 switch (vstack->tag) {
1274 case FcVStackInteger:
1275 v = vstack->u.integer;
1276 break;
1277 case FcVStackDouble:
1278 v = vstack->u._double;
1279 break;
1280 default:
1281 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1282 v = 1.0;
1283 break;
1284 }
1285 switch (matrix_state) {
1286 case m_xx: m.xx = v; break;
1287 case m_xy: m.xy = v; break;
1288 case m_yx: m.yx = v; break;
1289 case m_yy: m.yy = v; break;
1290 default: break;
c2e7c611 1291 }
39861b7d 1292 FcVStackPopAndDestroy (parse);
179c3995 1293 matrix_state--;
c2e7c611
KP
1294 }
1295 if (matrix_state != m_done)
179c3995 1296 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
c2e7c611
KP
1297 else
1298 FcVStackPushMatrix (parse, &m);
24330d27
KP
1299}
1300
857b7efe
AT
1301static void
1302FcParseRange (FcConfigParse *parse)
1303{
1304 FcVStack *vstack;
1305 FcRange r;
1306 FcChar32 n;
1307 int count = 1;
1308
1309 while ((vstack = FcVStackPeek (parse)))
1310 {
1311 if (count < 0)
1312 {
1313 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1314 return;
1315 }
1316 switch (vstack->tag) {
1317 case FcVStackInteger:
1318 n = vstack->u.integer;
1319 break;
1320 default:
1321 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1322 break;
1323 }
1324 if (count == 1)
1325 r.end = n;
1326 else
1327 r.begin = n;
1328 count--;
1329 FcVStackPopAndDestroy (parse);
1330 }
1331 if (count < 0)
1332 {
1333 if (r.begin > r.end)
1334 {
1335 FcConfigMessage (parse, FcSevereError, "invalid range");
1336 return;
1337 }
1338 FcVStackPushRange (parse, &r);
1339 }
1340 else
1341 FcConfigMessage (parse, FcSevereError, "invalid range");
1342}
1343
24330d27 1344static FcBool
fe8e8a1d 1345FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
c2e7c611 1346{
ca60d2b5
KP
1347 FcBool result = FcFalse;
1348
fe8e8a1d 1349 if (!FcNameBool (bool_, &result))
ca60d2b5 1350 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
fe8e8a1d 1351 bool_);
ca60d2b5 1352 return result;
c2e7c611
KP
1353}
1354
1355static void
1356FcParseBool (FcConfigParse *parse)
1357{
1358 FcChar8 *s;
1359
1360 if (!parse->pstack)
1361 return;
3ed70071 1362 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
1363 if (!s)
1364 {
179c3995 1365 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1366 return;
1367 }
ca60d2b5 1368 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
3ed70071 1369 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
1370}
1371
857b7efe
AT
1372static void
1373FcParseCharSet (FcConfigParse *parse)
1374{
1375 FcVStack *vstack;
1376 FcCharSet *charset = FcCharSetCreate ();
1377 FcChar32 i;
1378 int n = 0;
1379
1380 while ((vstack = FcVStackPeek (parse)))
1381 {
1382 switch (vstack->tag) {
1383 case FcVStackInteger:
1384 if (!FcCharSetAddChar (charset, vstack->u.integer))
1385 {
1386 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1387 }
1388 else
1389 n++;
1390 break;
1391 case FcVStackRange:
1392 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1393 {
1394 if (!FcCharSetAddChar (charset, i))
1395 {
1396 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1397 }
1398 else
1399 n++;
1400 }
1401 break;
1402 default:
1403 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1404 break;
1405 }
1406 FcVStackPopAndDestroy (parse);
1407 }
1408 if (n > 0)
1409 FcVStackPushCharSet (parse, charset);
1410 else
1411 FcCharSetDestroy (charset);
1412}
1413
681bb379
KP
1414static FcBool
1415FcConfigLexBinding (FcConfigParse *parse,
1416 const FcChar8 *binding_string,
1417 FcValueBinding *binding_ret)
1418{
1419 FcValueBinding binding;
d0d1f390 1420
681bb379
KP
1421 if (!binding_string)
1422 binding = FcValueBindingWeak;
1423 else
1424 {
1425 if (!strcmp ((char *) binding_string, "weak"))
1426 binding = FcValueBindingWeak;
1427 else if (!strcmp ((char *) binding_string, "strong"))
1428 binding = FcValueBindingStrong;
1429 else if (!strcmp ((char *) binding_string, "same"))
1430 binding = FcValueBindingSame;
1431 else
1432 {
1433 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1434 return FcFalse;
1435 }
1436 }
1437 *binding_ret = binding;
1438 return FcTrue;
1439}
1440
c2e7c611
KP
1441static void
1442FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
24330d27 1443{
c2e7c611
KP
1444 FcVStack *vstack;
1445 FcExpr *left, *expr = 0, *new;
1446
39861b7d 1447 while ((vstack = FcVStackPeek (parse)))
c2e7c611
KP
1448 {
1449 if (vstack->tag != FcVStackFamily)
1450 {
179c3995 1451 FcConfigMessage (parse, FcSevereWarning, "non-family");
39861b7d 1452 FcVStackPopAndDestroy (parse);
179c3995 1453 continue;
c2e7c611
KP
1454 }
1455 left = vstack->u.expr;
1456 vstack->tag = FcVStackNone;
39861b7d 1457 FcVStackPopAndDestroy (parse);
c2e7c611
KP
1458 if (expr)
1459 {
390c05e6 1460 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
c2e7c611
KP
1461 if (!new)
1462 {
179c3995 1463 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1464 FcExprDestroy (left);
1465 FcExprDestroy (expr);
1466 break;
1467 }
1468 expr = new;
1469 }
1470 else
1471 expr = left;
1472 }
1473 if (expr)
1474 {
1475 if (!FcVStackPushExpr (parse, tag, expr))
1476 {
179c3995 1477 FcConfigMessage (parse, FcSevereError, "out of memory");
f2fb985c 1478 FcExprDestroy (expr);
c2e7c611
KP
1479 }
1480 }
1481}
1482
1483static void
1484FcParseFamily (FcConfigParse *parse)
1485{
1486 FcChar8 *s;
1487 FcExpr *expr;
1488
1489 if (!parse->pstack)
1490 return;
3ed70071 1491 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
1492 if (!s)
1493 {
179c3995 1494 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1495 return;
1496 }
390c05e6 1497 expr = FcExprCreateString (parse->config, s);
3ed70071 1498 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
1499 if (expr)
1500 FcVStackPushExpr (parse, FcVStackFamily, expr);
1501}
1502
1503static void
1504FcParseAlias (FcConfigParse *parse)
1505{
179c3995 1506 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
24330d27 1507 FcEdit *edit = 0, *next;
c2e7c611 1508 FcVStack *vstack;
24330d27 1509 FcTest *test;
681bb379 1510 FcValueBinding binding;
24330d27 1511
681bb379
KP
1512 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1513 return;
39861b7d 1514 while ((vstack = FcVStackPeek (parse)))
24330d27 1515 {
c2e7c611
KP
1516 switch (vstack->tag) {
1517 case FcVStackFamily:
1518 if (family)
179c3995 1519 {
390c05e6 1520 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
179c3995
KP
1521 if (!new)
1522 FcConfigMessage (parse, FcSevereError, "out of memory");
1523 else
1524 family = new;
1525 }
1526 else
1527 new = vstack->u.expr;
1528 if (new)
1529 {
1530 family = new;
1531 vstack->tag = FcVStackNone;
1532 }
c2e7c611
KP
1533 break;
1534 case FcVStackPrefer:
1535 if (prefer)
1536 FcExprDestroy (prefer);
1537 prefer = vstack->u.expr;
1538 vstack->tag = FcVStackNone;
1539 break;
1540 case FcVStackAccept:
1541 if (accept)
1542 FcExprDestroy (accept);
1543 accept = vstack->u.expr;
1544 vstack->tag = FcVStackNone;
1545 break;
1546 case FcVStackDefault:
1547 if (def)
1548 FcExprDestroy (def);
1549 def = vstack->u.expr;
1550 vstack->tag = FcVStackNone;
1551 break;
1552 default:
179c3995 1553 FcConfigMessage (parse, FcSevereWarning, "bad alias");
c2e7c611
KP
1554 break;
1555 }
39861b7d 1556 FcVStackPopAndDestroy (parse);
24330d27 1557 }
ccb3e93b 1558 if (!family)
c2e7c611 1559 {
179c3995
KP
1560 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1561 if (prefer)
1562 FcExprDestroy (prefer);
1563 if (accept)
1564 FcExprDestroy (accept);
1565 if (def)
1566 FcExprDestroy (def);
c2e7c611
KP
1567 return;
1568 }
24330d27
KP
1569 if (prefer)
1570 {
d0d1f390 1571 edit = FcEditCreate (parse,
2d3387fd 1572 FC_FAMILY_OBJECT,
24330d27 1573 FcOpPrepend,
6fff2cda 1574 prefer,
681bb379 1575 binding);
24330d27
KP
1576 if (edit)
1577 edit->next = 0;
c2e7c611
KP
1578 else
1579 FcExprDestroy (prefer);
24330d27
KP
1580 }
1581 if (accept)
1582 {
1583 next = edit;
ca60d2b5 1584 edit = FcEditCreate (parse,
2d3387fd 1585 FC_FAMILY_OBJECT,
24330d27 1586 FcOpAppend,
6fff2cda 1587 accept,
681bb379 1588 binding);
24330d27
KP
1589 if (edit)
1590 edit->next = next;
c2e7c611
KP
1591 else
1592 FcExprDestroy (accept);
24330d27
KP
1593 }
1594 if (def)
1595 {
1596 next = edit;
ca60d2b5 1597 edit = FcEditCreate (parse,
2d3387fd 1598 FC_FAMILY_OBJECT,
6fff2cda
KP
1599 FcOpAppendLast,
1600 def,
681bb379 1601 binding);
24330d27
KP
1602 if (edit)
1603 edit->next = next;
c2e7c611
KP
1604 else
1605 FcExprDestroy (def);
24330d27
KP
1606 }
1607 if (edit)
1608 {
ca60d2b5 1609 test = FcTestCreate (parse, FcMatchPattern,
938bc633 1610 FcQualAny,
2623c1eb 1611 (FcChar8 *) FC_FAMILY,
24330d27
KP
1612 FcOpEqual,
1613 family);
1614 if (test)
c2e7c611
KP
1615 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1616 FcTestDestroy (test);
24330d27 1617 }
c2e7c611
KP
1618 else
1619 FcExprDestroy (family);
24330d27
KP
1620}
1621
c2e7c611
KP
1622static FcExpr *
1623FcPopExpr (FcConfigParse *parse)
24330d27 1624{
39861b7d 1625 FcVStack *vstack = FcVStackPeek (parse);
c2e7c611
KP
1626 FcExpr *expr = 0;
1627 if (!vstack)
1628 return 0;
1629 switch (vstack->tag) {
1630 case FcVStackNone:
1631 break;
1632 case FcVStackString:
1633 case FcVStackFamily:
390c05e6 1634 expr = FcExprCreateString (parse->config, vstack->u.string);
bbbaac36 1635 break;
c2e7c611 1636 case FcVStackField:
390c05e6 1637 expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
bbbaac36 1638 break;
c2e7c611 1639 case FcVStackConstant:
390c05e6 1640 expr = FcExprCreateConst (parse->config, vstack->u.string);
c2e7c611 1641 break;
34cd0514
CW
1642 case FcVStackGlob:
1643 /* XXX: What's the correct action here? (CDW) */
1644 break;
c2e7c611
KP
1645 case FcVStackPrefer:
1646 case FcVStackAccept:
1647 case FcVStackDefault:
1648 expr = vstack->u.expr;
1649 vstack->tag = FcVStackNone;
1650 break;
1651 case FcVStackInteger:
390c05e6 1652 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
c2e7c611
KP
1653 break;
1654 case FcVStackDouble:
390c05e6 1655 expr = FcExprCreateDouble (parse->config, vstack->u._double);
c2e7c611
KP
1656 break;
1657 case FcVStackMatrix:
390c05e6 1658 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
c2e7c611 1659 break;
857b7efe
AT
1660 case FcVStackRange:
1661 break;
c2e7c611 1662 case FcVStackBool:
390c05e6 1663 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
c2e7c611 1664 break;
857b7efe
AT
1665 case FcVStackCharSet:
1666 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1667 break;
c2e7c611
KP
1668 case FcVStackTest:
1669 break;
1670 case FcVStackExpr:
1671 expr = vstack->u.expr;
8ec077f2 1672 vstack->tag = FcVStackNone;
c2e7c611
KP
1673 break;
1674 case FcVStackEdit:
1675 break;
4f27c1c0
KP
1676 default:
1677 break;
c2e7c611 1678 }
39861b7d 1679 FcVStackPopAndDestroy (parse);
c2e7c611
KP
1680 return expr;
1681}
1682
3f7653c2
KP
1683/*
1684 * This builds a tree of binary operations. Note
1685 * that every operator is defined so that if only
1686 * a single operand is contained, the value of the
1687 * whole expression is the value of the operand.
1688 *
1689 * This code reduces in that case to returning that
1690 * operand.
1691 */
c2e7c611 1692static FcExpr *
3f7653c2 1693FcPopBinary (FcConfigParse *parse, FcOp op)
c2e7c611
KP
1694{
1695 FcExpr *left, *expr = 0, *new;
24330d27 1696
c2e7c611 1697 while ((left = FcPopExpr (parse)))
24330d27 1698 {
c2e7c611 1699 if (expr)
24330d27 1700 {
390c05e6 1701 new = FcExprCreateOp (parse->config, left, op, expr);
c2e7c611
KP
1702 if (!new)
1703 {
179c3995 1704 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1705 FcExprDestroy (left);
1706 FcExprDestroy (expr);
2de24638 1707 return 0;
c2e7c611
KP
1708 }
1709 expr = new;
24330d27 1710 }
c2e7c611
KP
1711 else
1712 expr = left;
1713 }
1714 return expr;
1715}
1716
1717static void
3f7653c2
KP
1718FcParseBinary (FcConfigParse *parse, FcOp op)
1719{
1720 FcExpr *expr = FcPopBinary (parse, op);
1721 if (expr)
1722 FcVStackPushExpr (parse, FcVStackExpr, expr);
1723}
1724
1725/*
1726 * This builds a a unary operator, it consumes only
1727 * a single operand
1728 */
1729
1730static FcExpr *
1731FcPopUnary (FcConfigParse *parse, FcOp op)
1732{
1733 FcExpr *operand, *new = 0;
1734
1735 if ((operand = FcPopExpr (parse)))
1736 {
390c05e6 1737 new = FcExprCreateOp (parse->config, operand, op, 0);
3f7653c2
KP
1738 if (!new)
1739 {
1740 FcExprDestroy (operand);
1741 FcConfigMessage (parse, FcSevereError, "out of memory");
1742 }
1743 }
1744 return new;
1745}
1746
1747static void
1748FcParseUnary (FcConfigParse *parse, FcOp op)
c2e7c611 1749{
3f7653c2 1750 FcExpr *expr = FcPopUnary (parse, op);
c2e7c611
KP
1751 if (expr)
1752 FcVStackPushExpr (parse, FcVStackExpr, expr);
1753}
1754
1755static void
1756FcParseInclude (FcConfigParse *parse)
1757{
1758 FcChar8 *s;
1759 const FcChar8 *i;
1760 FcBool ignore_missing = FcFalse;
d0d1f390 1761
3ed70071 1762 s = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611
KP
1763 if (!s)
1764 {
179c3995 1765 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1766 return;
1767 }
1768 i = FcConfigGetAttribute (parse, "ignore_missing");
ca60d2b5 1769 if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
c2e7c611 1770 ignore_missing = FcTrue;
24c90386 1771 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
c2e7c611 1772 parse->error = FcTrue;
3ed70071 1773 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
1774}
1775
1776typedef struct _FcOpMap {
67accef4 1777 char name[16];
c2e7c611
KP
1778 FcOp op;
1779} FcOpMap;
1780
1781static FcOp
1782FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1783{
1784 int i;
1785
1786 for (i = 0; i < nmap; i++)
d0d1f390 1787 if (!strcmp ((char *) op, map[i].name))
c2e7c611
KP
1788 return map[i].op;
1789 return FcOpInvalid;
1790}
1791
1792static const FcOpMap fcCompareOps[] = {
1793 { "eq", FcOpEqual },
1794 { "not_eq", FcOpNotEqual },
1795 { "less", FcOpLess },
1796 { "less_eq", FcOpLessEqual },
1797 { "more", FcOpMore },
47d4f950
KP
1798 { "more_eq", FcOpMoreEqual },
1799 { "contains", FcOpContains },
1800 { "not_contains", FcOpNotContains }
c2e7c611
KP
1801};
1802
67accef4 1803#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
c2e7c611
KP
1804
1805static FcOp
1806FcConfigLexCompare (const FcChar8 *compare)
1807{
1808 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1809}
1810
c2e7c611
KP
1811static void
1812FcParseTest (FcConfigParse *parse)
1813{
938bc633
KP
1814 const FcChar8 *kind_string;
1815 FcMatchKind kind;
c2e7c611
KP
1816 const FcChar8 *qual_string;
1817 FcQual qual;
1818 const FcChar8 *name;
1819 const FcChar8 *compare_string;
1820 FcOp compare;
1821 FcExpr *expr;
1822 FcTest *test;
1823
938bc633
KP
1824 kind_string = FcConfigGetAttribute (parse, "target");
1825 if (!kind_string)
1826 kind = FcMatchDefault;
1827 else
1828 {
1829 if (!strcmp ((char *) kind_string, "pattern"))
1830 kind = FcMatchPattern;
1831 else if (!strcmp ((char *) kind_string, "font"))
1832 kind = FcMatchFont;
c2c6976d
KP
1833 else if (!strcmp ((char *) kind_string, "scan"))
1834 kind = FcMatchScan;
938bc633
KP
1835 else if (!strcmp ((char *) kind_string, "default"))
1836 kind = FcMatchDefault;
1837 else
1838 {
1839 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1840 return;
1841 }
1842 }
c2e7c611
KP
1843 qual_string = FcConfigGetAttribute (parse, "qual");
1844 if (!qual_string)
1845 qual = FcQualAny;
1846 else
1847 {
1848 if (!strcmp ((char *) qual_string, "any"))
1849 qual = FcQualAny;
1850 else if (!strcmp ((char *) qual_string, "all"))
1851 qual = FcQualAll;
6f6563ed
KP
1852 else if (!strcmp ((char *) qual_string, "first"))
1853 qual = FcQualFirst;
1854 else if (!strcmp ((char *) qual_string, "not_first"))
1855 qual = FcQualNotFirst;
c2e7c611 1856 else
24330d27 1857 {
179c3995 1858 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
b4a2c1f0 1859 return;
24330d27 1860 }
c2e7c611
KP
1861 }
1862 name = FcConfigGetAttribute (parse, "name");
1863 if (!name)
1864 {
179c3995 1865 FcConfigMessage (parse, FcSevereWarning, "missing test name");
b4a2c1f0 1866 return;
c2e7c611
KP
1867 }
1868 compare_string = FcConfigGetAttribute (parse, "compare");
1869 if (!compare_string)
1870 compare = FcOpEqual;
1871 else
1872 {
1873 compare = FcConfigLexCompare (compare_string);
1874 if (compare == FcOpInvalid)
24330d27 1875 {
179c3995 1876 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
b4a2c1f0 1877 return;
24330d27 1878 }
c2e7c611 1879 }
3f7653c2 1880 expr = FcPopBinary (parse, FcOpComma);
c2e7c611
KP
1881 if (!expr)
1882 {
179c3995 1883 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
c2e7c611
KP
1884 return;
1885 }
ca60d2b5 1886 test = FcTestCreate (parse, kind, qual, name, compare, expr);
c2e7c611
KP
1887 if (!test)
1888 {
179c3995 1889 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1890 return;
1891 }
1892 FcVStackPushTest (parse, test);
1893}
1894
1895static const FcOpMap fcModeOps[] = {
1896 { "assign", FcOpAssign },
1897 { "assign_replace", FcOpAssignReplace },
1898 { "prepend", FcOpPrepend },
1899 { "prepend_first", FcOpPrependFirst },
1900 { "append", FcOpAppend },
1901 { "append_last", FcOpAppendLast },
1902};
1903
67accef4 1904#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
c2e7c611
KP
1905
1906static FcOp
1907FcConfigLexMode (const FcChar8 *mode)
1908{
1909 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1910}
1911
1912static void
1913FcParseEdit (FcConfigParse *parse)
1914{
1915 const FcChar8 *name;
1916 const FcChar8 *mode_string;
1917 FcOp mode;
6fff2cda 1918 FcValueBinding binding;
c2e7c611
KP
1919 FcExpr *expr;
1920 FcEdit *edit;
1921
1922 name = FcConfigGetAttribute (parse, "name");
1923 if (!name)
1924 {
179c3995 1925 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
b4a2c1f0 1926 return;
c2e7c611
KP
1927 }
1928 mode_string = FcConfigGetAttribute (parse, "mode");
1929 if (!mode_string)
8ec077f2 1930 mode = FcOpAssign;
c2e7c611
KP
1931 else
1932 {
1933 mode = FcConfigLexMode (mode_string);
1934 if (mode == FcOpInvalid)
24330d27 1935 {
179c3995 1936 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
b4a2c1f0 1937 return;
24330d27 1938 }
c2e7c611 1939 }
681bb379
KP
1940 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1941 return;
1942
3f7653c2 1943 expr = FcPopBinary (parse, FcOpComma);
2d3387fd
KP
1944 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1945 mode, expr, binding);
c2e7c611
KP
1946 if (!edit)
1947 {
179c3995 1948 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
1949 FcExprDestroy (expr);
1950 return;
1951 }
1952 if (!FcVStackPushEdit (parse, edit))
1953 FcEditDestroy (edit);
1954}
1955
1956static void
1957FcParseMatch (FcConfigParse *parse)
1958{
1959 const FcChar8 *kind_name;
1960 FcMatchKind kind;
1961 FcTest *test = 0;
1962 FcEdit *edit = 0;
1963 FcVStack *vstack;
1964
1965 kind_name = FcConfigGetAttribute (parse, "target");
1966 if (!kind_name)
1967 kind = FcMatchPattern;
1968 else
1969 {
1970 if (!strcmp ((char *) kind_name, "pattern"))
1971 kind = FcMatchPattern;
1972 else if (!strcmp ((char *) kind_name, "font"))
1973 kind = FcMatchFont;
c2c6976d
KP
1974 else if (!strcmp ((char *) kind_name, "scan"))
1975 kind = FcMatchScan;
c2e7c611 1976 else
24330d27 1977 {
179c3995 1978 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
b4a2c1f0 1979 return;
24330d27 1980 }
c2e7c611 1981 }
39861b7d 1982 while ((vstack = FcVStackPeek (parse)))
c2e7c611
KP
1983 {
1984 switch (vstack->tag) {
1985 case FcVStackTest:
1986 vstack->u.test->next = test;
1987 test = vstack->u.test;
1988 vstack->tag = FcVStackNone;
1989 break;
1990 case FcVStackEdit:
1991 vstack->u.edit->next = edit;
1992 edit = vstack->u.edit;
1993 vstack->tag = FcVStackNone;
0f963b0d
KP
1994 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
1995 {
d0d1f390 1996 FcConfigMessage (parse, FcSevereError,
0f963b0d
KP
1997 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
1998 FcObjectName(edit->object));
1999 }
c2e7c611
KP
2000 break;
2001 default:
179c3995 2002 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
c2e7c611
KP
2003 break;
2004 }
39861b7d 2005 FcVStackPopAndDestroy (parse);
c2e7c611
KP
2006 }
2007 if (!FcConfigAddEdit (parse->config, test, edit, kind))
179c3995 2008 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2009}
2010
d47c9d6e
KP
2011static void
2012FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2013{
2014 FcVStack *vstack;
2015
39861b7d 2016 while ((vstack = FcVStackPeek (parse)))
d47c9d6e
KP
2017 {
2018 switch (vstack->tag) {
2019 case FcVStackGlob:
d0d1f390 2020 if (!FcConfigGlobAdd (parse->config,
d47c9d6e
KP
2021 vstack->u.string,
2022 element == FcElementAcceptfont))
2023 {
2024 FcConfigMessage (parse, FcSevereError, "out of memory");
2025 }
2026 break;
4f27c1c0
KP
2027 case FcVStackPattern:
2028 if (!FcConfigPatternsAdd (parse->config,
2029 vstack->u.pattern,
2030 element == FcElementAcceptfont))
2031 {
2032 FcConfigMessage (parse, FcSevereError, "out of memory");
2033 }
2034 else
2035 vstack->tag = FcVStackNone;
2036 break;
d47c9d6e
KP
2037 default:
2038 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2039 break;
2040 }
39861b7d 2041 FcVStackPopAndDestroy (parse);
d47c9d6e
KP
2042 }
2043}
2044
4f27c1c0
KP
2045
2046static FcValue
2047FcPopValue (FcConfigParse *parse)
2048{
39861b7d 2049 FcVStack *vstack = FcVStackPeek (parse);
4f27c1c0 2050 FcValue value;
d0d1f390 2051
4f27c1c0 2052 value.type = FcTypeVoid;
d0d1f390 2053
4f27c1c0
KP
2054 if (!vstack)
2055 return value;
d0d1f390 2056
4f27c1c0
KP
2057 switch (vstack->tag) {
2058 case FcVStackString:
3164ac76 2059 value.u.s = FcStrStaticName (vstack->u.string);
4262e0b3 2060 if (value.u.s)
4f27c1c0
KP
2061 value.type = FcTypeString;
2062 break;
2063 case FcVStackConstant:
2064 if (FcNameConstant (vstack->u.string, &value.u.i))
2065 value.type = FcTypeInteger;
2066 break;
2067 case FcVStackInteger:
2068 value.u.i = vstack->u.integer;
2069 value.type = FcTypeInteger;
2070 break;
2071 case FcVStackDouble:
2072 value.u.d = vstack->u._double;
2073 value.type = FcTypeInteger;
2074 break;
2075 case FcVStackMatrix:
4262e0b3
PL
2076 value.u.m = FcMatrixCopy (vstack->u.matrix);
2077 if (value.u.m)
4f27c1c0
KP
2078 value.type = FcTypeMatrix;
2079 break;
2080 case FcVStackBool:
fe8e8a1d 2081 value.u.b = vstack->u.bool_;
4f27c1c0
KP
2082 value.type = FcTypeBool;
2083 break;
857b7efe
AT
2084 case FcVStackCharSet:
2085 value.u.c = FcCharSetCopy (vstack->u.charset);
2086 if (value.u.c)
2087 value.type = FcTypeCharSet;
2088 break;
4f27c1c0 2089 default:
d0d1f390 2090 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
4f27c1c0
KP
2091 vstack->tag);
2092 break;
2093 }
39861b7d 2094 FcVStackPopAndDestroy (parse);
d0d1f390 2095
4f27c1c0
KP
2096 return value;
2097}
2098
2099static void
2100FcParsePatelt (FcConfigParse *parse)
2101{
2102 FcValue value;
2103 FcPattern *pattern = FcPatternCreate ();
2104 const char *name;
2105
2106 if (!pattern)
2107 {
2108 FcConfigMessage (parse, FcSevereError, "out of memory");
2109 return;
2110 }
2111
8245771d 2112 name = (char *) FcConfigGetAttribute (parse, "name");
4f27c1c0
KP
2113 if (!name)
2114 {
2115 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2de24638 2116 FcPatternDestroy (pattern);
4f27c1c0
KP
2117 return;
2118 }
d0d1f390 2119
4f27c1c0
KP
2120 for (;;)
2121 {
2122 value = FcPopValue (parse);
2123 if (value.type == FcTypeVoid)
2124 break;
2125 if (!FcPatternAdd (pattern, name, value, FcTrue))
2126 {
2127 FcConfigMessage (parse, FcSevereError, "out of memory");
799691c9 2128 FcValueDestroy(value);
4f27c1c0
KP
2129 break;
2130 }
799691c9 2131 FcValueDestroy(value);
4f27c1c0
KP
2132 }
2133
529291be 2134 FcVStackPushPattern (parse, pattern);
4f27c1c0
KP
2135}
2136
2137static void
2138FcParsePattern (FcConfigParse *parse)
2139{
2140 FcVStack *vstack;
2141 FcPattern *pattern = FcPatternCreate ();
2142
2143 if (!pattern)
2144 {
2145 FcConfigMessage (parse, FcSevereError, "out of memory");
2146 return;
2147 }
2148
39861b7d 2149 while ((vstack = FcVStackPeek (parse)))
4f27c1c0
KP
2150 {
2151 switch (vstack->tag) {
2152 case FcVStackPattern:
2153 if (!FcPatternAppend (pattern, vstack->u.pattern))
2154 {
2155 FcConfigMessage (parse, FcSevereError, "out of memory");
2de24638 2156 FcPatternDestroy (pattern);
4f27c1c0
KP
2157 return;
2158 }
2159 break;
2160 default:
2161 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2162 break;
2163 }
39861b7d 2164 FcVStackPopAndDestroy (parse);
4f27c1c0
KP
2165 }
2166
2167 FcVStackPushPattern (parse, pattern);
2168}
2169
c2e7c611
KP
2170static void
2171FcEndElement(void *userData, const XML_Char *name)
2172{
2173 FcConfigParse *parse = userData;
2174 FcChar8 *data;
d1567812
TL
2175#ifdef _WIN32
2176 FcChar8 buffer[1000];
2177#endif
2178
c2e7c611
KP
2179 if (!parse->pstack)
2180 return;
2181 switch (parse->pstack->element) {
2182 case FcElementNone:
2183 break;
2184 case FcElementFontconfig:
2185 break;
2186 case FcElementDir:
3ed70071 2187 data = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 2188 if (!data)
24330d27 2189 {
179c3995 2190 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611 2191 break;
24330d27 2192 }
daeed6e0 2193#ifdef _WIN32
6d65081e
DS
2194 if (strcmp (data, "CUSTOMFONTDIR") == 0)
2195 {
e04afe83 2196 char *p;
d1567812
TL
2197 data = buffer;
2198 if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
6d65081e
DS
2199 {
2200 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
6d65081e
DS
2201 break;
2202 }
8b1ceef0
TL
2203 /*
2204 * Must use the multi-byte aware function to search
2205 * for backslash because East Asian double-byte code
2206 * pages have characters with backslash as the second
2207 * byte.
2208 */
2209 p = _mbsrchr (data, '\\');
6d65081e
DS
2210 if (p) *p = '\0';
2211 strcat (data, "\\fonts");
2212 }
1cdf7efb
BE
2213 else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2214 {
2215 char *p;
d1567812
TL
2216 data = buffer;
2217 if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
1cdf7efb
BE
2218 {
2219 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1cdf7efb
BE
2220 break;
2221 }
8b1ceef0 2222 p = _mbsrchr (data, '\\');
1cdf7efb
BE
2223 if (p) *p = '\0';
2224 strcat (data, "\\..\\share\\fonts");
2225 }
6d65081e 2226 else if (strcmp (data, "WINDOWSFONTDIR") == 0)
daeed6e0
TL
2227 {
2228 int rc;
d1567812 2229 data = buffer;
f33a2313 2230#if _WIN32_WINNT >= 0x0500
d1567812 2231 rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
f33a2313
BE
2232#else
2233 rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
2234#endif
d1567812 2235 if (rc == 0 || rc > sizeof (buffer) - 20)
daeed6e0 2236 {
327fc9d1 2237 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
daeed6e0
TL
2238 break;
2239 }
2240 if (data [strlen (data) - 1] != '\\')
2241 strcat (data, "\\");
2242 strcat (data, "fonts");
2243 }
2244#endif
8ade2369
KP
2245 if (strlen ((char *) data) == 0)
2246 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2247 else if (!FcStrUsesHome (data) || FcConfigHome ())
ff3f1f98
KP
2248 {
2249 if (!FcConfigAddDir (parse->config, data))
f468f568 2250 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
ff3f1f98 2251 }
3ed70071 2252 FcStrBufDestroy (&parse->pstack->str);
c2e7c611 2253 break;
7410e40b
PL
2254 case FcElementCacheDir:
2255 data = FcStrBufDone (&parse->pstack->str);
2256 if (!data)
2257 {
2258 FcConfigMessage (parse, FcSevereError, "out of memory");
2259 break;
2260 }
8a3dc488
TL
2261#ifdef _WIN32
2262 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2263 {
2264 int rc;
2265 FcStrFree (data);
2266 data = malloc (1000);
2267 if (!data)
2268 {
2269 FcConfigMessage (parse, FcSevereError, "out of memory");
2270 break;
2271 }
2272 FcMemAlloc (FC_MEM_STRING, 1000);
2273 rc = GetTempPath (800, data);
2274 if (rc == 0 || rc > 800)
2275 {
327fc9d1 2276 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
8a3dc488
TL
2277 FcStrFree (data);
2278 break;
2279 }
2280 if (data [strlen (data) - 1] != '\\')
2281 strcat (data, "\\");
2282 strcat (data, "fontconfig\\cache");
2283 }
2284#endif
7410e40b
PL
2285 if (!FcStrUsesHome (data) || FcConfigHome ())
2286 {
2287 if (!FcConfigAddCacheDir (parse->config, data))
2288 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2289 }
2290 FcStrFree (data);
2291 break;
2292
c2e7c611 2293 case FcElementCache:
3ed70071 2294 data = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 2295 if (!data)
24330d27 2296 {
179c3995 2297 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2298 break;
c2e7c611 2299 }
2d3387fd 2300 /* discard this data; no longer used */
3ed70071 2301 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
2302 break;
2303 case FcElementInclude:
2304 FcParseInclude (parse);
2305 break;
2306 case FcElementConfig:
2307 break;
2308 case FcElementMatch:
2309 FcParseMatch (parse);
2310 break;
2311 case FcElementAlias:
2312 FcParseAlias (parse);
2313 break;
2314
2315 case FcElementBlank:
2316 FcParseBlank (parse);
2317 break;
179c3995
KP
2318 case FcElementRescan:
2319 FcParseRescan (parse);
2320 break;
c2e7c611
KP
2321
2322 case FcElementPrefer:
2323 FcParseFamilies (parse, FcVStackPrefer);
2324 break;
2325 case FcElementAccept:
2326 FcParseFamilies (parse, FcVStackAccept);
2327 break;
2328 case FcElementDefault:
2329 FcParseFamilies (parse, FcVStackDefault);
2330 break;
2331 case FcElementFamily:
2332 FcParseFamily (parse);
2333 break;
2334
2335 case FcElementTest:
2336 FcParseTest (parse);
2337 break;
2338 case FcElementEdit:
2339 FcParseEdit (parse);
2340 break;
2341
2342 case FcElementInt:
2343 FcParseInt (parse);
2344 break;
2345 case FcElementDouble:
2346 FcParseDouble (parse);
2347 break;
2348 case FcElementString:
2349 FcParseString (parse, FcVStackString);
2350 break;
2351 case FcElementMatrix:
2352 FcParseMatrix (parse);
2353 break;
857b7efe
AT
2354 case FcElementRange:
2355 FcParseRange (parse);
2356 break;
c2e7c611
KP
2357 case FcElementBool:
2358 FcParseBool (parse);
2359 break;
857b7efe
AT
2360 case FcElementCharSet:
2361 FcParseCharSet (parse);
c2e7c611 2362 break;
d47c9d6e
KP
2363 case FcElementSelectfont:
2364 break;
2365 case FcElementAcceptfont:
2366 case FcElementRejectfont:
2367 FcParseAcceptRejectFont (parse, parse->pstack->element);
2368 break;
2369 case FcElementGlob:
2370 FcParseString (parse, FcVStackGlob);
2371 break;
4f27c1c0
KP
2372 case FcElementPattern:
2373 FcParsePattern (parse);
2374 break;
2375 case FcElementPatelt:
2376 FcParsePatelt (parse);
2377 break;
c2e7c611
KP
2378 case FcElementName:
2379 FcParseString (parse, FcVStackField);
2380 break;
2381 case FcElementConst:
2382 FcParseString (parse, FcVStackConstant);
2383 break;
2384 case FcElementOr:
3f7653c2 2385 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2386 break;
2387 case FcElementAnd:
3f7653c2 2388 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2389 break;
2390 case FcElementEq:
3f7653c2 2391 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2392 break;
2393 case FcElementNotEq:
3f7653c2 2394 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2395 break;
2396 case FcElementLess:
3f7653c2 2397 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2398 break;
2399 case FcElementLessEq:
3f7653c2 2400 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2401 break;
2402 case FcElementMore:
3f7653c2 2403 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2404 break;
2405 case FcElementMoreEq:
3f7653c2 2406 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2407 break;
47d4f950 2408 case FcElementContains:
3f7653c2 2409 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2410 break;
2411 case FcElementNotContains:
3f7653c2 2412 FcParseBinary (parse, FcOpNotContains);
47d4f950 2413 break;
c2e7c611 2414 case FcElementPlus:
3f7653c2 2415 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2416 break;
2417 case FcElementMinus:
3f7653c2 2418 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2419 break;
2420 case FcElementTimes:
3f7653c2 2421 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2422 break;
2423 case FcElementDivide:
3f7653c2 2424 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2425 break;
2426 case FcElementNot:
3f7653c2 2427 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2428 break;
2429 case FcElementIf:
3f7653c2
KP
2430 FcParseBinary (parse, FcOpQuest);
2431 break;
2432 case FcElementFloor:
2433 FcParseUnary (parse, FcOpFloor);
2434 break;
2435 case FcElementCeil:
2436 FcParseUnary (parse, FcOpCeil);
2437 break;
2438 case FcElementRound:
2439 FcParseUnary (parse, FcOpRound);
2440 break;
2441 case FcElementTrunc:
2442 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2443 break;
2444 case FcElementUnknown:
2445 break;
24330d27 2446 }
c2e7c611
KP
2447 (void) FcPStackPop (parse);
2448}
2449
2450static void
2451FcCharacterData (void *userData, const XML_Char *s, int len)
2452{
2453 FcConfigParse *parse = userData;
d0d1f390 2454
c2e7c611
KP
2455 if (!parse->pstack)
2456 return;
2457 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2458 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2459}
2460
2461static void
2462FcStartDoctypeDecl (void *userData,
2463 const XML_Char *doctypeName,
2464 const XML_Char *sysid,
2465 const XML_Char *pubid,
2466 int has_internal_subset)
2467{
2468 FcConfigParse *parse = userData;
2469
2470 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2471 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2472}
2473
0d745819 2474#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2475
2476static void
2477FcInternalSubsetDecl (void *userData,
2478 const XML_Char *doctypeName,
2479 const XML_Char *sysid,
2480 const XML_Char *pubid)
2481{
2482 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2483}
2484
2485static void
2486FcExternalSubsetDecl (void *userData,
2487 const XML_Char *doctypeName,
2488 const XML_Char *sysid,
2489 const XML_Char *pubid)
2490{
2491 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2492}
2493
2494#else /* ENABLE_LIBXML2 */
2495
c2e7c611
KP
2496static void
2497FcEndDoctypeDecl (void *userData)
2498{
24330d27
KP
2499}
2500
e99f0f0a
PL
2501#endif /* ENABLE_LIBXML2 */
2502
9419bb34
KP
2503static int
2504FcSortCmpStr (const void *a, const void *b)
2505{
2506 const FcChar8 *as = *((FcChar8 **) a);
2507 const FcChar8 *bs = *((FcChar8 **) b);
2508 return FcStrCmp (as, bs);
2509}
2510
2d9c79c0
KP
2511static FcBool
2512FcConfigParseAndLoadDir (FcConfig *config,
2513 const FcChar8 *name,
2514 const FcChar8 *dir,
2515 FcBool complain)
2516{
2517 DIR *d;
2518 struct dirent *e;
2519 FcBool ret = FcTrue;
2520 FcChar8 *file;
2521 FcChar8 *base;
2522 FcStrSet *files;
2523
2524 d = opendir ((char *) dir);
2525 if (!d)
2526 {
2527 if (complain)
2528 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2529 name);
2530 ret = FcFalse;
2531 goto bail0;
2532 }
2533 /* freed below */
2534 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2535 if (!file)
2536 {
2537 ret = FcFalse;
2538 goto bail1;
2539 }
d0d1f390 2540
2d9c79c0
KP
2541 strcpy ((char *) file, (char *) dir);
2542 strcat ((char *) file, "/");
2543 base = file + strlen ((char *) file);
d0d1f390 2544
2d9c79c0
KP
2545 files = FcStrSetCreate ();
2546 if (!files)
2547 {
2548 ret = FcFalse;
2549 goto bail2;
2550 }
d0d1f390 2551
2d9c79c0
KP
2552 if (FcDebug () & FC_DBG_CONFIG)
2553 printf ("\tScanning config dir %s\n", dir);
2554
2555 while (ret && (e = readdir (d)))
2556 {
8245771d
PL
2557 int d_len;
2558#define TAIL ".conf"
2559#define TAIL_LEN 5
2d9c79c0 2560 /*
8245771d 2561 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2562 */
2563 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2564 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2565 d_len > TAIL_LEN &&
2566 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2567 {
2568 strcpy ((char *) base, (char *) e->d_name);
2569 if (!FcStrSetAdd (files, file))
2570 {
2571 ret = FcFalse;
2572 goto bail3;
2573 }
2574 }
2575 }
2576 if (ret)
2577 {
2578 int i;
d0d1f390 2579 qsort (files->strs, files->num, sizeof (FcChar8 *),
9419bb34 2580 (int (*)(const void *, const void *)) FcSortCmpStr);
2d9c79c0 2581 for (i = 0; ret && i < files->num; i++)
4262e0b3 2582 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2583 }
2584bail3:
2585 FcStrSetDestroy (files);
2586bail2:
2587 free (file);
2588bail1:
2589 closedir (d);
2590bail0:
2591 return ret || !complain;
2592}
2593
24330d27
KP
2594FcBool
2595FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2596 const FcChar8 *name,
24330d27
KP
2597 FcBool complain)
2598{
24330d27 2599
c2e7c611
KP
2600 XML_Parser p;
2601 FcChar8 *filename;
3bfae75d 2602 int fd;
c2e7c611 2603 int len;
c2e7c611
KP
2604 FcConfigParse parse;
2605 FcBool error = FcTrue;
d0d1f390 2606
0d745819 2607#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2608 xmlSAXHandler sax;
2609 char buf[BUFSIZ];
2610#else
2611 void *buf;
2612#endif
d0d1f390 2613
c2e7c611
KP
2614 filename = FcConfigFilename (name);
2615 if (!filename)
2616 goto bail0;
d0d1f390 2617
cb6d97eb
PL
2618 if (FcStrSetMember (config->configFiles, filename))
2619 {
2620 FcStrFree (filename);
2621 return FcTrue;
2622 }
2623
4aded3e0 2624 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2625 {
2626 FcStrFree (filename);
4aded3e0 2627 goto bail0;
9dac3c59 2628 }
4aded3e0 2629
2d9c79c0
KP
2630 if (FcFileIsDir (filename))
2631 {
2632 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2633 FcStrFree (filename);
2634 return ret;
2635 }
2636
2637 if (FcDebug () & FC_DBG_CONFIG)
2638 printf ("\tLoading config file %s\n", filename);
2639
3bfae75d 2640 fd = open ((char *) filename, O_RDONLY);
d0d1f390 2641 if (fd == -1) {
8f2a8078 2642 FcStrFree (filename);
c2e7c611 2643 goto bail0;
8f2a8078 2644 }
d0d1f390 2645
0d745819 2646#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2647 memset(&sax, 0, sizeof(sax));
2648
2649 sax.internalSubset = FcInternalSubsetDecl;
2650 sax.externalSubset = FcExternalSubsetDecl;
2651 sax.startElement = FcStartElement;
2652 sax.endElement = FcEndElement;
2653 sax.characters = FcCharacterData;
2654
8f2a8078 2655 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2656#else
c2e7c611 2657 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2658#endif
8f2a8078 2659 FcStrFree (filename);
e99f0f0a 2660
c2e7c611
KP
2661 if (!p)
2662 goto bail1;
2663
2664 if (!FcConfigInit (&parse, name, config, p))
2665 goto bail2;
2666
0d745819 2667#ifndef ENABLE_LIBXML2
e99f0f0a 2668
c2e7c611 2669 XML_SetUserData (p, &parse);
d0d1f390 2670
c2e7c611
KP
2671 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2672 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2673 XML_SetCharacterDataHandler (p, FcCharacterData);
2674
e99f0f0a
PL
2675#endif /* ENABLE_LIBXML2 */
2676
c2e7c611 2677 do {
0d745819 2678#ifndef ENABLE_LIBXML2
c2e7c611
KP
2679 buf = XML_GetBuffer (p, BUFSIZ);
2680 if (!buf)
80c053b7 2681 {
179c3995 2682 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2683 goto bail3;
80c053b7 2684 }
e99f0f0a 2685#endif
3bfae75d 2686 len = read (fd, buf, BUFSIZ);
c2e7c611 2687 if (len < 0)
80c053b7 2688 {
179c3995 2689 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2690 goto bail3;
80c053b7 2691 }
e99f0f0a 2692
0d745819 2693#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2694 if (xmlParseChunk (p, buf, len, len == 0))
2695#else
c2e7c611 2696 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2697#endif
80c053b7 2698 {
d0d1f390 2699 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2700 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2701 goto bail3;
80c053b7 2702 }
c2e7c611
KP
2703 } while (len != 0);
2704 error = parse.error;
2705bail3:
2706 FcConfigCleanup (&parse);
2707bail2:
2708 XML_ParserFree (p);
2709bail1:
3bfae75d
PL
2710 close (fd);
2711 fd = -1;
c2e7c611
KP
2712bail0:
2713 if (error && complain)
24330d27 2714 {
c2e7c611 2715 if (name)
179c3995 2716 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2717 else
179c3995 2718 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2719 return FcFalse;
2720 }
2721 return FcTrue;
2722}
23816bf9
KP
2723#define __fcxml__
2724#include "fcaliastail.h"
2725#undef __fcxml__