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