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