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