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