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