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