]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
fontconfig library: build fixes and compiler warning fixes
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: $
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 static xmlParserInputPtr
29 FcEntityLoader (const char *url, const char *id, xmlParserCtxtPtr ctxt)
30 {
31 xmlParserInputPtr ret;
32 FcChar8 *file;
33
34 file = FcConfigFilename ((FcChar8 *) url);
35 if (!file)
36 return 0;
37 ret = xmlNewInputFromFile (ctxt, (char *) file);
38 free (file);
39 return ret;
40 }
41
42 xmlDocPtr
43 FcConfigLoad (const FcChar8 *file)
44 {
45 xmlDocPtr doc;
46 xmlExternalEntityLoader previous;
47
48 previous = xmlGetExternalEntityLoader ();
49 xmlSetExternalEntityLoader (FcEntityLoader);
50 doc = xmlParseFile ((char *) file);
51 xmlSetExternalEntityLoader (previous);
52 return doc;
53 }
54
55 #if 0
56 int
57 FcConfigSave (char *file, xmlDocPtr doc)
58 {
59 }
60 #endif
61
62 FcTest *
63 FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr)
64 {
65 FcTest *test = (FcTest *) malloc (sizeof (FcTest));;
66
67 if (test)
68 {
69 test->next = 0;
70 test->qual = qual;
71 test->field = (char *) FcStrCopy ((FcChar8 *) field);
72 test->op = compare;
73 test->expr = expr;
74 }
75 return test;
76 }
77
78 void
79 FcTestDestroy (FcTest *test)
80 {
81 if (test->next)
82 FcTestDestroy (test->next);
83 FcExprDestroy (test->expr);
84 FcStrFree ((FcChar8 *) test->field);
85 free (test);
86 }
87
88 FcExpr *
89 FcExprCreateInteger (int i)
90 {
91 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
92
93 if (e)
94 {
95 e->op = FcOpInteger;
96 e->u.ival = i;
97 }
98 return e;
99 }
100
101 FcExpr *
102 FcExprCreateDouble (double d)
103 {
104 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
105
106 if (e)
107 {
108 e->op = FcOpDouble;
109 e->u.dval = d;
110 }
111 return e;
112 }
113
114 FcExpr *
115 FcExprCreateString (const FcChar8 *s)
116 {
117 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119 if (e)
120 {
121 e->op = FcOpString;
122 e->u.sval = FcStrCopy (s);
123 }
124 return e;
125 }
126
127 FcExpr *
128 FcExprCreateMatrix (const FcMatrix *m)
129 {
130 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
131
132 if (e)
133 {
134 e->op = FcOpMatrix;
135 e->u.mval = FcMatrixCopy (m);
136 }
137 return e;
138 }
139
140 FcExpr *
141 FcExprCreateBool (FcBool b)
142 {
143 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
144
145 if (e)
146 {
147 e->op = FcOpBool;
148 e->u.bval = b;
149 }
150 return e;
151 }
152
153 FcExpr *
154 FcExprCreateNil (void)
155 {
156 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
157
158 if (e)
159 {
160 e->op = FcOpNil;
161 }
162 return e;
163 }
164
165 FcExpr *
166 FcExprCreateField (const char *field)
167 {
168 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
169
170 if (e)
171 {
172 e->op = FcOpField;
173 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
174 }
175 return e;
176 }
177
178 FcExpr *
179 FcExprCreateConst (const FcChar8 *constant)
180 {
181 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
182
183 if (e)
184 {
185 e->op = FcOpConst;
186 e->u.constant = FcStrCopy (constant);
187 }
188 return e;
189 }
190
191 FcExpr *
192 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
193 {
194 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
195
196 if (e)
197 {
198 e->op = op;
199 e->u.tree.left = left;
200 e->u.tree.right = right;
201 }
202 return e;
203 }
204
205 void
206 FcExprDestroy (FcExpr *e)
207 {
208 switch (e->op) {
209 case FcOpInteger:
210 break;
211 case FcOpDouble:
212 break;
213 case FcOpString:
214 FcStrFree (e->u.sval);
215 break;
216 case FcOpMatrix:
217 FcMatrixFree (e->u.mval);
218 break;
219 case FcOpCharSet:
220 FcCharSetDestroy (e->u.cval);
221 break;
222 case FcOpBool:
223 break;
224 case FcOpField:
225 FcStrFree ((FcChar8 *) e->u.field);
226 break;
227 case FcOpConst:
228 FcStrFree (e->u.constant);
229 break;
230 case FcOpAssign:
231 case FcOpAssignReplace:
232 case FcOpPrepend:
233 case FcOpPrependFirst:
234 case FcOpAppend:
235 case FcOpAppendLast:
236 break;
237 case FcOpOr:
238 case FcOpAnd:
239 case FcOpEqual:
240 case FcOpContains:
241 case FcOpNotEqual:
242 case FcOpLess:
243 case FcOpLessEqual:
244 case FcOpMore:
245 case FcOpMoreEqual:
246 case FcOpPlus:
247 case FcOpMinus:
248 case FcOpTimes:
249 case FcOpDivide:
250 case FcOpQuest:
251 case FcOpComma:
252 FcExprDestroy (e->u.tree.right);
253 /* fall through */
254 case FcOpNot:
255 FcExprDestroy (e->u.tree.left);
256 break;
257 case FcOpNil:
258 case FcOpInvalid:
259 break;
260 }
261 free (e);
262 }
263
264 FcEdit *
265 FcEditCreate (const char *field, FcOp op, FcExpr *expr)
266 {
267 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
268
269 if (e)
270 {
271 e->next = 0;
272 e->field = field; /* already saved in grammar */
273 e->op = op;
274 e->expr = expr;
275 }
276 return e;
277 }
278
279 void
280 FcEditDestroy (FcEdit *e)
281 {
282 if (e->next)
283 FcEditDestroy (e->next);
284 FcStrFree ((FcChar8 *) e->field);
285 if (e->expr)
286 FcExprDestroy (e->expr);
287 }
288
289 char *
290 FcConfigSaveField (const char *field)
291 {
292 return (char *) FcStrCopy ((FcChar8 *) field);
293 }
294
295 static void
296 FcConfigParseError (char *fmt, ...)
297 {
298 va_list args;
299
300 va_start (args, fmt);
301 fprintf (stderr, "font configuration error: ");
302 vfprintf (stderr, fmt, args);
303 fprintf (stderr, "\n");
304 va_end (args);
305 }
306
307 static xmlChar *
308 FcConfigContent (xmlDocPtr doc,
309 xmlNodePtr node)
310 {
311 xmlChar *content;
312
313 content = xmlNodeListGetString (doc, node->children, 1);
314 if (!content)
315 {
316 FcConfigParseError ("<%s> must have content",
317 node->name);
318 return FcFalse;
319 }
320 return content;
321 }
322
323 static xmlChar *
324 FcConfigAttr (xmlDocPtr doc,
325 xmlAttrPtr attr)
326 {
327 xmlChar *content;
328
329 content = xmlNodeListGetString (doc, attr->children, 1);
330 if (!content)
331 {
332 FcConfigParseError ("attribute %s must have a value",
333 attr->name);
334 return FcFalse;
335 }
336 return content;
337 }
338
339 static struct {
340 char *name;
341 FcOp op;
342 } fcOps[] = {
343 { "int", FcOpInteger },
344 { "double", FcOpDouble },
345 { "string", FcOpString },
346 { "matrix", FcOpMatrix },
347 { "bool", FcOpBool },
348 { "charset", FcOpCharSet },
349 { "name", FcOpField },
350 { "const", FcOpConst },
351 { "field", FcOpField },
352 { "if", FcOpQuest },
353 { "or", FcOpOr },
354 { "and", FcOpAnd },
355 { "eq", FcOpEqual },
356 { "not_eq", FcOpNotEqual },
357 { "less", FcOpLess },
358 { "less_eq", FcOpLessEqual },
359 { "more", FcOpMore },
360 { "more_eq", FcOpMoreEqual },
361 { "plus", FcOpPlus },
362 { "minus", FcOpMinus },
363 { "times", FcOpTimes },
364 { "divide", FcOpDivide },
365 { "not", FcOpNot },
366 { "assign", FcOpAssign },
367 { "assign_replace", FcOpAssignReplace },
368 { "prepend", FcOpPrepend },
369 { "prepend_first", FcOpPrependFirst },
370 { "append", FcOpAppend },
371 { "append_last", FcOpAppendLast },
372 };
373
374 #define NUM_OPS (sizeof fcOps / sizeof fcOps[0])
375
376 static FcOp
377 FcConfigLexOp (const xmlChar *op)
378 {
379 int i;
380
381 for (i = 0; i < NUM_OPS; i++)
382 if (!strcmp (op, fcOps[i].name)) return fcOps[i].op;
383 return FcOpInvalid;
384 }
385
386 static FcBool
387 FcConfigLexBool (const xmlChar *bool)
388 {
389 if (*bool == 't' || *bool == 'T')
390 return FcTrue;
391 if (*bool == 'y' || *bool == 'Y')
392 return FcTrue;
393 if (*bool == '1')
394 return FcTrue;
395 return FcFalse;
396 }
397
398 static FcBool
399 FcConfigParseDir (FcConfig *config,
400 xmlDocPtr doc,
401 xmlNodePtr dir)
402 {
403 xmlChar *content = FcConfigContent (doc, dir);
404
405 if (!content)
406 return FcFalse;
407 return FcConfigAddDir (config, (FcChar8 *) content);
408 }
409
410 static FcBool
411 FcConfigParseCache (FcConfig *config,
412 xmlDocPtr doc,
413 xmlNodePtr dir)
414 {
415 xmlChar *content = FcConfigContent (doc, dir);
416
417 if (!content)
418 return FcFalse;
419 return FcConfigSetCache (config, (FcChar8 *) content);
420 }
421
422 static FcBool
423 FcConfigParseInclude (FcConfig *config,
424 xmlDocPtr doc,
425 xmlNodePtr inc)
426 {
427 xmlChar *content = FcConfigContent (doc, inc);
428 xmlAttr *attr;
429 FcBool complain = FcTrue;
430
431 if (!content)
432 return FcFalse;
433
434 for (attr = inc->properties; attr; attr = attr->next)
435 {
436 if (attr->type != XML_ATTRIBUTE_NODE)
437 continue;
438 if (!strcmp (attr->name, "ignore_missing"))
439 complain = !FcConfigLexBool (FcConfigAttr (doc, attr));
440 }
441 return FcConfigParseAndLoad (config, (FcChar8 *) content, complain);
442 }
443
444 static FcBool
445 FcConfigParseBlank (FcConfig *config,
446 xmlDocPtr doc,
447 xmlNodePtr blank)
448 {
449 xmlNode *node;
450 FcChar32 ucs4;
451
452 for (node = blank->children; node; node = node->next)
453 {
454 if (node->type != XML_ELEMENT_NODE)
455 continue;
456 if (!strcmp (node->name, "int"))
457 {
458 ucs4 = (FcChar32) strtol ((char *) FcConfigContent (doc, node), 0, 0);
459 if (!config->blanks)
460 {
461 config->blanks = FcBlanksCreate ();
462 if (!config->blanks)
463 break;
464 }
465 if (!FcBlanksAdd (config->blanks, ucs4))
466 break;
467 }
468 }
469 if (node)
470 return FcFalse;
471 return FcTrue;
472 }
473
474 static FcBool
475 FcConfigParseConfig (FcConfig *config,
476 xmlDocPtr doc,
477 xmlNodePtr cfg)
478 {
479 xmlNode *node;
480
481 for (node = cfg->children; node; node = node->next)
482 {
483 if (node->type != XML_ELEMENT_NODE)
484 continue;
485 if (!strcmp (node->name, "blank"))
486 {
487 if (!FcConfigParseBlank (config, doc, node))
488 break;
489 }
490 }
491 if (node)
492 return FcFalse;
493 return FcTrue;
494 }
495
496 static FcMatrix *
497 FcConfigParseMatrix (xmlDocPtr doc,
498 xmlNodePtr node)
499 {
500 static FcMatrix m;
501 enum { m_xx, m_xy, m_yx, m_yy, m_done } matrix_state = m_xx;
502 double v;
503 xmlChar *text;
504
505 FcMatrixInit (&m);
506
507 for (; node; node = node->next)
508 {
509 if (node->type != XML_ELEMENT_NODE)
510 continue;
511 if (strcmp (node->name, "double"))
512 continue;
513 text = FcConfigContent (doc, node);
514 if (!text)
515 continue;
516 v = strtod ((char *) text, 0);
517 switch (matrix_state) {
518 case m_xx: m.xx = v; break;
519 case m_xy: m.xy = v; break;
520 case m_yx: m.yx = v; break;
521 case m_yy: m.yy = v; break;
522 default: break;
523 }
524 matrix_state++;
525 }
526
527 return &m;
528 }
529
530 static FcExpr *
531 FcConfigParseExpr (xmlDocPtr doc,
532 xmlNodePtr expr)
533 {
534 FcOp op = FcConfigLexOp (expr->name);
535 xmlNodePtr node;
536 FcExpr *l = 0, *e = 0, *r = 0, *c = 0;
537
538 switch (op) {
539 case FcOpInteger:
540 l = FcExprCreateInteger (strtol ((char *) FcConfigContent (doc, expr), 0, 0));
541 break;
542 case FcOpDouble:
543 l = FcExprCreateDouble (strtod ((char *) FcConfigContent (doc, expr), 0));
544 break;
545 case FcOpString:
546 l = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, expr));
547 break;
548 case FcOpMatrix:
549 l = FcExprCreateMatrix (FcConfigParseMatrix (doc, expr));
550 break;
551 case FcOpBool:
552 l = FcExprCreateBool (FcConfigLexBool(FcConfigContent (doc, expr)));
553 break;
554 case FcOpCharSet:
555 /* not sure what to do here yet */
556 break;
557 case FcOpField:
558 l = FcExprCreateField ((char *) FcConfigContent (doc, expr));
559 break;
560 case FcOpConst:
561 l = FcExprCreateConst ((FcChar8 *) FcConfigContent (doc, expr));
562 break;
563 case FcOpQuest:
564 for (node = expr->children; node; node = node->next)
565 {
566 if (node->type != XML_ELEMENT_NODE)
567 continue;
568 e = FcConfigParseExpr (doc, node);
569 if (!e)
570 break;
571 if (!l)
572 l = e;
573 else if (!c)
574 c = e;
575 else if (!r)
576 r = e;
577 else
578 FcExprDestroy (e);
579 }
580 e = 0;
581 if (!node && l && c && r)
582 {
583 e = FcExprCreateOp (c, FcOpQuest, r);
584 if (e)
585 {
586 r = e;
587 c = 0;
588 e = FcExprCreateOp (l, FcOpQuest, r);
589 }
590 if (!e)
591 node = expr->children;
592 }
593 if (node || !l || !c || !r || !e)
594 {
595 if (l)
596 FcExprDestroy (l);
597 if (c)
598 FcExprDestroy (c);
599 if (r)
600 FcExprDestroy (r);
601 return 0;
602 }
603 break;
604 default:
605 for (node = expr->children; node; node = node->next)
606 {
607 if (node->type != XML_ELEMENT_NODE)
608 continue;
609 e = FcConfigParseExpr (doc, node);
610 if (!e)
611 break;
612 if (!l)
613 l = e;
614 else
615 {
616 r = e;
617 e = FcExprCreateOp (l, op, r);
618 if (!e)
619 {
620 FcExprDestroy (r);
621 break;
622 }
623 l = e;
624 }
625 }
626 if (node || !l)
627 {
628 if (l)
629 FcExprDestroy (l);
630 return 0;
631 }
632 /*
633 * Special case for unary ops
634 */
635 if (!r)
636 {
637 e = FcExprCreateOp (l, op, 0);
638 if (!e)
639 {
640 FcExprDestroy (l);
641 return 0;
642 }
643 }
644 break;
645
646 case FcOpInvalid:
647 return 0;
648 }
649 return l;
650 }
651
652 static FcTest *
653 FcConfigParseTest (xmlDocPtr doc,
654 xmlNodePtr test)
655 {
656 xmlNodePtr node;
657 xmlAttrPtr attr;
658 FcQual qual = FcQualAny;
659 FcOp op = FcOpEqual;
660 xmlChar *field = 0;
661 FcExpr *expr = 0;
662
663 for (attr = test->properties; attr; attr = attr->next)
664 {
665 if (attr->type != XML_ATTRIBUTE_NODE)
666 continue;
667 if (!strcmp (attr->name, "qual"))
668 {
669 xmlChar *qual_name = FcConfigAttr (doc, attr);
670 if (!qual_name)
671 ;
672 else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "any"))
673 qual = FcQualAny;
674 else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "all"))
675 qual = FcQualAll;
676 }
677 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name"))
678 {
679 field = FcConfigAttr (doc, attr);
680 }
681 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "compare"))
682 {
683 xmlChar *compare = FcConfigAttr (doc, attr);
684
685 if (!compare || (op = FcConfigLexOp (compare)) == FcOpInvalid)
686 {
687 FcConfigParseError ("Invalid comparison %s",
688 compare ? (char *) compare : "<missing>");
689 return 0;
690 }
691 }
692 }
693 if (attr)
694 return 0;
695
696 for (node = test->children; node; node = node->next)
697 {
698 if (node->type != XML_ELEMENT_NODE)
699 continue;
700 expr = FcConfigParseExpr (doc, node);
701 if (!expr)
702 return 0;
703 break;
704 }
705
706 if (!expr)
707 {
708 FcConfigParseError ("Missing test expression");
709 return 0;
710 }
711
712 return FcTestCreate (qual, (char *) field, op, expr);
713 }
714
715 static FcExpr *
716 FcConfigParseExprList (xmlDocPtr doc,
717 xmlNodePtr expr)
718 {
719 FcExpr *l, *e, *r;
720
721 if (!expr)
722 return 0;
723
724 e = FcConfigParseExprList (doc, expr->next);
725
726 if (expr->type == XML_ELEMENT_NODE)
727 {
728 r = e;
729 l = FcConfigParseExpr (doc, expr);
730 if (!l)
731 goto bail;
732 if (r)
733 {
734 e = FcExprCreateOp (l, FcOpComma, r);
735 if (!e)
736 goto bail;
737 }
738 else
739 e = l;
740 }
741
742 return e;
743 bail:
744 if (l)
745 FcExprDestroy (l);
746 if (r)
747 FcExprDestroy (r);
748 return 0;
749 }
750
751 static FcEdit *
752 FcConfigParseEdit (xmlDocPtr doc,
753 xmlNodePtr edit)
754 {
755 xmlAttrPtr attr;
756 xmlChar *name = 0;
757 FcOp mode = FcOpAssign;
758 FcExpr *e;
759 FcEdit *ed;
760
761 for (attr = edit->properties; attr; attr = attr->next)
762 {
763 if (attr->type != XML_ATTRIBUTE_NODE)
764 continue;
765 if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name"))
766 name = FcConfigAttr (doc, attr);
767 else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "mode"))
768 mode = FcConfigLexOp (FcConfigAttr (doc, attr));
769 }
770
771 e = FcConfigParseExprList (doc, edit->children);
772
773 ed = FcEditCreate ((char *) name, mode, e);
774 if (!ed)
775 FcExprDestroy (e);
776 return ed;
777 }
778
779 static FcBool
780 FcConfigParseMatch (FcConfig *config,
781 xmlDocPtr doc,
782 xmlNodePtr match)
783 {
784 xmlNodePtr node;
785 xmlAttrPtr attr;
786 FcTest *tests = 0, **prevTest = &tests, *test;
787 FcEdit *edits = 0, **prevEdit = &edits, *edit;
788 FcMatchKind kind = FcMatchPattern;
789 FcBool found_kind = FcFalse;
790
791 for (node = match->children; node; node = node->next)
792 {
793 if (node->type != XML_ELEMENT_NODE)
794 continue;
795 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "test"))
796 {
797 test = FcConfigParseTest (doc, node);
798 if (!test)
799 break;
800 *prevTest = test;
801 prevTest = &test->next;
802 }
803 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "edit"))
804 {
805 edit = FcConfigParseEdit (doc, node);
806 if (!edit)
807 break;
808 *prevEdit = edit;
809 prevEdit = &edit->next;
810 }
811 }
812
813 for (attr = match->properties; attr; attr = attr->next)
814 {
815 if (attr->type != XML_ATTRIBUTE_NODE)
816 continue;
817 if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "target"))
818 {
819 xmlChar *target = FcConfigAttr (doc, attr);
820 if (!target)
821 {
822 FcConfigParseError ("Missing match target");
823 break;
824 }
825 else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "pattern"))
826 {
827 kind = FcMatchPattern;
828 found_kind = FcTrue;
829 }
830 else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "font"))
831 {
832 kind = FcMatchFont;
833 found_kind = FcTrue;
834 }
835 }
836 }
837
838 if (node || attr || !found_kind ||
839 !FcConfigAddEdit (config, tests, edits, kind))
840 {
841 if (tests)
842 FcTestDestroy (tests);
843 if (edits)
844 FcEditDestroy (edits);
845 return FcFalse;
846 }
847
848 return FcTrue;
849 }
850
851 static FcExpr *
852 FcConfigParseFamilies (xmlDocPtr doc,
853 xmlNodePtr family)
854 {
855 FcExpr *next = 0, *this = 0, *expr = 0;
856
857 if (!family)
858 return 0;
859 next = FcConfigParseFamilies (doc, family->next);
860
861 if (family->type == XML_ELEMENT_NODE &&
862 !FcStrCmpIgnoreCase ((FcChar8 *) family->name, (FcChar8 *) "family"))
863 {
864 this = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, family));
865 if (!this)
866 goto bail;
867 if (next)
868 {
869 expr = FcExprCreateOp (this, FcOpComma, next);
870 if (!expr)
871 goto bail;
872 }
873 else
874 expr = this;
875 }
876 else
877 expr = next;
878 return expr;
879
880 bail:
881 if (expr)
882 FcExprDestroy (expr);
883 if (this)
884 FcExprDestroy (this);
885 if (next)
886 FcExprDestroy (next);
887 return 0;
888 }
889
890 static FcBool
891 FcConfigParseAlias (FcConfig *config,
892 xmlDocPtr doc,
893 xmlNodePtr alias)
894 {
895 xmlNodePtr node;
896 FcExpr *prefer = 0, *accept = 0, *def = 0;
897 FcExpr *family = 0;
898 FcEdit *edit = 0, *next;
899 FcTest *test;
900
901 for (node = alias->children; node; node = node->next)
902 {
903 if (node->type != XML_ELEMENT_NODE)
904 continue;
905 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "family"))
906 family = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, node));
907 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "prefer"))
908 prefer = FcConfigParseFamilies (doc, node->children);
909 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "accept"))
910 accept = FcConfigParseFamilies (doc, node->children);
911 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "default"))
912 def = FcConfigParseFamilies (doc, node->children);
913 }
914 if (!family)
915 return FcFalse;
916
917 if (prefer)
918 {
919 edit = FcEditCreate (FcConfigSaveField ("family"),
920 FcOpPrepend,
921 prefer);
922 if (edit)
923 edit->next = 0;
924 }
925 if (accept)
926 {
927 next = edit;
928 edit = FcEditCreate (FcConfigSaveField ("family"),
929 FcOpAppend,
930 accept);
931 if (edit)
932 edit->next = next;
933 }
934 if (def)
935 {
936 next = edit;
937 edit = FcEditCreate (FcConfigSaveField ("family"),
938 FcOpAppendLast,
939 def);
940 if (edit)
941 edit->next = next;
942 }
943 if (edit)
944 {
945 test = FcTestCreate (FcQualAny,
946 FcConfigSaveField ("family"),
947 FcOpEqual,
948 family);
949 if (test)
950 FcConfigAddEdit (config, test, edit, FcMatchPattern);
951 }
952 return FcTrue;
953 }
954
955 FcBool
956 FcConfigParse (FcConfig *config,
957 xmlDocPtr doc)
958 {
959 xmlNodePtr cur;
960 xmlNodePtr node;
961
962 cur = xmlDocGetRootElement (doc);
963
964 for (node = cur->children; node; node = node->next)
965 {
966 if (node->type != XML_ELEMENT_NODE)
967 continue;
968 if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "dir"))
969 {
970 if (!FcConfigParseDir (config, doc, node))
971 break;
972 }
973 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "cache"))
974 {
975 if (!FcConfigParseCache (config, doc, node))
976 break;
977 }
978 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "include"))
979 {
980 if (!FcConfigParseInclude (config, doc, node))
981 break;
982 }
983 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "config"))
984 {
985 if (!FcConfigParseConfig (config, doc, node))
986 break;
987 }
988 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "match"))
989 {
990 if (!FcConfigParseMatch (config, doc, node))
991 break;
992 }
993 else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "alias"))
994 {
995 if (!FcConfigParseAlias (config, doc, node))
996 break;
997 }
998 else
999 {
1000 FcConfigParseError ("invalid element %s", node->name);
1001 break;
1002 }
1003 }
1004 if (node)
1005 return FcFalse;
1006 return FcTrue;
1007 }
1008
1009 FcBool
1010 FcConfigParseAndLoad (FcConfig *config,
1011 const FcChar8 *file,
1012 FcBool complain)
1013 {
1014 xmlDocPtr doc;
1015 FcBool ret;
1016
1017 doc = FcConfigLoad (file);
1018 if (doc)
1019 {
1020 ret = FcConfigAddConfigFile (config, file);
1021 if (ret)
1022 ret = FcConfigParse (config, doc);
1023 xmlFreeDoc (doc);
1024 return ret;
1025 }
1026 if (complain)
1027 {
1028 if (file)
1029 FcConfigParseError ("Cannot load config file \"%s\"", file);
1030 else
1031 FcConfigParseError ("Cannot load default config file");
1032 return FcFalse;
1033 }
1034 return FcTrue;
1035 }