]> git.wh0rd.org - fontconfig.git/blame - src/fcxml.c
Bug 22037 - No Fonts installed on a default install on Windows Server 2003
[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 2089 data = buffer;
f33a2313 2090#if _WIN32_WINNT >= 0x0500
d1567812 2091 rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
f33a2313
BE
2092#else
2093 rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
2094#endif
d1567812 2095 if (rc == 0 || rc > sizeof (buffer) - 20)
daeed6e0 2096 {
327fc9d1 2097 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
daeed6e0
TL
2098 break;
2099 }
2100 if (data [strlen (data) - 1] != '\\')
2101 strcat (data, "\\");
2102 strcat (data, "fonts");
2103 }
2104#endif
8ade2369
KP
2105 if (strlen ((char *) data) == 0)
2106 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2107 else if (!FcStrUsesHome (data) || FcConfigHome ())
ff3f1f98
KP
2108 {
2109 if (!FcConfigAddDir (parse->config, data))
f468f568 2110 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
ff3f1f98 2111 }
3ed70071 2112 FcStrBufDestroy (&parse->pstack->str);
c2e7c611 2113 break;
7410e40b
PL
2114 case FcElementCacheDir:
2115 data = FcStrBufDone (&parse->pstack->str);
2116 if (!data)
2117 {
2118 FcConfigMessage (parse, FcSevereError, "out of memory");
2119 break;
2120 }
8a3dc488
TL
2121#ifdef _WIN32
2122 if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2123 {
2124 int rc;
2125 FcStrFree (data);
2126 data = malloc (1000);
2127 if (!data)
2128 {
2129 FcConfigMessage (parse, FcSevereError, "out of memory");
2130 break;
2131 }
2132 FcMemAlloc (FC_MEM_STRING, 1000);
2133 rc = GetTempPath (800, data);
2134 if (rc == 0 || rc > 800)
2135 {
327fc9d1 2136 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
8a3dc488
TL
2137 FcStrFree (data);
2138 break;
2139 }
2140 if (data [strlen (data) - 1] != '\\')
2141 strcat (data, "\\");
2142 strcat (data, "fontconfig\\cache");
2143 }
2144#endif
7410e40b
PL
2145 if (!FcStrUsesHome (data) || FcConfigHome ())
2146 {
2147 if (!FcConfigAddCacheDir (parse->config, data))
2148 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2149 }
2150 FcStrFree (data);
2151 break;
2152
c2e7c611 2153 case FcElementCache:
3ed70071 2154 data = FcStrBufDoneStatic (&parse->pstack->str);
c2e7c611 2155 if (!data)
24330d27 2156 {
179c3995 2157 FcConfigMessage (parse, FcSevereError, "out of memory");
24330d27 2158 break;
c2e7c611 2159 }
2d3387fd 2160 /* discard this data; no longer used */
3ed70071 2161 FcStrBufDestroy (&parse->pstack->str);
c2e7c611
KP
2162 break;
2163 case FcElementInclude:
2164 FcParseInclude (parse);
2165 break;
2166 case FcElementConfig:
2167 break;
2168 case FcElementMatch:
2169 FcParseMatch (parse);
2170 break;
2171 case FcElementAlias:
2172 FcParseAlias (parse);
2173 break;
2174
2175 case FcElementBlank:
2176 FcParseBlank (parse);
2177 break;
179c3995
KP
2178 case FcElementRescan:
2179 FcParseRescan (parse);
2180 break;
c2e7c611
KP
2181
2182 case FcElementPrefer:
2183 FcParseFamilies (parse, FcVStackPrefer);
2184 break;
2185 case FcElementAccept:
2186 FcParseFamilies (parse, FcVStackAccept);
2187 break;
2188 case FcElementDefault:
2189 FcParseFamilies (parse, FcVStackDefault);
2190 break;
2191 case FcElementFamily:
2192 FcParseFamily (parse);
2193 break;
2194
2195 case FcElementTest:
2196 FcParseTest (parse);
2197 break;
2198 case FcElementEdit:
2199 FcParseEdit (parse);
2200 break;
2201
2202 case FcElementInt:
2203 FcParseInt (parse);
2204 break;
2205 case FcElementDouble:
2206 FcParseDouble (parse);
2207 break;
2208 case FcElementString:
2209 FcParseString (parse, FcVStackString);
2210 break;
2211 case FcElementMatrix:
2212 FcParseMatrix (parse);
2213 break;
2214 case FcElementBool:
2215 FcParseBool (parse);
2216 break;
2217 case FcElementCharset:
2218/* FcParseCharset (parse); */
2219 break;
d47c9d6e
KP
2220 case FcElementSelectfont:
2221 break;
2222 case FcElementAcceptfont:
2223 case FcElementRejectfont:
2224 FcParseAcceptRejectFont (parse, parse->pstack->element);
2225 break;
2226 case FcElementGlob:
2227 FcParseString (parse, FcVStackGlob);
2228 break;
4f27c1c0
KP
2229 case FcElementPattern:
2230 FcParsePattern (parse);
2231 break;
2232 case FcElementPatelt:
2233 FcParsePatelt (parse);
2234 break;
c2e7c611
KP
2235 case FcElementName:
2236 FcParseString (parse, FcVStackField);
2237 break;
2238 case FcElementConst:
2239 FcParseString (parse, FcVStackConstant);
2240 break;
2241 case FcElementOr:
3f7653c2 2242 FcParseBinary (parse, FcOpOr);
c2e7c611
KP
2243 break;
2244 case FcElementAnd:
3f7653c2 2245 FcParseBinary (parse, FcOpAnd);
c2e7c611
KP
2246 break;
2247 case FcElementEq:
3f7653c2 2248 FcParseBinary (parse, FcOpEqual);
c2e7c611
KP
2249 break;
2250 case FcElementNotEq:
3f7653c2 2251 FcParseBinary (parse, FcOpNotEqual);
c2e7c611
KP
2252 break;
2253 case FcElementLess:
3f7653c2 2254 FcParseBinary (parse, FcOpLess);
c2e7c611
KP
2255 break;
2256 case FcElementLessEq:
3f7653c2 2257 FcParseBinary (parse, FcOpLessEqual);
c2e7c611
KP
2258 break;
2259 case FcElementMore:
3f7653c2 2260 FcParseBinary (parse, FcOpMore);
c2e7c611
KP
2261 break;
2262 case FcElementMoreEq:
3f7653c2 2263 FcParseBinary (parse, FcOpMoreEqual);
c2e7c611 2264 break;
47d4f950 2265 case FcElementContains:
3f7653c2 2266 FcParseBinary (parse, FcOpContains);
47d4f950
KP
2267 break;
2268 case FcElementNotContains:
3f7653c2 2269 FcParseBinary (parse, FcOpNotContains);
47d4f950 2270 break;
c2e7c611 2271 case FcElementPlus:
3f7653c2 2272 FcParseBinary (parse, FcOpPlus);
c2e7c611
KP
2273 break;
2274 case FcElementMinus:
3f7653c2 2275 FcParseBinary (parse, FcOpMinus);
c2e7c611
KP
2276 break;
2277 case FcElementTimes:
3f7653c2 2278 FcParseBinary (parse, FcOpTimes);
c2e7c611
KP
2279 break;
2280 case FcElementDivide:
3f7653c2 2281 FcParseBinary (parse, FcOpDivide);
c2e7c611
KP
2282 break;
2283 case FcElementNot:
3f7653c2 2284 FcParseUnary (parse, FcOpNot);
c2e7c611
KP
2285 break;
2286 case FcElementIf:
3f7653c2
KP
2287 FcParseBinary (parse, FcOpQuest);
2288 break;
2289 case FcElementFloor:
2290 FcParseUnary (parse, FcOpFloor);
2291 break;
2292 case FcElementCeil:
2293 FcParseUnary (parse, FcOpCeil);
2294 break;
2295 case FcElementRound:
2296 FcParseUnary (parse, FcOpRound);
2297 break;
2298 case FcElementTrunc:
2299 FcParseUnary (parse, FcOpTrunc);
c2e7c611
KP
2300 break;
2301 case FcElementUnknown:
2302 break;
24330d27 2303 }
c2e7c611
KP
2304 (void) FcPStackPop (parse);
2305}
2306
2307static void
2308FcCharacterData (void *userData, const XML_Char *s, int len)
2309{
2310 FcConfigParse *parse = userData;
2311
2312 if (!parse->pstack)
2313 return;
2314 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
179c3995 2315 FcConfigMessage (parse, FcSevereError, "out of memory");
c2e7c611
KP
2316}
2317
2318static void
2319FcStartDoctypeDecl (void *userData,
2320 const XML_Char *doctypeName,
2321 const XML_Char *sysid,
2322 const XML_Char *pubid,
2323 int has_internal_subset)
2324{
2325 FcConfigParse *parse = userData;
2326
2327 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
179c3995 2328 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
c2e7c611
KP
2329}
2330
0d745819 2331#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2332
2333static void
2334FcInternalSubsetDecl (void *userData,
2335 const XML_Char *doctypeName,
2336 const XML_Char *sysid,
2337 const XML_Char *pubid)
2338{
2339 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2340}
2341
2342static void
2343FcExternalSubsetDecl (void *userData,
2344 const XML_Char *doctypeName,
2345 const XML_Char *sysid,
2346 const XML_Char *pubid)
2347{
2348 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2349}
2350
2351#else /* ENABLE_LIBXML2 */
2352
c2e7c611
KP
2353static void
2354FcEndDoctypeDecl (void *userData)
2355{
24330d27
KP
2356}
2357
e99f0f0a
PL
2358#endif /* ENABLE_LIBXML2 */
2359
9419bb34
KP
2360static int
2361FcSortCmpStr (const void *a, const void *b)
2362{
2363 const FcChar8 *as = *((FcChar8 **) a);
2364 const FcChar8 *bs = *((FcChar8 **) b);
2365 return FcStrCmp (as, bs);
2366}
2367
2d9c79c0
KP
2368static FcBool
2369FcConfigParseAndLoadDir (FcConfig *config,
2370 const FcChar8 *name,
2371 const FcChar8 *dir,
2372 FcBool complain)
2373{
2374 DIR *d;
2375 struct dirent *e;
2376 FcBool ret = FcTrue;
2377 FcChar8 *file;
2378 FcChar8 *base;
2379 FcStrSet *files;
2380
2381 d = opendir ((char *) dir);
2382 if (!d)
2383 {
2384 if (complain)
2385 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2386 name);
2387 ret = FcFalse;
2388 goto bail0;
2389 }
2390 /* freed below */
2391 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2392 if (!file)
2393 {
2394 ret = FcFalse;
2395 goto bail1;
2396 }
2397
2398 strcpy ((char *) file, (char *) dir);
2399 strcat ((char *) file, "/");
2400 base = file + strlen ((char *) file);
2401
2402 files = FcStrSetCreate ();
2403 if (!files)
2404 {
2405 ret = FcFalse;
2406 goto bail2;
2407 }
2408
2409 if (FcDebug () & FC_DBG_CONFIG)
2410 printf ("\tScanning config dir %s\n", dir);
2411
2412 while (ret && (e = readdir (d)))
2413 {
8245771d
PL
2414 int d_len;
2415#define TAIL ".conf"
2416#define TAIL_LEN 5
2d9c79c0 2417 /*
8245771d 2418 * Add all files of the form [0-9]*.conf
2d9c79c0
KP
2419 */
2420 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
8245771d
PL
2421 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2422 d_len > TAIL_LEN &&
2423 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2d9c79c0
KP
2424 {
2425 strcpy ((char *) base, (char *) e->d_name);
2426 if (!FcStrSetAdd (files, file))
2427 {
2428 ret = FcFalse;
2429 goto bail3;
2430 }
2431 }
2432 }
2433 if (ret)
2434 {
2435 int i;
4262e0b3 2436 qsort (files->strs, files->num, sizeof (FcChar8 *),
9419bb34 2437 (int (*)(const void *, const void *)) FcSortCmpStr);
2d9c79c0 2438 for (i = 0; ret && i < files->num; i++)
4262e0b3 2439 ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2d9c79c0
KP
2440 }
2441bail3:
2442 FcStrSetDestroy (files);
2443bail2:
2444 free (file);
2445bail1:
2446 closedir (d);
2447bail0:
2448 return ret || !complain;
2449}
2450
24330d27
KP
2451FcBool
2452FcConfigParseAndLoad (FcConfig *config,
c2e7c611 2453 const FcChar8 *name,
24330d27
KP
2454 FcBool complain)
2455{
24330d27 2456
c2e7c611
KP
2457 XML_Parser p;
2458 FcChar8 *filename;
3bfae75d 2459 int fd;
c2e7c611 2460 int len;
c2e7c611
KP
2461 FcConfigParse parse;
2462 FcBool error = FcTrue;
2463
0d745819 2464#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2465 xmlSAXHandler sax;
2466 char buf[BUFSIZ];
2467#else
2468 void *buf;
2469#endif
2470
c2e7c611
KP
2471 filename = FcConfigFilename (name);
2472 if (!filename)
2473 goto bail0;
4aded3e0 2474
cb6d97eb
PL
2475 if (FcStrSetMember (config->configFiles, filename))
2476 {
2477 FcStrFree (filename);
2478 return FcTrue;
2479 }
2480
4aded3e0 2481 if (!FcStrSetAdd (config->configFiles, filename))
9dac3c59
KP
2482 {
2483 FcStrFree (filename);
4aded3e0 2484 goto bail0;
9dac3c59 2485 }
4aded3e0 2486
2d9c79c0
KP
2487 if (FcFileIsDir (filename))
2488 {
2489 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2490 FcStrFree (filename);
2491 return ret;
2492 }
2493
2494 if (FcDebug () & FC_DBG_CONFIG)
2495 printf ("\tLoading config file %s\n", filename);
2496
3bfae75d
PL
2497 fd = open ((char *) filename, O_RDONLY);
2498 if (fd == -1) {
8f2a8078 2499 FcStrFree (filename);
c2e7c611 2500 goto bail0;
8f2a8078 2501 }
c2e7c611 2502
0d745819 2503#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2504 memset(&sax, 0, sizeof(sax));
2505
2506 sax.internalSubset = FcInternalSubsetDecl;
2507 sax.externalSubset = FcExternalSubsetDecl;
2508 sax.startElement = FcStartElement;
2509 sax.endElement = FcEndElement;
2510 sax.characters = FcCharacterData;
2511
8f2a8078 2512 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
e99f0f0a 2513#else
c2e7c611 2514 p = XML_ParserCreate ("UTF-8");
e99f0f0a 2515#endif
8f2a8078 2516 FcStrFree (filename);
e99f0f0a 2517
c2e7c611
KP
2518 if (!p)
2519 goto bail1;
2520
2521 if (!FcConfigInit (&parse, name, config, p))
2522 goto bail2;
2523
0d745819 2524#ifndef ENABLE_LIBXML2
e99f0f0a 2525
c2e7c611
KP
2526 XML_SetUserData (p, &parse);
2527
2528 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2529 XML_SetElementHandler (p, FcStartElement, FcEndElement);
2530 XML_SetCharacterDataHandler (p, FcCharacterData);
2531
e99f0f0a
PL
2532#endif /* ENABLE_LIBXML2 */
2533
c2e7c611 2534 do {
0d745819 2535#ifndef ENABLE_LIBXML2
c2e7c611
KP
2536 buf = XML_GetBuffer (p, BUFSIZ);
2537 if (!buf)
80c053b7 2538 {
179c3995 2539 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
c2e7c611 2540 goto bail3;
80c053b7 2541 }
e99f0f0a 2542#endif
3bfae75d 2543 len = read (fd, buf, BUFSIZ);
c2e7c611 2544 if (len < 0)
80c053b7 2545 {
179c3995 2546 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
c2e7c611 2547 goto bail3;
80c053b7 2548 }
e99f0f0a 2549
0d745819 2550#ifdef ENABLE_LIBXML2
e99f0f0a
PL
2551 if (xmlParseChunk (p, buf, len, len == 0))
2552#else
c2e7c611 2553 if (!XML_ParseBuffer (p, len, len == 0))
e99f0f0a 2554#endif
80c053b7 2555 {
179c3995 2556 FcConfigMessage (&parse, FcSevereError, "%s",
80c053b7 2557 XML_ErrorString (XML_GetErrorCode (p)));
c2e7c611 2558 goto bail3;
80c053b7 2559 }
c2e7c611
KP
2560 } while (len != 0);
2561 error = parse.error;
2562bail3:
2563 FcConfigCleanup (&parse);
2564bail2:
2565 XML_ParserFree (p);
2566bail1:
3bfae75d
PL
2567 close (fd);
2568 fd = -1;
c2e7c611
KP
2569bail0:
2570 if (error && complain)
24330d27 2571 {
c2e7c611 2572 if (name)
179c3995 2573 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
24330d27 2574 else
179c3995 2575 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
24330d27
KP
2576 return FcFalse;
2577 }
2578 return FcTrue;
2579}
23816bf9
KP
2580#define __fcxml__
2581#include "fcaliastail.h"
2582#undef __fcxml__