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