]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Add a bunch more languages that use the Latin alphabet
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.14 2002/06/21 07:01:11 keithp Exp $
3 *
4 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
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
25 #include <stdarg.h>
26 #include "fcint.h"
27
28 #ifndef HAVE_EXPAT
29 #define HAVE_EXPAT 1
30 #endif
31
32 #ifndef HAVE_XML2
33 #define HAVE_XML2 0
34 #endif
35
36 #if HAVE_EXPAT
37 #ifndef HAVE_XMLPARSE_H
38 #define HAVE_XMLPARSE_H 0
39 #endif
40 #if HAVE_XMLPARSE_H
41 #include <xmlparse.h>
42 #else
43 #include <expat.h>
44 #endif
45 #endif
46
47 #if HAVE_XML2
48 #include "fclibxml2.h"
49 #endif
50
51 FcTest *
52 FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr)
53 {
54 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
55
56 if (test)
57 {
58 test->next = 0;
59 test->qual = qual;
60 test->field = (char *) FcStrCopy (field);
61 test->op = compare;
62 test->expr = expr;
63 }
64 return test;
65 }
66
67 void
68 FcTestDestroy (FcTest *test)
69 {
70 if (test->next)
71 FcTestDestroy (test->next);
72 FcExprDestroy (test->expr);
73 FcStrFree ((FcChar8 *) test->field);
74 free (test);
75 }
76
77 FcExpr *
78 FcExprCreateInteger (int i)
79 {
80 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
81
82 if (e)
83 {
84 e->op = FcOpInteger;
85 e->u.ival = i;
86 }
87 return e;
88 }
89
90 FcExpr *
91 FcExprCreateDouble (double d)
92 {
93 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
94
95 if (e)
96 {
97 e->op = FcOpDouble;
98 e->u.dval = d;
99 }
100 return e;
101 }
102
103 FcExpr *
104 FcExprCreateString (const FcChar8 *s)
105 {
106 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
107
108 if (e)
109 {
110 e->op = FcOpString;
111 e->u.sval = FcStrCopy (s);
112 }
113 return e;
114 }
115
116 FcExpr *
117 FcExprCreateMatrix (const FcMatrix *m)
118 {
119 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
120
121 if (e)
122 {
123 e->op = FcOpMatrix;
124 e->u.mval = FcMatrixCopy (m);
125 }
126 return e;
127 }
128
129 FcExpr *
130 FcExprCreateBool (FcBool b)
131 {
132 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
133
134 if (e)
135 {
136 e->op = FcOpBool;
137 e->u.bval = b;
138 }
139 return e;
140 }
141
142 FcExpr *
143 FcExprCreateNil (void)
144 {
145 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
146
147 if (e)
148 {
149 e->op = FcOpNil;
150 }
151 return e;
152 }
153
154 FcExpr *
155 FcExprCreateField (const char *field)
156 {
157 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
158
159 if (e)
160 {
161 e->op = FcOpField;
162 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
163 }
164 return e;
165 }
166
167 FcExpr *
168 FcExprCreateConst (const FcChar8 *constant)
169 {
170 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
171
172 if (e)
173 {
174 e->op = FcOpConst;
175 e->u.constant = FcStrCopy (constant);
176 }
177 return e;
178 }
179
180 FcExpr *
181 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
182 {
183 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
184
185 if (e)
186 {
187 e->op = op;
188 e->u.tree.left = left;
189 e->u.tree.right = right;
190 }
191 return e;
192 }
193
194 void
195 FcExprDestroy (FcExpr *e)
196 {
197 switch (e->op) {
198 case FcOpInteger:
199 break;
200 case FcOpDouble:
201 break;
202 case FcOpString:
203 FcStrFree (e->u.sval);
204 break;
205 case FcOpMatrix:
206 FcMatrixFree (e->u.mval);
207 break;
208 case FcOpCharSet:
209 FcCharSetDestroy (e->u.cval);
210 break;
211 case FcOpBool:
212 break;
213 case FcOpField:
214 FcStrFree ((FcChar8 *) e->u.field);
215 break;
216 case FcOpConst:
217 FcStrFree (e->u.constant);
218 break;
219 case FcOpAssign:
220 case FcOpAssignReplace:
221 case FcOpPrepend:
222 case FcOpPrependFirst:
223 case FcOpAppend:
224 case FcOpAppendLast:
225 break;
226 case FcOpOr:
227 case FcOpAnd:
228 case FcOpEqual:
229 case FcOpContains:
230 case FcOpNotEqual:
231 case FcOpLess:
232 case FcOpLessEqual:
233 case FcOpMore:
234 case FcOpMoreEqual:
235 case FcOpPlus:
236 case FcOpMinus:
237 case FcOpTimes:
238 case FcOpDivide:
239 case FcOpQuest:
240 case FcOpComma:
241 FcExprDestroy (e->u.tree.right);
242 /* fall through */
243 case FcOpNot:
244 FcExprDestroy (e->u.tree.left);
245 break;
246 case FcOpNil:
247 case FcOpInvalid:
248 break;
249 }
250 free (e);
251 }
252
253 FcEdit *
254 FcEditCreate (const char *field, FcOp op, FcExpr *expr)
255 {
256 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
257
258 if (e)
259 {
260 e->next = 0;
261 e->field = field; /* already saved in grammar */
262 e->op = op;
263 e->expr = expr;
264 }
265 return e;
266 }
267
268 void
269 FcEditDestroy (FcEdit *e)
270 {
271 if (e->next)
272 FcEditDestroy (e->next);
273 FcStrFree ((FcChar8 *) e->field);
274 if (e->expr)
275 FcExprDestroy (e->expr);
276 }
277
278 char *
279 FcConfigSaveField (const char *field)
280 {
281 return (char *) FcStrCopy ((FcChar8 *) field);
282 }
283
284 typedef enum _FcElement {
285 FcElementNone,
286 FcElementFontconfig,
287 FcElementDir,
288 FcElementCache,
289 FcElementInclude,
290 FcElementConfig,
291 FcElementMatch,
292 FcElementAlias,
293
294 FcElementBlank,
295 FcElementRescan,
296
297 FcElementPrefer,
298 FcElementAccept,
299 FcElementDefault,
300 FcElementFamily,
301
302 FcElementTest,
303 FcElementEdit,
304 FcElementInt,
305 FcElementDouble,
306 FcElementString,
307 FcElementMatrix,
308 FcElementBool,
309 FcElementCharset,
310 FcElementName,
311 FcElementConst,
312 FcElementOr,
313 FcElementAnd,
314 FcElementEq,
315 FcElementNotEq,
316 FcElementLess,
317 FcElementLessEq,
318 FcElementMore,
319 FcElementMoreEq,
320 FcElementPlus,
321 FcElementMinus,
322 FcElementTimes,
323 FcElementDivide,
324 FcElementNot,
325 FcElementIf,
326 FcElementUnknown
327 } FcElement;
328
329 static FcElement
330 FcElementMap (const XML_Char *name)
331 {
332 static struct {
333 char *name;
334 FcElement element;
335 } fcElementMap[] = {
336 { "fontconfig", FcElementFontconfig },
337 { "dir", FcElementDir },
338 { "cache", FcElementCache },
339 { "include", FcElementInclude },
340 { "config", FcElementConfig },
341 { "match", FcElementMatch },
342 { "alias", FcElementAlias },
343
344 { "blank", FcElementBlank },
345 { "rescan", FcElementRescan },
346
347 { "prefer", FcElementPrefer },
348 { "accept", FcElementAccept },
349 { "default", FcElementDefault },
350 { "family", FcElementFamily },
351
352 { "test", FcElementTest },
353 { "edit", FcElementEdit },
354 { "int", FcElementInt },
355 { "double", FcElementDouble },
356 { "string", FcElementString },
357 { "matrix", FcElementMatrix },
358 { "bool", FcElementBool },
359 { "charset", FcElementCharset },
360 { "name", FcElementName },
361 { "const", FcElementConst },
362 { "or", FcElementOr },
363 { "and", FcElementAnd },
364 { "eq", FcElementEq },
365 { "not_eq", FcElementNotEq },
366 { "less", FcElementLess },
367 { "less_eq", FcElementLessEq },
368 { "more", FcElementMore },
369 { "more_eq", FcElementMoreEq },
370 { "plus", FcElementPlus },
371 { "minus", FcElementMinus },
372 { "times", FcElementTimes },
373 { "divide", FcElementDivide },
374 { "not", FcElementNot },
375 { "if", FcElementIf },
376
377 { 0, 0 }
378 };
379
380 int i;
381 for (i = 0; fcElementMap[i].name; i++)
382 if (!strcmp ((char *) name, fcElementMap[i].name))
383 return fcElementMap[i].element;
384 return FcElementUnknown;
385 }
386
387 typedef struct _FcPStack {
388 struct _FcPStack *prev;
389 FcElement element;
390 FcChar8 **attr;
391 FcStrBuf str;
392 } FcPStack;
393
394 typedef enum _FcVStackTag {
395 FcVStackNone,
396
397 FcVStackString,
398 FcVStackFamily,
399 FcVStackField,
400 FcVStackConstant,
401
402 FcVStackPrefer,
403 FcVStackAccept,
404 FcVStackDefault,
405
406 FcVStackInteger,
407 FcVStackDouble,
408 FcVStackMatrix,
409 FcVStackBool,
410
411 FcVStackTest,
412 FcVStackExpr,
413 FcVStackEdit
414 } FcVStackTag;
415
416 typedef struct _FcVStack {
417 struct _FcVStack *prev;
418 FcPStack *pstack; /* related parse element */
419 FcVStackTag tag;
420 union {
421 FcChar8 *string;
422
423 int integer;
424 double _double;
425 FcMatrix *matrix;
426 FcBool bool;
427
428 FcTest *test;
429 FcQual qual;
430 FcOp op;
431 FcExpr *expr;
432 FcEdit *edit;
433 } u;
434 } FcVStack;
435
436 typedef struct _FcConfigParse {
437 FcPStack *pstack;
438 FcVStack *vstack;
439 FcBool error;
440 const FcChar8 *name;
441 FcConfig *config;
442 XML_Parser parser;
443 } FcConfigParse;
444
445 typedef enum _FcConfigSeverity {
446 FcSevereInfo, FcSevereWarning, FcSevereError
447 } FcConfigSeverity;
448
449 static void
450 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
451 {
452 char *s = "unknown";
453 va_list args;
454
455 va_start (args, fmt);
456
457 switch (severe) {
458 case FcSevereInfo: s = "info"; break;
459 case FcSevereWarning: s = "warning"; break;
460 case FcSevereError: s = "error"; break;
461 }
462 if (parse)
463 {
464 if (parse->name)
465 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
466 parse->name, XML_GetCurrentLineNumber (parse->parser));
467 else
468 fprintf (stderr, "Fontconfig %s: line %d: ", s,
469 XML_GetCurrentLineNumber (parse->parser));
470 if (severe >= FcSevereError)
471 parse->error = FcTrue;
472 }
473 else
474 fprintf (stderr, "Fontconfig %s: ", s);
475 vfprintf (stderr, fmt, args);
476 fprintf (stderr, "\n");
477 va_end (args);
478 }
479
480 static void
481 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
482 {
483 vstack->prev = parse->vstack;
484 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
485 parse->vstack = vstack;
486 }
487
488 static FcVStack *
489 FcVStackCreate (void)
490 {
491 FcVStack *new;
492
493 new = malloc (sizeof (FcVStack));
494 if (!new)
495 return 0;
496 new->tag = FcVStackNone;
497 new->prev = 0;
498 return new;
499 }
500
501 static void
502 FcVStackDestroy (FcVStack *vstack)
503 {
504 FcVStack *prev;
505
506 for (; vstack; vstack = prev)
507 {
508 prev = vstack->prev;
509 switch (vstack->tag) {
510 case FcVStackNone:
511 break;
512 case FcVStackString:
513 case FcVStackFamily:
514 case FcVStackField:
515 case FcVStackConstant:
516 FcStrFree (vstack->u.string);
517 break;
518 case FcVStackInteger:
519 case FcVStackDouble:
520 break;
521 case FcVStackMatrix:
522 FcMatrixFree (vstack->u.matrix);
523 break;
524 case FcVStackBool:
525 break;
526 case FcVStackTest:
527 FcTestDestroy (vstack->u.test);
528 break;
529 case FcVStackExpr:
530 case FcVStackPrefer:
531 case FcVStackAccept:
532 case FcVStackDefault:
533 FcExprDestroy (vstack->u.expr);
534 break;
535 case FcVStackEdit:
536 FcEditDestroy (vstack->u.edit);
537 break;
538 }
539 free (vstack);
540 }
541 }
542
543 static FcBool
544 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
545 {
546 FcVStack *vstack = FcVStackCreate ();
547 if (!vstack)
548 return FcFalse;
549 vstack->u.string = string;
550 vstack->tag = tag;
551 FcVStackPush (parse, vstack);
552 return FcTrue;
553 }
554
555 static FcBool
556 FcVStackPushInteger (FcConfigParse *parse, int integer)
557 {
558 FcVStack *vstack = FcVStackCreate ();
559 if (!vstack)
560 return FcFalse;
561 vstack->u.integer = integer;
562 vstack->tag = FcVStackInteger;
563 FcVStackPush (parse, vstack);
564 return FcTrue;
565 }
566
567 static FcBool
568 FcVStackPushDouble (FcConfigParse *parse, double _double)
569 {
570 FcVStack *vstack = FcVStackCreate ();
571 if (!vstack)
572 return FcFalse;
573 vstack->u._double = _double;
574 vstack->tag = FcVStackDouble;
575 FcVStackPush (parse, vstack);
576 return FcTrue;
577 }
578
579 static FcBool
580 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
581 {
582 FcVStack *vstack = FcVStackCreate ();
583 if (!vstack)
584 return FcFalse;
585 matrix = FcMatrixCopy (matrix);
586 if (!matrix)
587 {
588 FcVStackDestroy (vstack);
589 return FcFalse;
590 }
591 vstack->u.matrix = matrix;
592 vstack->tag = FcVStackMatrix;
593 FcVStackPush (parse, vstack);
594 return FcTrue;
595 }
596
597 static FcBool
598 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
599 {
600 FcVStack *vstack = FcVStackCreate ();
601 if (!vstack)
602 return FcFalse;
603 vstack->u.bool = bool;
604 vstack->tag = FcVStackBool;
605 FcVStackPush (parse, vstack);
606 return FcTrue;
607 }
608
609 static FcBool
610 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
611 {
612 FcVStack *vstack = FcVStackCreate ();
613 if (!vstack)
614 return FcFalse;
615 vstack->u.test = test;
616 vstack->tag = FcVStackTest;
617 FcVStackPush (parse, vstack);
618 return FcTrue;
619 }
620
621 static FcBool
622 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
623 {
624 FcVStack *vstack = FcVStackCreate ();
625 if (!vstack)
626 return FcFalse;
627 vstack->u.expr = expr;
628 vstack->tag = tag;
629 FcVStackPush (parse, vstack);
630 return FcTrue;
631 }
632
633 static FcBool
634 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
635 {
636 FcVStack *vstack = FcVStackCreate ();
637 if (!vstack)
638 return FcFalse;
639 vstack->u.edit = edit;
640 vstack->tag = FcVStackEdit;
641 FcVStackPush (parse, vstack);
642 return FcTrue;
643 }
644
645 static FcVStack *
646 FcVStackFetch (FcConfigParse *parse, int off)
647 {
648 FcVStack *vstack;
649
650 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
651 return vstack;
652 }
653
654 static void
655 FcVStackClear (FcConfigParse *parse)
656 {
657 while (parse->vstack && parse->vstack->pstack == parse->pstack)
658 {
659 FcVStack *vstack = parse->vstack;
660 parse->vstack = vstack->prev;
661 vstack->prev = 0;
662 FcVStackDestroy (vstack);
663 }
664 }
665
666 static FcVStack *
667 FcVStackPop (FcConfigParse *parse)
668 {
669 FcVStack *vstack = parse->vstack;
670
671 if (!vstack || vstack->pstack != parse->pstack)
672 return 0;
673 parse->vstack = vstack->prev;
674 vstack->prev = 0;
675 return vstack;
676 }
677
678 static int
679 FcVStackElements (FcConfigParse *parse)
680 {
681 int h = 0;
682 FcVStack *vstack = parse->vstack;
683 while (vstack && vstack->pstack == parse->pstack)
684 {
685 h++;
686 vstack = vstack->prev;
687 }
688 return h;
689 }
690
691 static FcChar8 **
692 FcConfigSaveAttr (const XML_Char **attr)
693 {
694 int n;
695 int slen;
696 int i;
697 FcChar8 **new;
698 FcChar8 *s;
699
700 if (!attr)
701 return 0;
702 slen = 0;
703 for (i = 0; attr[i]; i++)
704 slen += strlen (attr[i]) + 1;
705 n = i;
706 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
707 if (!new)
708 return 0;
709 s = (FcChar8 *) (new + (i + 1));
710 for (i = 0; attr[i]; i++)
711 {
712 new[i] = s;
713 strcpy ((char *) s, (char *) attr[i]);
714 s += strlen ((char *) s) + 1;
715 }
716 new[i] = 0;
717 return new;
718 }
719
720 static FcBool
721 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
722 {
723 FcPStack *new = malloc (sizeof (FcPStack));
724
725 if (!new)
726 return FcFalse;
727 new->prev = parse->pstack;
728 new->element = element;
729 if (attr)
730 {
731 new->attr = FcConfigSaveAttr (attr);
732 if (!new->attr)
733 FcConfigMessage (parse, FcSevereError, "out of memory");
734 }
735 else
736 new->attr = 0;
737 FcStrBufInit (&new->str, 0, 0);
738 parse->pstack = new;
739 return FcTrue;
740 }
741
742 static FcBool
743 FcPStackPop (FcConfigParse *parse)
744 {
745 FcPStack *old;
746
747 if (!parse->pstack)
748 {
749 FcConfigMessage (parse, FcSevereError, "mismatching element");
750 return FcFalse;
751 }
752 FcVStackClear (parse);
753 old = parse->pstack;
754 parse->pstack = old->prev;
755 FcStrBufDestroy (&old->str);
756 if (old->attr)
757 free (old->attr);
758 free (old);
759 return FcTrue;
760 }
761
762 static FcBool
763 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
764 {
765 parse->pstack = 0;
766 parse->vstack = 0;
767 parse->error = FcFalse;
768 parse->name = name;
769 parse->config = config;
770 parse->parser = parser;
771 return FcTrue;
772 }
773
774 static void
775 FcConfigCleanup (FcConfigParse *parse)
776 {
777 while (parse->pstack)
778 FcPStackPop (parse);
779 }
780
781 static const FcChar8 *
782 FcConfigGetAttribute (FcConfigParse *parse, char *attr)
783 {
784 FcChar8 **attrs;
785 if (!parse->pstack)
786 return 0;
787
788 attrs = parse->pstack->attr;
789 while (*attrs)
790 {
791 if (!strcmp ((char *) *attrs, attr))
792 return attrs[1];
793 attrs += 2;
794 }
795 return 0;
796 }
797
798 static void
799 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
800 {
801 FcConfigParse *parse = userData;
802 FcElement element;
803
804 element = FcElementMap (name);
805 if (element == FcElementUnknown)
806 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
807
808 if (!FcPStackPush (parse, element, attr))
809 {
810 FcConfigMessage (parse, FcSevereError, "out of memory");
811 return;
812 }
813 return;
814 }
815
816 static void
817 FcParseBlank (FcConfigParse *parse)
818 {
819 int n = FcVStackElements (parse);
820 while (n-- > 0)
821 {
822 FcVStack *v = FcVStackFetch (parse, n);
823 if (v->tag != FcVStackInteger)
824 FcConfigMessage (parse, FcSevereError, "non-integer blank");
825 else
826 {
827 if (!parse->config->blanks)
828 {
829 parse->config->blanks = FcBlanksCreate ();
830 if (!parse->config->blanks)
831 {
832 FcConfigMessage (parse, FcSevereError, "out of memory");
833 break;
834 }
835 }
836 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
837 {
838 FcConfigMessage (parse, FcSevereError, "out of memory");
839 break;
840 }
841 }
842 }
843 }
844
845 static void
846 FcParseRescan (FcConfigParse *parse)
847 {
848 int n = FcVStackElements (parse);
849 while (n-- > 0)
850 {
851 FcVStack *v = FcVStackFetch (parse, n);
852 if (v->tag != FcVStackInteger)
853 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
854 else
855 parse->config->rescanInterval = v->u.integer;
856 }
857 }
858
859 static void
860 FcParseInt (FcConfigParse *parse)
861 {
862 FcChar8 *s, *end;
863 int l;
864
865 if (!parse->pstack)
866 return;
867 s = FcStrBufDone (&parse->pstack->str);
868 if (!s)
869 {
870 FcConfigMessage (parse, FcSevereError, "out of memory");
871 return;
872 }
873 end = 0;
874 l = (int) strtol ((char *) s, (char **)&end, 0);
875 if (end != s + strlen ((char *) s))
876 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
877 else
878 FcVStackPushInteger (parse, l);
879 FcStrFree (s);
880 }
881
882 /*
883 * idea copied from glib g_ascii_strtod with
884 * permission of the author (Alexander Larsson)
885 */
886
887 #include <locale.h>
888
889 static double
890 FcStrtod (char *s, char **end)
891 {
892 struct lconv *locale_data;
893 char *dot;
894 double v;
895
896 /*
897 * Have to swap the decimal point to match the current locale
898 * if that locale doesn't use 0x2e
899 */
900 if ((dot = strchr (s, 0x2e)) &&
901 (locale_data = localeconv ()) &&
902 (locale_data->decimal_point[0] != 0x2e ||
903 locale_data->decimal_point[1] != 0))
904 {
905 char buf[128];
906 int slen = strlen (s);
907 int dlen = strlen (locale_data->decimal_point);
908
909 if (slen + dlen > sizeof (buf))
910 {
911 if (end)
912 *end = s;
913 v = 0;
914 }
915 else
916 {
917 char *buf_end;
918 /* mantissa */
919 strncpy (buf, s, dot - s);
920 /* decimal point */
921 strcpy (buf + (dot - s), locale_data->decimal_point);
922 /* rest of number */
923 strcpy (buf + (dot - s) + dlen, dot + 1);
924 buf_end = 0;
925 v = strtod (buf, &buf_end);
926 if (buf_end)
927 buf_end = s + (buf_end - buf);
928 if (end)
929 *end = buf_end;
930 }
931 }
932 else
933 v = strtod (s, end);
934 return v;
935 }
936
937 static void
938 FcParseDouble (FcConfigParse *parse)
939 {
940 FcChar8 *s, *end;
941 double d;
942
943 if (!parse->pstack)
944 return;
945 s = FcStrBufDone (&parse->pstack->str);
946 if (!s)
947 {
948 FcConfigMessage (parse, FcSevereError, "out of memory");
949 return;
950 }
951 end = 0;
952 d = FcStrtod ((char *) s, (char **)&end);
953 if (end != s + strlen ((char *) s))
954 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
955 else
956 FcVStackPushDouble (parse, d);
957 FcStrFree (s);
958 }
959
960 static void
961 FcParseString (FcConfigParse *parse, FcVStackTag tag)
962 {
963 FcChar8 *s;
964
965 if (!parse->pstack)
966 return;
967 s = FcStrBufDone (&parse->pstack->str);
968 if (!s)
969 {
970 FcConfigMessage (parse, FcSevereError, "out of memory");
971 return;
972 }
973 if (!FcVStackPushString (parse, tag, s))
974 FcStrFree (s);
975 }
976
977 static void
978 FcParseMatrix (FcConfigParse *parse)
979 {
980 FcVStack *vstack;
981 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
982 FcMatrix m;
983
984 while ((vstack = FcVStackPop (parse)))
985 {
986 double v;
987 switch (vstack->tag) {
988 case FcVStackInteger:
989 v = vstack->u.integer;
990 break;
991 case FcVStackDouble:
992 v = vstack->u._double;
993 break;
994 default:
995 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
996 v = 1.0;
997 break;
998 }
999 switch (matrix_state) {
1000 case m_xx: m.xx = v; break;
1001 case m_xy: m.xy = v; break;
1002 case m_yx: m.yx = v; break;
1003 case m_yy: m.yy = v; break;
1004 default: break;
1005 }
1006 matrix_state--;
1007 }
1008 if (matrix_state != m_done)
1009 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1010 else
1011 FcVStackPushMatrix (parse, &m);
1012 }
1013
1014 static FcBool
1015 FcConfigLexBool (const FcChar8 *bool)
1016 {
1017 if (*bool == 't' || *bool == 'T')
1018 return FcTrue;
1019 if (*bool == 'y' || *bool == 'Y')
1020 return FcTrue;
1021 if (*bool == '1')
1022 return FcTrue;
1023 return FcFalse;
1024 }
1025
1026 static void
1027 FcParseBool (FcConfigParse *parse)
1028 {
1029 FcChar8 *s;
1030
1031 if (!parse->pstack)
1032 return;
1033 s = FcStrBufDone (&parse->pstack->str);
1034 if (!s)
1035 {
1036 FcConfigMessage (parse, FcSevereError, "out of memory");
1037 return;
1038 }
1039 FcVStackPushBool (parse, FcConfigLexBool (s));
1040 FcStrFree (s);
1041 }
1042
1043 static void
1044 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1045 {
1046 FcVStack *vstack;
1047 FcExpr *left, *expr = 0, *new;
1048
1049 while ((vstack = FcVStackPop (parse)))
1050 {
1051 if (vstack->tag != FcVStackFamily)
1052 {
1053 FcConfigMessage (parse, FcSevereWarning, "non-family");
1054 FcVStackDestroy (vstack);
1055 continue;
1056 }
1057 left = vstack->u.expr;
1058 vstack->tag = FcVStackNone;
1059 FcVStackDestroy (vstack);
1060 if (expr)
1061 {
1062 new = FcExprCreateOp (left, FcOpComma, expr);
1063 if (!new)
1064 {
1065 FcConfigMessage (parse, FcSevereError, "out of memory");
1066 FcExprDestroy (left);
1067 FcExprDestroy (expr);
1068 break;
1069 }
1070 expr = new;
1071 }
1072 else
1073 expr = left;
1074 }
1075 if (expr)
1076 {
1077 if (!FcVStackPushExpr (parse, tag, expr))
1078 {
1079 FcConfigMessage (parse, FcSevereError, "out of memory");
1080 if (expr)
1081 FcExprDestroy (expr);
1082 }
1083 }
1084 }
1085
1086 static void
1087 FcParseFamily (FcConfigParse *parse)
1088 {
1089 FcChar8 *s;
1090 FcExpr *expr;
1091
1092 if (!parse->pstack)
1093 return;
1094 s = FcStrBufDone (&parse->pstack->str);
1095 if (!s)
1096 {
1097 FcConfigMessage (parse, FcSevereError, "out of memory");
1098 return;
1099 }
1100 expr = FcExprCreateString (s);
1101 FcStrFree (s);
1102 if (expr)
1103 FcVStackPushExpr (parse, FcVStackFamily, expr);
1104 }
1105
1106 static void
1107 FcParseAlias (FcConfigParse *parse)
1108 {
1109 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1110 FcEdit *edit = 0, *next;
1111 FcVStack *vstack;
1112 FcTest *test;
1113
1114 while ((vstack = FcVStackPop (parse)))
1115 {
1116 switch (vstack->tag) {
1117 case FcVStackFamily:
1118 if (family)
1119 {
1120 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1121 if (!new)
1122 FcConfigMessage (parse, FcSevereError, "out of memory");
1123 else
1124 family = new;
1125 }
1126 else
1127 new = vstack->u.expr;
1128 if (new)
1129 {
1130 family = new;
1131 vstack->tag = FcVStackNone;
1132 }
1133 break;
1134 case FcVStackPrefer:
1135 if (prefer)
1136 FcExprDestroy (prefer);
1137 prefer = vstack->u.expr;
1138 vstack->tag = FcVStackNone;
1139 break;
1140 case FcVStackAccept:
1141 if (accept)
1142 FcExprDestroy (accept);
1143 accept = vstack->u.expr;
1144 vstack->tag = FcVStackNone;
1145 break;
1146 case FcVStackDefault:
1147 if (def)
1148 FcExprDestroy (def);
1149 def = vstack->u.expr;
1150 vstack->tag = FcVStackNone;
1151 break;
1152 default:
1153 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1154 break;
1155 }
1156 FcVStackDestroy (vstack);
1157 }
1158 if (!family)
1159 {
1160 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1161 if (prefer)
1162 FcExprDestroy (prefer);
1163 if (accept)
1164 FcExprDestroy (accept);
1165 if (def)
1166 FcExprDestroy (def);
1167 return;
1168 }
1169 if (prefer)
1170 {
1171 edit = FcEditCreate (FcConfigSaveField ("family"),
1172 FcOpPrepend,
1173 prefer);
1174 if (edit)
1175 edit->next = 0;
1176 else
1177 FcExprDestroy (prefer);
1178 }
1179 if (accept)
1180 {
1181 next = edit;
1182 edit = FcEditCreate (FcConfigSaveField ("family"),
1183 FcOpAppend,
1184 accept);
1185 if (edit)
1186 edit->next = next;
1187 else
1188 FcExprDestroy (accept);
1189 }
1190 if (def)
1191 {
1192 next = edit;
1193 edit = FcEditCreate (FcConfigSaveField ("family"),
1194 FcOpAppendLast,
1195 def);
1196 if (edit)
1197 edit->next = next;
1198 else
1199 FcExprDestroy (def);
1200 }
1201 if (edit)
1202 {
1203 test = FcTestCreate (FcQualAny,
1204 (FcChar8 *) FC_FAMILY,
1205 FcOpEqual,
1206 family);
1207 if (test)
1208 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1209 FcTestDestroy (test);
1210 }
1211 else
1212 FcExprDestroy (family);
1213 }
1214
1215 static FcExpr *
1216 FcPopExpr (FcConfigParse *parse)
1217 {
1218 FcVStack *vstack = FcVStackPop (parse);
1219 FcExpr *expr = 0;
1220 if (!vstack)
1221 return 0;
1222 switch (vstack->tag) {
1223 case FcVStackNone:
1224 break;
1225 case FcVStackString:
1226 case FcVStackFamily:
1227 expr = FcExprCreateString (vstack->u.string);
1228 break;
1229 case FcVStackField:
1230 expr = FcExprCreateField ((char *) vstack->u.string);
1231 break;
1232 case FcVStackConstant:
1233 expr = FcExprCreateConst (vstack->u.string);
1234 break;
1235 case FcVStackPrefer:
1236 case FcVStackAccept:
1237 case FcVStackDefault:
1238 expr = vstack->u.expr;
1239 vstack->tag = FcVStackNone;
1240 break;
1241 case FcVStackInteger:
1242 expr = FcExprCreateInteger (vstack->u.integer);
1243 break;
1244 case FcVStackDouble:
1245 expr = FcExprCreateDouble (vstack->u._double);
1246 break;
1247 case FcVStackMatrix:
1248 expr = FcExprCreateMatrix (vstack->u.matrix);
1249 break;
1250 case FcVStackBool:
1251 expr = FcExprCreateBool (vstack->u.bool);
1252 break;
1253 case FcVStackTest:
1254 break;
1255 case FcVStackExpr:
1256 expr = vstack->u.expr;
1257 vstack->tag = FcVStackNone;
1258 break;
1259 case FcVStackEdit:
1260 break;
1261 }
1262 FcVStackDestroy (vstack);
1263 return expr;
1264 }
1265
1266 static FcExpr *
1267 FcPopExprs (FcConfigParse *parse, FcOp op)
1268 {
1269 FcExpr *left, *expr = 0, *new;
1270
1271 while ((left = FcPopExpr (parse)))
1272 {
1273 if (expr)
1274 {
1275 new = FcExprCreateOp (left, op, expr);
1276 if (!new)
1277 {
1278 FcConfigMessage (parse, FcSevereError, "out of memory");
1279 FcExprDestroy (left);
1280 FcExprDestroy (expr);
1281 break;
1282 }
1283 expr = new;
1284 }
1285 else
1286 expr = left;
1287 }
1288 return expr;
1289 }
1290
1291 static void
1292 FcParseExpr (FcConfigParse *parse, FcOp op)
1293 {
1294 FcExpr *expr = FcPopExprs (parse, op);
1295 if (expr)
1296 FcVStackPushExpr (parse, FcVStackExpr, expr);
1297 }
1298
1299 static void
1300 FcParseInclude (FcConfigParse *parse)
1301 {
1302 FcChar8 *s;
1303 const FcChar8 *i;
1304 FcBool ignore_missing = FcFalse;
1305
1306 s = FcStrBufDone (&parse->pstack->str);
1307 if (!s)
1308 {
1309 FcConfigMessage (parse, FcSevereError, "out of memory");
1310 return;
1311 }
1312 i = FcConfigGetAttribute (parse, "ignore_missing");
1313 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1314 ignore_missing = FcTrue;
1315 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1316 parse->error = FcTrue;
1317 free (s);
1318 }
1319
1320 typedef struct _FcOpMap {
1321 char *name;
1322 FcOp op;
1323 } FcOpMap;
1324
1325 static FcOp
1326 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1327 {
1328 int i;
1329
1330 for (i = 0; i < nmap; i++)
1331 if (!strcmp ((char *) op, map[i].name))
1332 return map[i].op;
1333 return FcOpInvalid;
1334 }
1335
1336 static const FcOpMap fcCompareOps[] = {
1337 { "eq", FcOpEqual },
1338 { "not_eq", FcOpNotEqual },
1339 { "less", FcOpLess },
1340 { "less_eq", FcOpLessEqual },
1341 { "more", FcOpMore },
1342 { "more_eq", FcOpMoreEqual }
1343 };
1344
1345 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1346
1347 static FcOp
1348 FcConfigLexCompare (const FcChar8 *compare)
1349 {
1350 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1351 }
1352
1353
1354 static void
1355 FcParseTest (FcConfigParse *parse)
1356 {
1357 const FcChar8 *qual_string;
1358 FcQual qual;
1359 const FcChar8 *name;
1360 const FcChar8 *compare_string;
1361 FcOp compare;
1362 FcExpr *expr;
1363 FcTest *test;
1364
1365 qual_string = FcConfigGetAttribute (parse, "qual");
1366 if (!qual_string)
1367 qual = FcQualAny;
1368 else
1369 {
1370 if (!strcmp ((char *) qual_string, "any"))
1371 qual = FcQualAny;
1372 else if (!strcmp ((char *) qual_string, "all"))
1373 qual = FcQualAll;
1374 else if (!strcmp ((char *) qual_string, "first"))
1375 qual = FcQualFirst;
1376 else if (!strcmp ((char *) qual_string, "not_first"))
1377 qual = FcQualNotFirst;
1378 else
1379 {
1380 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1381 return;
1382 }
1383 }
1384 name = FcConfigGetAttribute (parse, "name");
1385 if (!name)
1386 {
1387 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1388 return;
1389 }
1390 compare_string = FcConfigGetAttribute (parse, "compare");
1391 if (!compare_string)
1392 compare = FcOpEqual;
1393 else
1394 {
1395 compare = FcConfigLexCompare (compare_string);
1396 if (compare == FcOpInvalid)
1397 {
1398 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1399 return;
1400 }
1401 }
1402 expr = FcPopExprs (parse, FcOpComma);
1403 if (!expr)
1404 {
1405 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1406 return;
1407 }
1408 test = FcTestCreate (qual, name, compare, expr);
1409 if (!test)
1410 {
1411 FcConfigMessage (parse, FcSevereError, "out of memory");
1412 return;
1413 }
1414 FcVStackPushTest (parse, test);
1415 }
1416
1417 static const FcOpMap fcModeOps[] = {
1418 { "assign", FcOpAssign },
1419 { "assign_replace", FcOpAssignReplace },
1420 { "prepend", FcOpPrepend },
1421 { "prepend_first", FcOpPrependFirst },
1422 { "append", FcOpAppend },
1423 { "append_last", FcOpAppendLast },
1424 };
1425
1426 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1427
1428 static FcOp
1429 FcConfigLexMode (const FcChar8 *mode)
1430 {
1431 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1432 }
1433
1434 static void
1435 FcParseEdit (FcConfigParse *parse)
1436 {
1437 const FcChar8 *name;
1438 const FcChar8 *mode_string;
1439 FcOp mode;
1440 FcExpr *expr;
1441 FcEdit *edit;
1442
1443 name = FcConfigGetAttribute (parse, "name");
1444 if (!name)
1445 {
1446 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1447 return;
1448 }
1449 mode_string = FcConfigGetAttribute (parse, "mode");
1450 if (!mode_string)
1451 mode = FcOpAssign;
1452 else
1453 {
1454 mode = FcConfigLexMode (mode_string);
1455 if (mode == FcOpInvalid)
1456 {
1457 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1458 return;
1459 }
1460 }
1461 expr = FcPopExprs (parse, FcOpComma);
1462 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr);
1463 if (!edit)
1464 {
1465 FcConfigMessage (parse, FcSevereError, "out of memory");
1466 FcExprDestroy (expr);
1467 return;
1468 }
1469 if (!FcVStackPushEdit (parse, edit))
1470 FcEditDestroy (edit);
1471 }
1472
1473 static void
1474 FcParseMatch (FcConfigParse *parse)
1475 {
1476 const FcChar8 *kind_name;
1477 FcMatchKind kind;
1478 FcTest *test = 0;
1479 FcEdit *edit = 0;
1480 FcVStack *vstack;
1481
1482 kind_name = FcConfigGetAttribute (parse, "target");
1483 if (!kind_name)
1484 kind = FcMatchPattern;
1485 else
1486 {
1487 if (!strcmp ((char *) kind_name, "pattern"))
1488 kind = FcMatchPattern;
1489 else if (!strcmp ((char *) kind_name, "font"))
1490 kind = FcMatchFont;
1491 else
1492 {
1493 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1494 return;
1495 }
1496 }
1497 while ((vstack = FcVStackPop (parse)))
1498 {
1499 switch (vstack->tag) {
1500 case FcVStackTest:
1501 vstack->u.test->next = test;
1502 test = vstack->u.test;
1503 vstack->tag = FcVStackNone;
1504 break;
1505 case FcVStackEdit:
1506 vstack->u.edit->next = edit;
1507 edit = vstack->u.edit;
1508 vstack->tag = FcVStackNone;
1509 break;
1510 default:
1511 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1512 break;
1513 }
1514 FcVStackDestroy (vstack);
1515 }
1516 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1517 FcConfigMessage (parse, FcSevereError, "out of memory");
1518 }
1519
1520 static void
1521 FcEndElement(void *userData, const XML_Char *name)
1522 {
1523 FcConfigParse *parse = userData;
1524 FcChar8 *data;
1525
1526 if (!parse->pstack)
1527 return;
1528 switch (parse->pstack->element) {
1529 case FcElementNone:
1530 break;
1531 case FcElementFontconfig:
1532 break;
1533 case FcElementDir:
1534 data = FcStrBufDone (&parse->pstack->str);
1535 if (!data)
1536 {
1537 FcConfigMessage (parse, FcSevereError, "out of memory");
1538 break;
1539 }
1540 if (!FcConfigAddDir (parse->config, data))
1541 FcConfigMessage (parse, FcSevereError, "out of memory");
1542 free (data);
1543 break;
1544 case FcElementCache:
1545 data = FcStrBufDone (&parse->pstack->str);
1546 if (!data)
1547 {
1548 FcConfigMessage (parse, FcSevereError, "out of memory");
1549 break;
1550 }
1551 if (!FcConfigSetCache (parse->config, data))
1552 FcConfigMessage (parse, FcSevereError, "out of memory");
1553 free (data);
1554 break;
1555 case FcElementInclude:
1556 FcParseInclude (parse);
1557 break;
1558 case FcElementConfig:
1559 break;
1560 case FcElementMatch:
1561 FcParseMatch (parse);
1562 break;
1563 case FcElementAlias:
1564 FcParseAlias (parse);
1565 break;
1566
1567 case FcElementBlank:
1568 FcParseBlank (parse);
1569 break;
1570 case FcElementRescan:
1571 FcParseRescan (parse);
1572 break;
1573
1574 case FcElementPrefer:
1575 FcParseFamilies (parse, FcVStackPrefer);
1576 break;
1577 case FcElementAccept:
1578 FcParseFamilies (parse, FcVStackAccept);
1579 break;
1580 case FcElementDefault:
1581 FcParseFamilies (parse, FcVStackDefault);
1582 break;
1583 case FcElementFamily:
1584 FcParseFamily (parse);
1585 break;
1586
1587 case FcElementTest:
1588 FcParseTest (parse);
1589 break;
1590 case FcElementEdit:
1591 FcParseEdit (parse);
1592 break;
1593
1594 case FcElementInt:
1595 FcParseInt (parse);
1596 break;
1597 case FcElementDouble:
1598 FcParseDouble (parse);
1599 break;
1600 case FcElementString:
1601 FcParseString (parse, FcVStackString);
1602 break;
1603 case FcElementMatrix:
1604 FcParseMatrix (parse);
1605 break;
1606 case FcElementBool:
1607 FcParseBool (parse);
1608 break;
1609 case FcElementCharset:
1610 /* FcParseCharset (parse); */
1611 break;
1612
1613 case FcElementName:
1614 FcParseString (parse, FcVStackField);
1615 break;
1616 case FcElementConst:
1617 FcParseString (parse, FcVStackConstant);
1618 break;
1619 case FcElementOr:
1620 FcParseExpr (parse, FcOpOr);
1621 break;
1622 case FcElementAnd:
1623 FcParseExpr (parse, FcOpAnd);
1624 break;
1625 case FcElementEq:
1626 FcParseExpr (parse, FcOpEqual);
1627 break;
1628 case FcElementNotEq:
1629 FcParseExpr (parse, FcOpNotEqual);
1630 break;
1631 case FcElementLess:
1632 FcParseExpr (parse, FcOpLess);
1633 break;
1634 case FcElementLessEq:
1635 FcParseExpr (parse, FcOpLessEqual);
1636 break;
1637 case FcElementMore:
1638 FcParseExpr (parse, FcOpMore);
1639 break;
1640 case FcElementMoreEq:
1641 FcParseExpr (parse, FcOpMoreEqual);
1642 break;
1643 case FcElementPlus:
1644 FcParseExpr (parse, FcOpPlus);
1645 break;
1646 case FcElementMinus:
1647 FcParseExpr (parse, FcOpMinus);
1648 break;
1649 case FcElementTimes:
1650 FcParseExpr (parse, FcOpTimes);
1651 break;
1652 case FcElementDivide:
1653 FcParseExpr (parse, FcOpDivide);
1654 break;
1655 case FcElementNot:
1656 FcParseExpr (parse, FcOpNot);
1657 break;
1658 case FcElementIf:
1659 FcParseExpr (parse, FcOpQuest);
1660 break;
1661 case FcElementUnknown:
1662 break;
1663 }
1664 (void) FcPStackPop (parse);
1665 }
1666
1667 static void
1668 FcCharacterData (void *userData, const XML_Char *s, int len)
1669 {
1670 FcConfigParse *parse = userData;
1671
1672 if (!parse->pstack)
1673 return;
1674 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1675 FcConfigMessage (parse, FcSevereError, "out of memory");
1676 }
1677
1678 static void
1679 FcStartDoctypeDecl (void *userData,
1680 const XML_Char *doctypeName,
1681 const XML_Char *sysid,
1682 const XML_Char *pubid,
1683 int has_internal_subset)
1684 {
1685 FcConfigParse *parse = userData;
1686
1687 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1688 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1689 }
1690
1691 static void
1692 FcEndDoctypeDecl (void *userData)
1693 {
1694 }
1695
1696 FcBool
1697 FcConfigParseAndLoad (FcConfig *config,
1698 const FcChar8 *name,
1699 FcBool complain)
1700 {
1701
1702 XML_Parser p;
1703 FcChar8 *filename;
1704 FILE *f;
1705 int len;
1706 void *buf;
1707 FcConfigParse parse;
1708 FcBool error = FcTrue;
1709
1710 filename = FcConfigFilename (name);
1711 if (!filename)
1712 goto bail0;
1713
1714 if (!FcStrSetAdd (config->configFiles, filename))
1715 goto bail0;
1716
1717 f = fopen ((char *) filename, "r");
1718 free (filename);
1719 if (!f)
1720 goto bail0;
1721
1722 p = XML_ParserCreate ("UTF-8");
1723 if (!p)
1724 goto bail1;
1725
1726 if (!FcConfigInit (&parse, name, config, p))
1727 goto bail2;
1728
1729 XML_SetUserData (p, &parse);
1730
1731 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1732 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1733 XML_SetCharacterDataHandler (p, FcCharacterData);
1734
1735 do {
1736 buf = XML_GetBuffer (p, BUFSIZ);
1737 if (!buf)
1738 {
1739 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1740 goto bail3;
1741 }
1742 len = fread (buf, 1, BUFSIZ, f);
1743 if (len < 0)
1744 {
1745 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1746 goto bail3;
1747 }
1748 if (!XML_ParseBuffer (p, len, len == 0))
1749 {
1750 FcConfigMessage (&parse, FcSevereError, "%s",
1751 XML_ErrorString (XML_GetErrorCode (p)));
1752 goto bail3;
1753 }
1754 } while (len != 0);
1755 error = parse.error;
1756 bail3:
1757 FcConfigCleanup (&parse);
1758 bail2:
1759 XML_ParserFree (p);
1760 bail1:
1761 fclose (f);
1762 bail0:
1763 if (error && complain)
1764 {
1765 if (name)
1766 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1767 else
1768 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1769 return FcFalse;
1770 }
1771 return FcTrue;
1772 }