1 /*
2 * fontconfig/src/fcxml.c
3 *
4 * Copyright © 2002 Keith Packard
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 the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make 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 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) 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 <string.h>
26 #include "fcint.h"
27 #include <fcntl.h>
28 #include <stdarg.h>
29
30 #ifdef HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33
34 #ifdef ENABLE_LIBXML2
35
36 #include <libxml/parser.h>
37
38 #define XML_Char xmlChar
39 #define XML_Parser xmlParserCtxtPtr
40 #define XML_ParserFree xmlFreeParserCtxt
41 #define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
42 #define XML_GetErrorCode xmlCtxtGetLastError
43 #define XML_ErrorString(Error) (Error)->message
44
45 #else /* ENABLE_LIBXML2 */
46
47 #ifndef HAVE_XMLPARSE_H
48 #define HAVE_XMLPARSE_H 0
49 #endif
50
51 #if HAVE_XMLPARSE_H
52 #include <xmlparse.h>
53 #else
54 #include <expat.h>
55 #endif
56
57 #endif /* ENABLE_LIBXML2 */
58
59 #ifdef _WIN32
60 #include <mbstring.h>
61 extern FcChar8 fontconfig_instprefix[];
62 #endif
63
64 static FcChar8 *__fc_userdir = NULL;
65 static FcChar8 *__fc_userconf = NULL;
66
67 static void
68 FcExprDestroy (FcExpr *e);
69 static FcBool
70 _FcConfigParse (FcConfig *config,
71 const FcChar8 *name,
72 FcBool complain,
73 FcBool load);
74
75 void
FcTestDestroy(FcTest * test)76 FcTestDestroy (FcTest *test)
77 {
78 FcExprDestroy (test->expr);
79 free (test);
80 }
81
82 void
FcRuleDestroy(FcRule * rule)83 FcRuleDestroy (FcRule *rule)
84 {
85 FcRule *n = rule->next;
86
87 switch (rule->type) {
88 case FcRuleTest:
89 FcTestDestroy (rule->u.test);
90 break;
91 case FcRuleEdit:
92 FcEditDestroy (rule->u.edit);
93 break;
94 case FcRuleUnknown:
95 default:
96 break;
97 }
98 free (rule);
99 if (n)
100 FcRuleDestroy (n);
101 }
102
103 static FcExpr *
FcExprCreateInteger(FcConfig * config,int i)104 FcExprCreateInteger (FcConfig *config, int i)
105 {
106 FcExpr *e = FcConfigAllocExpr (config);
107 if (e)
108 {
109 e->op = FcOpInteger;
110 e->u.ival = i;
111 }
112 return e;
113 }
114
115 static FcExpr *
FcExprCreateDouble(FcConfig * config,double d)116 FcExprCreateDouble (FcConfig *config, double d)
117 {
118 FcExpr *e = FcConfigAllocExpr (config);
119 if (e)
120 {
121 e->op = FcOpDouble;
122 e->u.dval = d;
123 }
124 return e;
125 }
126
127 static FcExpr *
FcExprCreateString(FcConfig * config,const FcChar8 * s)128 FcExprCreateString (FcConfig *config, const FcChar8 *s)
129 {
130 FcExpr *e = FcConfigAllocExpr (config);
131 if (e)
132 {
133 e->op = FcOpString;
134 e->u.sval = FcStrdup (s);
135 }
136 return e;
137 }
138
139 static FcExprMatrix *
FcExprMatrixCopyShallow(const FcExprMatrix * matrix)140 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
141 {
142 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
143 if (m)
144 {
145 *m = *matrix;
146 }
147 return m;
148 }
149
150 static void
FcExprMatrixFreeShallow(FcExprMatrix * m)151 FcExprMatrixFreeShallow (FcExprMatrix *m)
152 {
153 if (!m)
154 return;
155
156 free (m);
157 }
158
159 static void
FcExprMatrixFree(FcExprMatrix * m)160 FcExprMatrixFree (FcExprMatrix *m)
161 {
162 if (!m)
163 return;
164
165 FcExprDestroy (m->xx);
166 FcExprDestroy (m->xy);
167 FcExprDestroy (m->yx);
168 FcExprDestroy (m->yy);
169
170 free (m);
171 }
172
173 static FcExpr *
FcExprCreateMatrix(FcConfig * config,const FcExprMatrix * matrix)174 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
175 {
176 FcExpr *e = FcConfigAllocExpr (config);
177 if (e)
178 {
179 e->op = FcOpMatrix;
180 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
181 }
182 return e;
183 }
184
185 static FcExpr *
FcExprCreateRange(FcConfig * config,FcRange * range)186 FcExprCreateRange (FcConfig *config, FcRange *range)
187 {
188 FcExpr *e = FcConfigAllocExpr (config);
189 if (e)
190 {
191 e->op = FcOpRange;
192 e->u.rval = FcRangeCopy (range);
193 }
194 return e;
195 }
196
197 static FcExpr *
FcExprCreateBool(FcConfig * config,FcBool b)198 FcExprCreateBool (FcConfig *config, FcBool b)
199 {
200 FcExpr *e = FcConfigAllocExpr (config);
201 if (e)
202 {
203 e->op = FcOpBool;
204 e->u.bval = b;
205 }
206 return e;
207 }
208
209 static FcExpr *
FcExprCreateCharSet(FcConfig * config,FcCharSet * charset)210 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
211 {
212 FcExpr *e = FcConfigAllocExpr (config);
213 if (e)
214 {
215 e->op = FcOpCharSet;
216 e->u.cval = FcCharSetCopy (charset);
217 }
218 return e;
219 }
220
221 static FcExpr *
FcExprCreateLangSet(FcConfig * config,FcLangSet * langset)222 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
223 {
224 FcExpr *e = FcConfigAllocExpr (config);
225 if (e)
226 {
227 e->op = FcOpLangSet;
228 e->u.lval = FcLangSetCopy (langset);
229 }
230 return e;
231 }
232
233 static FcExpr *
FcExprCreateName(FcConfig * config,FcExprName name)234 FcExprCreateName (FcConfig *config, FcExprName name)
235 {
236 FcExpr *e = FcConfigAllocExpr (config);
237 if (e)
238 {
239 e->op = FcOpField;
240 e->u.name = name;
241 }
242 return e;
243 }
244
245 static FcExpr *
FcExprCreateConst(FcConfig * config,const FcChar8 * constant)246 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
247 {
248 FcExpr *e = FcConfigAllocExpr (config);
249 if (e)
250 {
251 e->op = FcOpConst;
252 e->u.constant = FcStrdup (constant);
253 }
254 return e;
255 }
256
257 static FcExpr *
FcExprCreateOp(FcConfig * config,FcExpr * left,FcOp op,FcExpr * right)258 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
259 {
260 FcExpr *e = FcConfigAllocExpr (config);
261 if (e)
262 {
263 e->op = op;
264 e->u.tree.left = left;
265 e->u.tree.right = right;
266 }
267 return e;
268 }
269
270 static void
FcExprDestroy(FcExpr * e)271 FcExprDestroy (FcExpr *e)
272 {
273 if (!e)
274 return;
275 switch (FC_OP_GET_OP (e->op)) {
276 case FcOpInteger:
277 break;
278 case FcOpDouble:
279 break;
280 case FcOpString:
281 FcFree (e->u.sval);
282 break;
283 case FcOpMatrix:
284 FcExprMatrixFree (e->u.mexpr);
285 break;
286 case FcOpRange:
287 FcRangeDestroy (e->u.rval);
288 break;
289 case FcOpCharSet:
290 FcCharSetDestroy (e->u.cval);
291 break;
292 case FcOpLangSet:
293 FcLangSetDestroy (e->u.lval);
294 break;
295 case FcOpBool:
296 break;
297 case FcOpField:
298 break;
299 case FcOpConst:
300 FcFree (e->u.constant);
301 break;
302 case FcOpAssign:
303 case FcOpAssignReplace:
304 case FcOpPrepend:
305 case FcOpPrependFirst:
306 case FcOpAppend:
307 case FcOpAppendLast:
308 case FcOpDelete:
309 case FcOpDeleteAll:
310 break;
311 case FcOpOr:
312 case FcOpAnd:
313 case FcOpEqual:
314 case FcOpNotEqual:
315 case FcOpLess:
316 case FcOpLessEqual:
317 case FcOpMore:
318 case FcOpMoreEqual:
319 case FcOpContains:
320 case FcOpListing:
321 case FcOpNotContains:
322 case FcOpPlus:
323 case FcOpMinus:
324 case FcOpTimes:
325 case FcOpDivide:
326 case FcOpQuest:
327 case FcOpComma:
328 FcExprDestroy (e->u.tree.right);
329 /* fall through */
330 case FcOpNot:
331 case FcOpFloor:
332 case FcOpCeil:
333 case FcOpRound:
334 case FcOpTrunc:
335 FcExprDestroy (e->u.tree.left);
336 break;
337 case FcOpNil:
338 case FcOpInvalid:
339 break;
340 }
341
342 e->op = FcOpNil;
343 }
344
345 void
FcEditDestroy(FcEdit * e)346 FcEditDestroy (FcEdit *e)
347 {
348 if (e->expr)
349 FcExprDestroy (e->expr);
350 free (e);
351 }
352
353 typedef enum _FcElement {
354 FcElementNone,
355 FcElementFontconfig,
356 FcElementDir,
357 FcElementCacheDir,
358 FcElementCache,
359 FcElementInclude,
360 FcElementConfig,
361 FcElementMatch,
362 FcElementAlias,
363 FcElementDescription,
364 FcElementRemapDir,
365 FcElementResetDirs,
366
367 FcElementRescan,
368
369 FcElementPrefer,
370 FcElementAccept,
371 FcElementDefault,
372 FcElementFamily,
373
374 FcElementSelectfont,
375 FcElementAcceptfont,
376 FcElementRejectfont,
377 FcElementGlob,
378 FcElementPattern,
379 FcElementPatelt,
380
381 FcElementTest,
382 FcElementEdit,
383 FcElementInt,
384 FcElementDouble,
385 FcElementString,
386 FcElementMatrix,
387 FcElementRange,
388 FcElementBool,
389 FcElementCharSet,
390 FcElementLangSet,
391 FcElementName,
392 FcElementConst,
393 FcElementOr,
394 FcElementAnd,
395 FcElementEq,
396 FcElementNotEq,
397 FcElementLess,
398 FcElementLessEq,
399 FcElementMore,
400 FcElementMoreEq,
401 FcElementContains,
402 FcElementNotContains,
403 FcElementPlus,
404 FcElementMinus,
405 FcElementTimes,
406 FcElementDivide,
407 FcElementNot,
408 FcElementIf,
409 FcElementFloor,
410 FcElementCeil,
411 FcElementRound,
412 FcElementTrunc,
413 FcElementUnknown
414 } FcElement;
415
416 static const struct {
417 const char name[16];
418 FcElement element;
419 } fcElementMap[] = {
420 { "fontconfig", FcElementFontconfig },
421 { "dir", FcElementDir },
422 { "cachedir", FcElementCacheDir },
423 { "cache", FcElementCache },
424 { "include", FcElementInclude },
425 { "config", FcElementConfig },
426 { "match", FcElementMatch },
427 { "alias", FcElementAlias },
428 { "description", FcElementDescription },
429 { "remap-dir", FcElementRemapDir },
430 { "reset-dirs", FcElementResetDirs },
431
432 { "rescan", FcElementRescan },
433
434 { "prefer", FcElementPrefer },
435 { "accept", FcElementAccept },
436 { "default", FcElementDefault },
437 { "family", FcElementFamily },
438
439 { "selectfont", FcElementSelectfont },
440 { "acceptfont", FcElementAcceptfont },
441 { "rejectfont", FcElementRejectfont },
442 { "glob", FcElementGlob },
443 { "pattern", FcElementPattern },
444 { "patelt", FcElementPatelt },
445
446 { "test", FcElementTest },
447 { "edit", FcElementEdit },
448 { "int", FcElementInt },
449 { "double", FcElementDouble },
450 { "string", FcElementString },
451 { "matrix", FcElementMatrix },
452 { "range", FcElementRange },
453 { "bool", FcElementBool },
454 { "charset", FcElementCharSet },
455 { "langset", FcElementLangSet },
456 { "name", FcElementName },
457 { "const", FcElementConst },
458 { "or", FcElementOr },
459 { "and", FcElementAnd },
460 { "eq", FcElementEq },
461 { "not_eq", FcElementNotEq },
462 { "less", FcElementLess },
463 { "less_eq", FcElementLessEq },
464 { "more", FcElementMore },
465 { "more_eq", FcElementMoreEq },
466 { "contains", FcElementContains },
467 { "not_contains", FcElementNotContains },
468 { "plus", FcElementPlus },
469 { "minus", FcElementMinus },
470 { "times", FcElementTimes },
471 { "divide", FcElementDivide },
472 { "not", FcElementNot },
473 { "if", FcElementIf },
474 { "floor", FcElementFloor },
475 { "ceil", FcElementCeil },
476 { "round", FcElementRound },
477 { "trunc", FcElementTrunc },
478 };
479 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
480
481 static const char *fcElementIgnoreName[16] = {
482 "its:",
483 NULL
484 };
485
486 static FcElement
FcElementMap(const XML_Char * name)487 FcElementMap (const XML_Char *name)
488 {
489
490 int i;
491 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
492 if (!strcmp ((char *) name, fcElementMap[i].name))
493 return fcElementMap[i].element;
494 for (i = 0; fcElementIgnoreName[i] != NULL; i++)
495 if (!strncmp ((char *) name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
496 return FcElementNone;
497 return FcElementUnknown;
498 }
499
500 static const char *
FcElementReverseMap(FcElement e)501 FcElementReverseMap (FcElement e)
502 {
503 int i;
504
505 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
506 if (fcElementMap[i].element == e)
507 return fcElementMap[i].name;
508
509 return NULL;
510 }
511
512
513 typedef struct _FcPStack {
514 struct _FcPStack *prev;
515 FcElement element;
516 FcChar8 **attr;
517 FcStrBuf str;
518 FcChar8 *attr_buf_static[16];
519 } FcPStack;
520
521 typedef enum _FcVStackTag {
522 FcVStackNone,
523
524 FcVStackString,
525 FcVStackFamily,
526 FcVStackConstant,
527 FcVStackGlob,
528 FcVStackName,
529 FcVStackPattern,
530
531 FcVStackPrefer,
532 FcVStackAccept,
533 FcVStackDefault,
534
535 FcVStackInteger,
536 FcVStackDouble,
537 FcVStackMatrix,
538 FcVStackRange,
539 FcVStackBool,
540 FcVStackCharSet,
541 FcVStackLangSet,
542
543 FcVStackTest,
544 FcVStackExpr,
545 FcVStackEdit
546 } FcVStackTag;
547
548 typedef struct _FcVStack {
549 struct _FcVStack *prev;
550 FcPStack *pstack; /* related parse element */
551 FcVStackTag tag;
552 union {
553 FcChar8 *string;
554
555 int integer;
556 double _double;
557 FcExprMatrix *matrix;
558 FcRange *range;
559 FcBool bool_;
560 FcCharSet *charset;
561 FcLangSet *langset;
562 FcExprName name;
563
564 FcTest *test;
565 FcQual qual;
566 FcOp op;
567 FcExpr *expr;
568 FcEdit *edit;
569
570 FcPattern *pattern;
571 } u;
572 } FcVStack;
573
574 typedef struct _FcConfigParse {
575 FcPStack *pstack;
576 FcVStack *vstack;
577 FcBool error;
578 const FcChar8 *name;
579 FcConfig *config;
580 FcRuleSet *ruleset;
581 XML_Parser parser;
582 unsigned int pstack_static_used;
583 FcPStack pstack_static[8];
584 unsigned int vstack_static_used;
585 FcVStack vstack_static[64];
586 FcBool scanOnly;
587 } FcConfigParse;
588
589 typedef enum _FcConfigSeverity {
590 FcSevereInfo, FcSevereWarning, FcSevereError
591 } FcConfigSeverity;
592
593 static void
FcConfigMessage(FcConfigParse * parse,FcConfigSeverity severe,const char * fmt,...)594 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
595 {
596 const char *s = "unknown";
597 va_list args;
598
599 va_start (args, fmt);
600
601 switch (severe) {
602 case FcSevereInfo: s = "info"; break;
603 case FcSevereWarning: s = "warning"; break;
604 case FcSevereError: s = "error"; break;
605 }
606 if (parse)
607 {
608 if (parse->name)
609 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
610 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
611 else
612 fprintf (stderr, "Fontconfig %s: line %d: ", s,
613 (int)XML_GetCurrentLineNumber (parse->parser));
614 if (severe >= FcSevereError)
615 parse->error = FcTrue;
616 }
617 else
618 fprintf (stderr, "Fontconfig %s: ", s);
619 vfprintf (stderr, fmt, args);
620 fprintf (stderr, "\n");
621 va_end (args);
622 }
623
624
625 static FcExpr *
626 FcPopExpr (FcConfigParse *parse);
627
628
629 static const char *
FcTypeName(FcType type)630 FcTypeName (FcType type)
631 {
632 switch (type) {
633 case FcTypeVoid:
634 return "void";
635 case FcTypeInteger:
636 case FcTypeDouble:
637 return "number";
638 case FcTypeString:
639 return "string";
640 case FcTypeBool:
641 return "bool";
642 case FcTypeMatrix:
643 return "matrix";
644 case FcTypeCharSet:
645 return "charset";
646 case FcTypeFTFace:
647 return "FT_Face";
648 case FcTypeLangSet:
649 return "langset";
650 case FcTypeRange:
651 return "range";
652 case FcTypeUnknown:
653 default:
654 return "unknown";
655 }
656 }
657
658 static void
FcTypecheckValue(FcConfigParse * parse,FcType value,FcType type)659 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
660 {
661 if (value == FcTypeInteger)
662 value = FcTypeDouble;
663 if (type == FcTypeInteger)
664 type = FcTypeDouble;
665 if (value != type)
666 {
667 if ((value == FcTypeLangSet && type == FcTypeString) ||
668 (value == FcTypeString && type == FcTypeLangSet) ||
669 (value == FcTypeDouble && type == FcTypeRange))
670 return;
671 if (type == FcTypeUnknown)
672 return;
673 /* It's perfectly fine to use user-define elements in expressions,
674 * so don't warn in that case. */
675 if (value == FcTypeUnknown)
676 return;
677 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
678 FcTypeName (value), FcTypeName (type));
679 }
680 }
681
682 static void
FcTypecheckExpr(FcConfigParse * parse,FcExpr * expr,FcType type)683 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
684 {
685 const FcObjectType *o;
686 const FcConstant *c;
687
688 /* If parsing the expression failed, some nodes may be NULL */
689 if (!expr)
690 return;
691
692 switch (FC_OP_GET_OP (expr->op)) {
693 case FcOpInteger:
694 case FcOpDouble:
695 FcTypecheckValue (parse, FcTypeDouble, type);
696 break;
697 case FcOpString:
698 FcTypecheckValue (parse, FcTypeString, type);
699 break;
700 case FcOpMatrix:
701 FcTypecheckValue (parse, FcTypeMatrix, type);
702 break;
703 case FcOpBool:
704 FcTypecheckValue (parse, FcTypeBool, type);
705 break;
706 case FcOpCharSet:
707 FcTypecheckValue (parse, FcTypeCharSet, type);
708 break;
709 case FcOpLangSet:
710 FcTypecheckValue (parse, FcTypeLangSet, type);
711 break;
712 case FcOpRange:
713 FcTypecheckValue (parse, FcTypeRange, type);
714 break;
715 case FcOpNil:
716 break;
717 case FcOpField:
718 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
719 if (o)
720 FcTypecheckValue (parse, o->type, type);
721 break;
722 case FcOpConst:
723 c = FcNameGetConstant (expr->u.constant);
724 if (c)
725 {
726 o = FcNameGetObjectType (c->object);
727 if (o)
728 FcTypecheckValue (parse, o->type, type);
729 }
730 else
731 FcConfigMessage (parse, FcSevereWarning,
732 "invalid constant used : %s",
733 expr->u.constant);
734 break;
735 case FcOpQuest:
736 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
737 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
738 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
739 break;
740 case FcOpAssign:
741 case FcOpAssignReplace:
742 break;
743 case FcOpEqual:
744 case FcOpNotEqual:
745 case FcOpLess:
746 case FcOpLessEqual:
747 case FcOpMore:
748 case FcOpMoreEqual:
749 case FcOpContains:
750 case FcOpNotContains:
751 case FcOpListing:
752 FcTypecheckValue (parse, FcTypeBool, type);
753 break;
754 case FcOpComma:
755 case FcOpOr:
756 case FcOpAnd:
757 case FcOpPlus:
758 case FcOpMinus:
759 case FcOpTimes:
760 case FcOpDivide:
761 FcTypecheckExpr (parse, expr->u.tree.left, type);
762 FcTypecheckExpr (parse, expr->u.tree.right, type);
763 break;
764 case FcOpNot:
765 FcTypecheckValue (parse, FcTypeBool, type);
766 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
767 break;
768 case FcOpFloor:
769 case FcOpCeil:
770 case FcOpRound:
771 case FcOpTrunc:
772 FcTypecheckValue (parse, FcTypeDouble, type);
773 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
774 break;
775 default:
776 break;
777 }
778 }
779
780 static FcTest *
FcTestCreate(FcConfigParse * parse,FcMatchKind kind,FcQual qual,const FcChar8 * field,unsigned int compare,FcExpr * expr)781 FcTestCreate (FcConfigParse *parse,
782 FcMatchKind kind,
783 FcQual qual,
784 const FcChar8 *field,
785 unsigned int compare,
786 FcExpr *expr)
787 {
788 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
789
790 if (test)
791 {
792 const FcObjectType *o;
793
794 test->kind = kind;
795 test->qual = qual;
796 test->object = FcObjectFromName ((const char *) field);
797 test->op = compare;
798 test->expr = expr;
799 o = FcNameGetObjectType (FcObjectName (test->object));
800 if (o)
801 FcTypecheckExpr (parse, expr, o->type);
802 }
803 return test;
804 }
805
806 static FcEdit *
FcEditCreate(FcConfigParse * parse,FcObject object,FcOp op,FcExpr * expr,FcValueBinding binding)807 FcEditCreate (FcConfigParse *parse,
808 FcObject object,
809 FcOp op,
810 FcExpr *expr,
811 FcValueBinding binding)
812 {
813 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
814
815 if (e)
816 {
817 const FcObjectType *o;
818
819 e->object = object;
820 e->op = op;
821 e->expr = expr;
822 e->binding = binding;
823 o = FcNameGetObjectType (FcObjectName (e->object));
824 if (o)
825 FcTypecheckExpr (parse, expr, o->type);
826 }
827 return e;
828 }
829
830 static FcRule *
FcRuleCreate(FcRuleType type,void * p)831 FcRuleCreate (FcRuleType type,
832 void *p)
833 {
834 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
835
836 if (!r)
837 return NULL;
838
839 r->next = NULL;
840 r->type = type;
841 switch (type)
842 {
843 case FcRuleTest:
844 r->u.test = (FcTest *) p;
845 break;
846 case FcRuleEdit:
847 r->u.edit = (FcEdit *) p;
848 break;
849 case FcRuleUnknown:
850 default:
851 free (r);
852 r = NULL;
853 break;
854 }
855
856 return r;
857 }
858
859 static FcVStack *
FcVStackCreateAndPush(FcConfigParse * parse)860 FcVStackCreateAndPush (FcConfigParse *parse)
861 {
862 FcVStack *new;
863
864 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
865 new = &parse->vstack_static[parse->vstack_static_used++];
866 else
867 {
868 new = malloc (sizeof (FcVStack));
869 if (!new)
870 return 0;
871 }
872 new->tag = FcVStackNone;
873 new->prev = 0;
874
875 new->prev = parse->vstack;
876 new->pstack = parse->pstack ? parse->pstack->prev : 0;
877 parse->vstack = new;
878
879 return new;
880 }
881
882 static FcBool
FcVStackPushString(FcConfigParse * parse,FcVStackTag tag,FcChar8 * string)883 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
884 {
885 FcVStack *vstack = FcVStackCreateAndPush (parse);
886 if (!vstack)
887 return FcFalse;
888 vstack->u.string = string;
889 vstack->tag = tag;
890 return FcTrue;
891 }
892
893 static FcBool
FcVStackPushInteger(FcConfigParse * parse,int integer)894 FcVStackPushInteger (FcConfigParse *parse, int integer)
895 {
896 FcVStack *vstack = FcVStackCreateAndPush (parse);
897 if (!vstack)
898 return FcFalse;
899 vstack->u.integer = integer;
900 vstack->tag = FcVStackInteger;
901 return FcTrue;
902 }
903
904 static FcBool
FcVStackPushDouble(FcConfigParse * parse,double _double)905 FcVStackPushDouble (FcConfigParse *parse, double _double)
906 {
907 FcVStack *vstack = FcVStackCreateAndPush (parse);
908 if (!vstack)
909 return FcFalse;
910 vstack->u._double = _double;
911 vstack->tag = FcVStackDouble;
912 return FcTrue;
913 }
914
915 static FcBool
FcVStackPushMatrix(FcConfigParse * parse,FcExprMatrix * matrix)916 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
917 {
918 FcVStack *vstack;
919 vstack = FcVStackCreateAndPush (parse);
920 if (!vstack)
921 return FcFalse;
922 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
923 vstack->tag = FcVStackMatrix;
924 return FcTrue;
925 }
926
927 static FcBool
FcVStackPushRange(FcConfigParse * parse,FcRange * range)928 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
929 {
930 FcVStack *vstack = FcVStackCreateAndPush (parse);
931 if (!vstack)
932 return FcFalse;
933 vstack->u.range = range;
934 vstack->tag = FcVStackRange;
935 return FcTrue;
936 }
937
938 static FcBool
FcVStackPushBool(FcConfigParse * parse,FcBool bool_)939 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
940 {
941 FcVStack *vstack = FcVStackCreateAndPush (parse);
942 if (!vstack)
943 return FcFalse;
944 vstack->u.bool_ = bool_;
945 vstack->tag = FcVStackBool;
946 return FcTrue;
947 }
948
949 static FcBool
FcVStackPushCharSet(FcConfigParse * parse,FcCharSet * charset)950 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
951 {
952 FcVStack *vstack;
953 if (!charset)
954 return FcFalse;
955 vstack = FcVStackCreateAndPush (parse);
956 if (!vstack)
957 return FcFalse;
958 vstack->u.charset = charset;
959 vstack->tag = FcVStackCharSet;
960 return FcTrue;
961 }
962
963 static FcBool
FcVStackPushLangSet(FcConfigParse * parse,FcLangSet * langset)964 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
965 {
966 FcVStack *vstack;
967 if (!langset)
968 return FcFalse;
969 vstack = FcVStackCreateAndPush (parse);
970 if (!vstack)
971 return FcFalse;
972 vstack->u.langset = langset;
973 vstack->tag = FcVStackLangSet;
974 return FcTrue;
975 }
976
977 static FcBool
FcVStackPushName(FcConfigParse * parse,FcMatchKind kind,FcObject object)978 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
979 {
980 FcVStack *vstack = FcVStackCreateAndPush (parse);
981 if (!vstack)
982 return FcFalse;
983 vstack->u.name.object = object;
984 vstack->u.name.kind = kind;
985 vstack->tag = FcVStackName;
986 return FcTrue;
987 }
988
989 static FcBool
FcVStackPushTest(FcConfigParse * parse,FcTest * test)990 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
991 {
992 FcVStack *vstack = FcVStackCreateAndPush (parse);
993 if (!vstack)
994 return FcFalse;
995 vstack->u.test = test;
996 vstack->tag = FcVStackTest;
997 return FcTrue;
998 }
999
1000 static FcBool
FcVStackPushExpr(FcConfigParse * parse,FcVStackTag tag,FcExpr * expr)1001 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
1002 {
1003 FcVStack *vstack = FcVStackCreateAndPush (parse);
1004 if (!vstack)
1005 return FcFalse;
1006 vstack->u.expr = expr;
1007 vstack->tag = tag;
1008 return FcTrue;
1009 }
1010
1011 static FcBool
FcVStackPushEdit(FcConfigParse * parse,FcEdit * edit)1012 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
1013 {
1014 FcVStack *vstack = FcVStackCreateAndPush (parse);
1015 if (!vstack)
1016 return FcFalse;
1017 vstack->u.edit = edit;
1018 vstack->tag = FcVStackEdit;
1019 return FcTrue;
1020 }
1021
1022 static FcBool
FcVStackPushPattern(FcConfigParse * parse,FcPattern * pattern)1023 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
1024 {
1025 FcVStack *vstack = FcVStackCreateAndPush (parse);
1026 if (!vstack)
1027 return FcFalse;
1028 vstack->u.pattern = pattern;
1029 vstack->tag = FcVStackPattern;
1030 return FcTrue;
1031 }
1032
1033 static FcVStack *
FcVStackFetch(FcConfigParse * parse,int off)1034 FcVStackFetch (FcConfigParse *parse, int off)
1035 {
1036 FcVStack *vstack;
1037
1038 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
1039 return vstack;
1040 }
1041
1042 static FcVStack *
FcVStackPeek(FcConfigParse * parse)1043 FcVStackPeek (FcConfigParse *parse)
1044 {
1045 FcVStack *vstack = parse->vstack;
1046
1047 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1048 }
1049
1050 static void
FcVStackPopAndDestroy(FcConfigParse * parse)1051 FcVStackPopAndDestroy (FcConfigParse *parse)
1052 {
1053 FcVStack *vstack = parse->vstack;
1054
1055 if (!vstack || vstack->pstack != parse->pstack)
1056 return;
1057
1058 parse->vstack = vstack->prev;
1059
1060 switch (vstack->tag) {
1061 case FcVStackNone:
1062 break;
1063 case FcVStackName:
1064 break;
1065 case FcVStackFamily:
1066 break;
1067 case FcVStackString:
1068 case FcVStackConstant:
1069 case FcVStackGlob:
1070 FcStrFree (vstack->u.string);
1071 break;
1072 case FcVStackPattern:
1073 FcPatternDestroy (vstack->u.pattern);
1074 break;
1075 case FcVStackInteger:
1076 case FcVStackDouble:
1077 break;
1078 case FcVStackMatrix:
1079 FcExprMatrixFreeShallow (vstack->u.matrix);
1080 break;
1081 case FcVStackBool:
1082 break;
1083 case FcVStackRange:
1084 FcRangeDestroy (vstack->u.range);
1085 break;
1086 case FcVStackCharSet:
1087 FcCharSetDestroy (vstack->u.charset);
1088 break;
1089 case FcVStackLangSet:
1090 FcLangSetDestroy (vstack->u.langset);
1091 break;
1092 case FcVStackTest:
1093 FcTestDestroy (vstack->u.test);
1094 break;
1095 case FcVStackExpr:
1096 case FcVStackPrefer:
1097 case FcVStackAccept:
1098 case FcVStackDefault:
1099 FcExprDestroy (vstack->u.expr);
1100 break;
1101 case FcVStackEdit:
1102 FcEditDestroy (vstack->u.edit);
1103 break;
1104 }
1105
1106 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1107 parse->vstack_static_used--;
1108 else
1109 free (vstack);
1110 }
1111
1112 static void
FcVStackClear(FcConfigParse * parse)1113 FcVStackClear (FcConfigParse *parse)
1114 {
1115 while (FcVStackPeek (parse))
1116 FcVStackPopAndDestroy (parse);
1117 }
1118
1119 static int
FcVStackElements(FcConfigParse * parse)1120 FcVStackElements (FcConfigParse *parse)
1121 {
1122 int h = 0;
1123 FcVStack *vstack = parse->vstack;
1124 while (vstack && vstack->pstack == parse->pstack)
1125 {
1126 h++;
1127 vstack = vstack->prev;
1128 }
1129 return h;
1130 }
1131
1132 static FcChar8 **
FcConfigSaveAttr(const XML_Char ** attr,FcChar8 ** buf,int size_bytes)1133 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1134 {
1135 int slen;
1136 int i;
1137 FcChar8 **new;
1138 FcChar8 *s;
1139
1140 if (!attr)
1141 return 0;
1142 slen = 0;
1143 for (i = 0; attr[i]; i++)
1144 slen += strlen ((char *) attr[i]) + 1;
1145 if (i == 0)
1146 return 0;
1147 slen += (i + 1) * sizeof (FcChar8 *);
1148 if (slen <= size_bytes)
1149 new = buf;
1150 else
1151 {
1152 new = malloc (slen);
1153 if (!new)
1154 {
1155 FcConfigMessage (0, FcSevereError, "out of memory");
1156 return 0;
1157 }
1158 }
1159 s = (FcChar8 *) (new + (i + 1));
1160 for (i = 0; attr[i]; i++)
1161 {
1162 new[i] = s;
1163 strcpy ((char *) s, (char *) attr[i]);
1164 s += strlen ((char *) s) + 1;
1165 }
1166 new[i] = 0;
1167 return new;
1168 }
1169
1170 static FcBool
FcPStackPush(FcConfigParse * parse,FcElement element,const XML_Char ** attr)1171 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1172 {
1173 FcPStack *new;
1174
1175 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1176 new = &parse->pstack_static[parse->pstack_static_used++];
1177 else
1178 {
1179 new = malloc (sizeof (FcPStack));
1180 if (!new)
1181 return FcFalse;
1182 }
1183
1184 new->prev = parse->pstack;
1185 new->element = element;
1186 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1187 FcStrBufInit (&new->str, 0, 0);
1188 parse->pstack = new;
1189 return FcTrue;
1190 }
1191
1192 static FcBool
FcPStackPop(FcConfigParse * parse)1193 FcPStackPop (FcConfigParse *parse)
1194 {
1195 FcPStack *old;
1196
1197 if (!parse->pstack)
1198 {
1199 FcConfigMessage (parse, FcSevereError, "mismatching element");
1200 return FcFalse;
1201 }
1202
1203 /* Don't check the attributes for FcElementNone */
1204 if (parse->pstack->element != FcElementNone &&
1205 parse->pstack->attr)
1206 {
1207 /* Warn about unused attrs. */
1208 FcChar8 **attrs = parse->pstack->attr;
1209 while (*attrs)
1210 {
1211 if (attrs[0][0])
1212 {
1213 FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
1214 }
1215 attrs += 2;
1216 }
1217 }
1218
1219 FcVStackClear (parse);
1220 old = parse->pstack;
1221 parse->pstack = old->prev;
1222 FcStrBufDestroy (&old->str);
1223
1224 if (old->attr && old->attr != old->attr_buf_static)
1225 free (old->attr);
1226
1227 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1228 parse->pstack_static_used--;
1229 else
1230 free (old);
1231 return FcTrue;
1232 }
1233
1234 static FcBool
FcConfigParseInit(FcConfigParse * parse,const FcChar8 * name,FcConfig * config,XML_Parser parser,FcBool enabled)1235 FcConfigParseInit (FcConfigParse *parse,
1236 const FcChar8 *name,
1237 FcConfig *config,
1238 XML_Parser parser,
1239 FcBool enabled)
1240 {
1241 parse->pstack = 0;
1242 parse->pstack_static_used = 0;
1243 parse->vstack = 0;
1244 parse->vstack_static_used = 0;
1245 parse->error = FcFalse;
1246 parse->name = name;
1247 parse->config = config;
1248 parse->ruleset = FcRuleSetCreate (name);
1249 parse->parser = parser;
1250 parse->scanOnly = !enabled;
1251 FcRuleSetEnable (parse->ruleset, enabled);
1252
1253 return FcTrue;
1254 }
1255
1256 static void
FcConfigCleanup(FcConfigParse * parse)1257 FcConfigCleanup (FcConfigParse *parse)
1258 {
1259 while (parse->pstack)
1260 FcPStackPop (parse);
1261 FcRuleSetDestroy (parse->ruleset);
1262 parse->ruleset = NULL;
1263 }
1264
1265 static const FcChar8 *
FcConfigGetAttribute(FcConfigParse * parse,const char * attr)1266 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1267 {
1268 FcChar8 **attrs;
1269 if (!parse->pstack)
1270 return 0;
1271
1272 attrs = parse->pstack->attr;
1273 if (!attrs)
1274 return 0;
1275
1276 while (*attrs)
1277 {
1278 if (!strcmp ((char *) *attrs, attr))
1279 {
1280 attrs[0][0] = '\0'; /* Mark as used. */
1281 return attrs[1];
1282 }
1283 attrs += 2;
1284 }
1285 return 0;
1286 }
1287
1288 static FcStrSet *
_get_real_paths_from_prefix(FcConfigParse * parse,const FcChar8 * path,const FcChar8 * prefix)1289 _get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
1290 {
1291 #ifdef _WIN32
1292 FcChar8 buffer[1000] = { 0 };
1293 #endif
1294 FcChar8 *parent = NULL, *retval = NULL;
1295 FcStrSet *e = NULL;
1296
1297 if (prefix)
1298 {
1299 if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0)
1300 {
1301 parent = FcConfigXdgDataHome ();
1302 if (!parent)
1303 {
1304 /* Home directory might be disabled */
1305 return NULL;
1306 }
1307 e = FcConfigXdgDataDirs ();
1308 if (!e)
1309 {
1310 FcStrFree (parent);
1311 return NULL;
1312 }
1313 }
1314 else if (FcStrCmp (prefix, (const FcChar8 *) "default") == 0 ||
1315 FcStrCmp (prefix, (const FcChar8 *) "cwd") == 0)
1316 {
1317 /* Nothing to do */
1318 }
1319 else if (FcStrCmp (prefix, (const FcChar8 *) "relative") == 0)
1320 {
1321 parent = FcStrDirname (parse->name);
1322 if (!parent)
1323 return NULL;
1324 }
1325 }
1326 #ifndef _WIN32
1327 /* For Win32, check this later for dealing with special cases */
1328 else
1329 {
1330 if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1331 FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1332 }
1333 #else
1334 if (strcmp ((const char *) path, "CUSTOMFONTDIR") == 0)
1335 {
1336 FcChar8 *p;
1337 path = buffer;
1338 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1339 {
1340 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1341 return NULL;
1342 }
1343 /*
1344 * Must use the multi-byte aware function to search
1345 * for backslash because East Asian double-byte code
1346 * pages have characters with backslash as the second
1347 * byte.
1348 */
1349 p = _mbsrchr (path, '\\');
1350 if (p) *p = '\0';
1351 strcat ((char *) path, "\\fonts");
1352 }
1353 else if (strcmp ((const char *) path, "APPSHAREFONTDIR") == 0)
1354 {
1355 FcChar8 *p;
1356 path = buffer;
1357 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1358 {
1359 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1360 return NULL;
1361 }
1362 p = _mbsrchr (path, '\\');
1363 if (p) *p = '\0';
1364 strcat ((char *) path, "\\..\\share\\fonts");
1365 }
1366 else if (strcmp ((const char *) path, "WINDOWSFONTDIR") == 0)
1367 {
1368 int rc;
1369 path = buffer;
1370 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1371 if (rc == 0 || rc > sizeof (buffer) - 20)
1372 {
1373 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1374 return NULL;
1375 }
1376 if (path [strlen ((const char *) path) - 1] != '\\')
1377 strcat ((char *) path, "\\");
1378 strcat ((char *) path, "fonts");
1379 }
1380 else
1381 {
1382 if (!prefix)
1383 {
1384 if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1385 FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1386 }
1387 }
1388 #endif
1389 if (parent)
1390 {
1391 retval = FcStrBuildFilename (parent, path, NULL);
1392 FcStrFree (parent);
1393 }
1394 else
1395 {
1396 retval = FcStrdup (path);
1397 }
1398 if (!e)
1399 e = FcStrSetCreate ();
1400 else
1401 {
1402 FcChar8 *s;
1403 int i;
1404
1405 for (i = 0; i < e->num; i++)
1406 {
1407 s = FcStrBuildFilename (e->strs[i], path, NULL);
1408 FcStrFree (e->strs[i]);
1409 e->strs[i] = s;
1410 }
1411 }
1412 if (!FcStrSetInsert (e, retval, 0))
1413 {
1414 FcStrSetDestroy (e);
1415 e = NULL;
1416 }
1417 FcStrFree (retval);
1418
1419 return e;
1420 }
1421
1422 static void
FcStartElement(void * userData,const XML_Char * name,const XML_Char ** attr)1423 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1424 {
1425 FcConfigParse *parse = userData;
1426 FcElement element;
1427
1428 element = FcElementMap (name);
1429 if (element == FcElementUnknown)
1430 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1431
1432 if (!FcPStackPush (parse, element, attr))
1433 {
1434 FcConfigMessage (parse, FcSevereError, "out of memory");
1435 return;
1436 }
1437 return;
1438 }
1439
1440 static void
FcParseRescan(FcConfigParse * parse)1441 FcParseRescan (FcConfigParse *parse)
1442 {
1443 int n = FcVStackElements (parse);
1444 while (n-- > 0)
1445 {
1446 FcVStack *v = FcVStackFetch (parse, n);
1447 if (v->tag != FcVStackInteger)
1448 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1449 else
1450 parse->config->rescanInterval = v->u.integer;
1451 }
1452 }
1453
1454 static void
FcParseInt(FcConfigParse * parse)1455 FcParseInt (FcConfigParse *parse)
1456 {
1457 FcChar8 *s, *end;
1458 int l;
1459
1460 if (!parse->pstack)
1461 return;
1462 s = FcStrBufDoneStatic (&parse->pstack->str);
1463 if (!s)
1464 {
1465 FcConfigMessage (parse, FcSevereError, "out of memory");
1466 return;
1467 }
1468 end = 0;
1469 l = (int) strtol ((char *) s, (char **)&end, 0);
1470 if (end != s + strlen ((char *) s))
1471 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1472 else
1473 FcVStackPushInteger (parse, l);
1474 FcStrBufDestroy (&parse->pstack->str);
1475 }
1476
1477 /*
1478 * idea copied from glib g_ascii_strtod with
1479 * permission of the author (Alexander Larsson)
1480 */
1481
1482 #include <locale.h>
1483
1484 static double
FcStrtod(char * s,char ** end)1485 FcStrtod (char *s, char **end)
1486 {
1487 #ifndef __BIONIC__
1488 struct lconv *locale_data;
1489 #endif
1490 const char *decimal_point;
1491 int dlen;
1492 char *dot;
1493 double v;
1494
1495 /*
1496 * Have to swap the decimal point to match the current locale
1497 * if that locale doesn't use 0x2e
1498 */
1499 #ifndef __BIONIC__
1500 locale_data = localeconv ();
1501 decimal_point = locale_data->decimal_point;
1502 dlen = strlen (decimal_point);
1503 #else
1504 decimal_point = ".";
1505 dlen = 1;
1506 #endif
1507
1508 if ((dot = strchr (s, 0x2e)) &&
1509 (decimal_point[0] != 0x2e ||
1510 decimal_point[1] != 0))
1511 {
1512 char buf[128];
1513 int slen = strlen (s);
1514
1515 if (slen + dlen > (int) sizeof (buf))
1516 {
1517 if (end)
1518 *end = s;
1519 v = 0;
1520 }
1521 else
1522 {
1523 char *buf_end;
1524 /* mantissa */
1525 strncpy (buf, s, dot - s);
1526 /* decimal point */
1527 strcpy (buf + (dot - s), decimal_point);
1528 /* rest of number */
1529 strcpy (buf + (dot - s) + dlen, dot + 1);
1530 buf_end = 0;
1531 v = strtod (buf, &buf_end);
1532 if (buf_end) {
1533 buf_end = s + (buf_end - buf);
1534 if (buf_end > dot)
1535 buf_end -= dlen - 1;
1536 }
1537 if (end)
1538 *end = buf_end;
1539 }
1540 }
1541 else
1542 v = strtod (s, end);
1543 return v;
1544 }
1545
1546 static void
FcParseDouble(FcConfigParse * parse)1547 FcParseDouble (FcConfigParse *parse)
1548 {
1549 FcChar8 *s, *end;
1550 double d;
1551
1552 if (!parse->pstack)
1553 return;
1554 s = FcStrBufDoneStatic (&parse->pstack->str);
1555 if (!s)
1556 {
1557 FcConfigMessage (parse, FcSevereError, "out of memory");
1558 return;
1559 }
1560 end = 0;
1561 d = FcStrtod ((char *) s, (char **)&end);
1562 if (end != s + strlen ((char *) s))
1563 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1564 else
1565 FcVStackPushDouble (parse, d);
1566 FcStrBufDestroy (&parse->pstack->str);
1567 }
1568
1569 static void
FcParseString(FcConfigParse * parse,FcVStackTag tag)1570 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1571 {
1572 FcChar8 *s;
1573
1574 if (!parse->pstack)
1575 return;
1576 s = FcStrBufDone (&parse->pstack->str);
1577 if (!s)
1578 {
1579 FcConfigMessage (parse, FcSevereError, "out of memory");
1580 return;
1581 }
1582 if (!FcVStackPushString (parse, tag, s))
1583 FcStrFree (s);
1584 }
1585
1586 static void
FcParseName(FcConfigParse * parse)1587 FcParseName (FcConfigParse *parse)
1588 {
1589 const FcChar8 *kind_string;
1590 FcMatchKind kind;
1591 FcChar8 *s;
1592 FcObject object;
1593
1594 kind_string = FcConfigGetAttribute (parse, "target");
1595 if (!kind_string)
1596 kind = FcMatchDefault;
1597 else
1598 {
1599 if (!strcmp ((char *) kind_string, "pattern"))
1600 kind = FcMatchPattern;
1601 else if (!strcmp ((char *) kind_string, "font"))
1602 kind = FcMatchFont;
1603 else if (!strcmp ((char *) kind_string, "default"))
1604 kind = FcMatchDefault;
1605 else
1606 {
1607 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1608 return;
1609 }
1610 }
1611
1612 if (!parse->pstack)
1613 return;
1614 s = FcStrBufDone (&parse->pstack->str);
1615 if (!s)
1616 {
1617 FcConfigMessage (parse, FcSevereError, "out of memory");
1618 return;
1619 }
1620 object = FcObjectFromName ((const char *) s);
1621
1622 FcVStackPushName (parse, kind, object);
1623
1624 FcStrFree (s);
1625 }
1626
1627 static void
FcParseMatrix(FcConfigParse * parse)1628 FcParseMatrix (FcConfigParse *parse)
1629 {
1630 FcExprMatrix m;
1631
1632 m.yy = FcPopExpr (parse);
1633 m.yx = FcPopExpr (parse);
1634 m.xy = FcPopExpr (parse);
1635 m.xx = FcPopExpr (parse);
1636
1637 if (!m.yy || !m.yx || !m.xy || !m.xx)
1638 {
1639 FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1640 return;
1641 }
1642 if (FcPopExpr (parse))
1643 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1644 else
1645 FcVStackPushMatrix (parse, &m);
1646 }
1647
1648 static void
FcParseRange(FcConfigParse * parse)1649 FcParseRange (FcConfigParse *parse)
1650 {
1651 FcVStack *vstack;
1652 FcRange *r;
1653 FcChar32 n[2] = {0, 0};
1654 int count = 1;
1655 double d[2] = {0.0L, 0.0L};
1656 FcBool dflag = FcFalse;
1657
1658 while ((vstack = FcVStackPeek (parse)))
1659 {
1660 if (count < 0)
1661 {
1662 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1663 return;
1664 }
1665 switch ((int) vstack->tag) {
1666 case FcVStackInteger:
1667 if (dflag)
1668 d[count] = (double)vstack->u.integer;
1669 else
1670 n[count] = vstack->u.integer;
1671 break;
1672 case FcVStackDouble:
1673 if (count == 0 && !dflag)
1674 d[1] = (double)n[1];
1675 d[count] = vstack->u._double;
1676 dflag = FcTrue;
1677 break;
1678 default:
1679 FcConfigMessage (parse, FcSevereError, "invalid element in range");
1680 if (dflag)
1681 d[count] = 0.0L;
1682 else
1683 n[count] = 0;
1684 break;
1685 }
1686 count--;
1687 FcVStackPopAndDestroy (parse);
1688 }
1689 if (count >= 0)
1690 {
1691 FcConfigMessage (parse, FcSevereError, "invalid range");
1692 return;
1693 }
1694 if (dflag)
1695 {
1696 if (d[0] > d[1])
1697 {
1698 FcConfigMessage (parse, FcSevereError, "invalid range");
1699 return;
1700 }
1701 r = FcRangeCreateDouble (d[0], d[1]);
1702 }
1703 else
1704 {
1705 if (n[0] > n[1])
1706 {
1707 FcConfigMessage (parse, FcSevereError, "invalid range");
1708 return;
1709 }
1710 r = FcRangeCreateInteger (n[0], n[1]);
1711 }
1712 FcVStackPushRange (parse, r);
1713 }
1714
1715 static FcBool
FcConfigLexBool(FcConfigParse * parse,const FcChar8 * bool_)1716 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1717 {
1718 FcBool result = FcFalse;
1719
1720 if (!FcNameBool (bool_, &result))
1721 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1722 bool_);
1723 return result;
1724 }
1725
1726 static void
FcParseBool(FcConfigParse * parse)1727 FcParseBool (FcConfigParse *parse)
1728 {
1729 FcChar8 *s;
1730
1731 if (!parse->pstack)
1732 return;
1733 s = FcStrBufDoneStatic (&parse->pstack->str);
1734 if (!s)
1735 {
1736 FcConfigMessage (parse, FcSevereError, "out of memory");
1737 return;
1738 }
1739 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1740 FcStrBufDestroy (&parse->pstack->str);
1741 }
1742
1743 static void
FcParseCharSet(FcConfigParse * parse)1744 FcParseCharSet (FcConfigParse *parse)
1745 {
1746 FcVStack *vstack;
1747 FcCharSet *charset = FcCharSetCreate ();
1748 FcChar32 i, begin, end;
1749 int n = 0;
1750
1751 while ((vstack = FcVStackPeek (parse)))
1752 {
1753 switch ((int) vstack->tag) {
1754 case FcVStackInteger:
1755 if (!FcCharSetAddChar (charset, vstack->u.integer))
1756 {
1757 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1758 }
1759 else
1760 n++;
1761 break;
1762 case FcVStackRange:
1763 begin = (FcChar32) vstack->u.range->begin;
1764 end = (FcChar32) vstack->u.range->end;
1765
1766 if (begin <= end)
1767 {
1768 for (i = begin; i <= end; i++)
1769 {
1770 if (!FcCharSetAddChar (charset, i))
1771 {
1772 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1773 }
1774 else
1775 n++;
1776 }
1777 }
1778 break;
1779 default:
1780 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1781 break;
1782 }
1783 FcVStackPopAndDestroy (parse);
1784 }
1785 if (n > 0)
1786 FcVStackPushCharSet (parse, charset);
1787 else
1788 FcCharSetDestroy (charset);
1789 }
1790
1791 static void
FcParseLangSet(FcConfigParse * parse)1792 FcParseLangSet (FcConfigParse *parse)
1793 {
1794 FcVStack *vstack;
1795 FcLangSet *langset = FcLangSetCreate ();
1796 int n = 0;
1797
1798 while ((vstack = FcVStackPeek (parse)))
1799 {
1800 switch ((int) vstack->tag) {
1801 case FcVStackString:
1802 if (!FcLangSetAdd (langset, vstack->u.string))
1803 {
1804 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1805 }
1806 else
1807 n++;
1808 break;
1809 default:
1810 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1811 break;
1812 }
1813 FcVStackPopAndDestroy (parse);
1814 }
1815 if (n > 0)
1816 FcVStackPushLangSet (parse, langset);
1817 else
1818 FcLangSetDestroy (langset);
1819 }
1820
1821 static FcBool
FcConfigLexBinding(FcConfigParse * parse,const FcChar8 * binding_string,FcValueBinding * binding_ret)1822 FcConfigLexBinding (FcConfigParse *parse,
1823 const FcChar8 *binding_string,
1824 FcValueBinding *binding_ret)
1825 {
1826 FcValueBinding binding;
1827
1828 if (!binding_string)
1829 binding = FcValueBindingWeak;
1830 else
1831 {
1832 if (!strcmp ((char *) binding_string, "weak"))
1833 binding = FcValueBindingWeak;
1834 else if (!strcmp ((char *) binding_string, "strong"))
1835 binding = FcValueBindingStrong;
1836 else if (!strcmp ((char *) binding_string, "same"))
1837 binding = FcValueBindingSame;
1838 else
1839 {
1840 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1841 return FcFalse;
1842 }
1843 }
1844 *binding_ret = binding;
1845 return FcTrue;
1846 }
1847
1848 static void
FcParseFamilies(FcConfigParse * parse,FcVStackTag tag)1849 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1850 {
1851 FcVStack *vstack;
1852 FcExpr *left, *expr = 0, *new;
1853
1854 while ((vstack = FcVStackPeek (parse)))
1855 {
1856 if (vstack->tag != FcVStackFamily)
1857 {
1858 FcConfigMessage (parse, FcSevereWarning, "non-family");
1859 FcVStackPopAndDestroy (parse);
1860 continue;
1861 }
1862 left = vstack->u.expr;
1863 vstack->tag = FcVStackNone;
1864 FcVStackPopAndDestroy (parse);
1865 if (expr)
1866 {
1867 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1868 if (!new)
1869 {
1870 FcConfigMessage (parse, FcSevereError, "out of memory");
1871 FcExprDestroy (left);
1872 FcExprDestroy (expr);
1873 break;
1874 }
1875 expr = new;
1876 }
1877 else
1878 expr = left;
1879 }
1880 if (expr)
1881 {
1882 if (!FcVStackPushExpr (parse, tag, expr))
1883 {
1884 FcConfigMessage (parse, FcSevereError, "out of memory");
1885 FcExprDestroy (expr);
1886 }
1887 }
1888 }
1889
1890 static void
FcParseFamily(FcConfigParse * parse)1891 FcParseFamily (FcConfigParse *parse)
1892 {
1893 FcChar8 *s;
1894 FcExpr *expr;
1895
1896 if (!parse->pstack)
1897 return;
1898 s = FcStrBufDoneStatic (&parse->pstack->str);
1899 if (!s)
1900 {
1901 FcConfigMessage (parse, FcSevereError, "out of memory");
1902 return;
1903 }
1904 expr = FcExprCreateString (parse->config, s);
1905 FcStrBufDestroy (&parse->pstack->str);
1906 if (expr)
1907 FcVStackPushExpr (parse, FcVStackFamily, expr);
1908 }
1909
1910 static void
FcParseAlias(FcConfigParse * parse)1911 FcParseAlias (FcConfigParse *parse)
1912 {
1913 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1914 FcEdit *edit = 0;
1915 FcVStack *vstack;
1916 FcRule *rule = NULL, *r;
1917 FcValueBinding binding;
1918 int n;
1919
1920 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1921 return;
1922 while ((vstack = FcVStackPeek (parse)))
1923 {
1924 switch ((int) vstack->tag) {
1925 case FcVStackFamily:
1926 if (family)
1927 {
1928 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1929 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1930 if (!new)
1931 FcConfigMessage (parse, FcSevereError, "out of memory");
1932 else
1933 family = new;
1934 }
1935 else
1936 new = vstack->u.expr;
1937 if (new)
1938 {
1939 family = new;
1940 vstack->tag = FcVStackNone;
1941 }
1942 break;
1943 case FcVStackPrefer:
1944 if (prefer)
1945 FcExprDestroy (prefer);
1946 prefer = vstack->u.expr;
1947 vstack->tag = FcVStackNone;
1948 break;
1949 case FcVStackAccept:
1950 if (accept)
1951 FcExprDestroy (accept);
1952 accept = vstack->u.expr;
1953 vstack->tag = FcVStackNone;
1954 break;
1955 case FcVStackDefault:
1956 if (def)
1957 FcExprDestroy (def);
1958 def = vstack->u.expr;
1959 vstack->tag = FcVStackNone;
1960 break;
1961 case FcVStackTest:
1962 if (rule)
1963 {
1964 r = FcRuleCreate (FcRuleTest, vstack->u.test);
1965 r->next = rule;
1966 rule = r;
1967 }
1968 else
1969 rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1970 vstack->tag = FcVStackNone;
1971 break;
1972 default:
1973 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1974 break;
1975 }
1976 FcVStackPopAndDestroy (parse);
1977 }
1978 if (!family)
1979 {
1980 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1981 if (prefer)
1982 FcExprDestroy (prefer);
1983 if (accept)
1984 FcExprDestroy (accept);
1985 if (def)
1986 FcExprDestroy (def);
1987 if (rule)
1988 FcRuleDestroy (rule);
1989 return;
1990 }
1991 if (!prefer &&
1992 !accept &&
1993 !def)
1994 {
1995 FcExprDestroy (family);
1996 if (rule)
1997 FcRuleDestroy (rule);
1998 return;
1999 }
2000 else
2001 {
2002 FcTest *t = FcTestCreate (parse, FcMatchPattern,
2003 FcQualAny,
2004 (FcChar8 *) FC_FAMILY,
2005 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
2006 family);
2007 if (rule)
2008 {
2009 for (r = rule; r->next; r = r->next);
2010 r->next = FcRuleCreate (FcRuleTest, t);
2011 r = r->next;
2012 }
2013 else
2014 {
2015 r = rule = FcRuleCreate (FcRuleTest, t);
2016 }
2017 }
2018 if (prefer)
2019 {
2020 edit = FcEditCreate (parse,
2021 FC_FAMILY_OBJECT,
2022 FcOpPrepend,
2023 prefer,
2024 binding);
2025 if (!edit)
2026 FcExprDestroy (prefer);
2027 else
2028 {
2029 r->next = FcRuleCreate (FcRuleEdit, edit);
2030 r = r->next;
2031 }
2032 }
2033 if (accept)
2034 {
2035 edit = FcEditCreate (parse,
2036 FC_FAMILY_OBJECT,
2037 FcOpAppend,
2038 accept,
2039 binding);
2040 if (!edit)
2041 FcExprDestroy (accept);
2042 else
2043 {
2044 r->next = FcRuleCreate (FcRuleEdit, edit);
2045 r = r->next;
2046 }
2047 }
2048 if (def)
2049 {
2050 edit = FcEditCreate (parse,
2051 FC_FAMILY_OBJECT,
2052 FcOpAppendLast,
2053 def,
2054 binding);
2055 if (!edit)
2056 FcExprDestroy (def);
2057 else
2058 {
2059 r->next = FcRuleCreate (FcRuleEdit, edit);
2060 r = r->next;
2061 }
2062 }
2063 if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
2064 FcRuleDestroy (rule);
2065 else
2066 if (parse->config->maxObjects < n)
2067 parse->config->maxObjects = n;
2068 }
2069
2070 static void
FcParseDescription(FcConfigParse * parse)2071 FcParseDescription (FcConfigParse *parse)
2072 {
2073 const FcChar8 *domain;
2074 FcChar8 *desc;
2075
2076 domain = FcConfigGetAttribute (parse, "domain");
2077 desc = FcStrBufDone (&parse->pstack->str);
2078 if (!desc)
2079 {
2080 FcConfigMessage (parse, FcSevereError, "out of memory");
2081 return;
2082 }
2083 FcRuleSetAddDescription (parse->ruleset, domain, desc);
2084
2085 FcStrFree (desc);
2086 }
2087
2088 static void
FcParseRemapDir(FcConfigParse * parse)2089 FcParseRemapDir (FcConfigParse *parse)
2090 {
2091 const FcChar8 *path, *attr, *data, *salt;
2092 FcStrSet *prefix_dirs = NULL;
2093
2094 data = FcStrBufDoneStatic (&parse->pstack->str);
2095 if (!data)
2096 {
2097 FcConfigMessage (parse, FcSevereError, "out of memory");
2098 return;
2099 }
2100 if (data[0] == 0)
2101 {
2102 FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
2103 return;
2104 }
2105 path = FcConfigGetAttribute (parse, "as-path");
2106 if (!path)
2107 {
2108 FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2109 return;
2110 }
2111 attr = FcConfigGetAttribute (parse, "prefix");
2112 salt = FcConfigGetAttribute (parse, "salt");
2113 prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2114 if (prefix_dirs)
2115 {
2116 FcStrList *l = FcStrListCreate (prefix_dirs);
2117 FcChar8 *prefix;
2118
2119 FcStrSetDestroy (prefix_dirs);
2120 while ((prefix = FcStrListNext (l)))
2121 {
2122 if (!prefix || prefix[0] == 0)
2123 {
2124 /* nop */
2125 }
2126 else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2127 {
2128 if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2129 FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2130 }
2131 FcStrBufDestroy (&parse->pstack->str);
2132 }
2133 FcStrListDone (l);
2134 }
2135 }
2136
2137 static void
FcParseResetDirs(FcConfigParse * parse)2138 FcParseResetDirs (FcConfigParse *parse)
2139 {
2140 if (!parse->scanOnly)
2141 {
2142 if (!FcConfigResetFontDirs (parse->config))
2143 FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2144 }
2145 }
2146
2147 static FcExpr *
FcPopExpr(FcConfigParse * parse)2148 FcPopExpr (FcConfigParse *parse)
2149 {
2150 FcVStack *vstack = FcVStackPeek (parse);
2151 FcExpr *expr = 0;
2152 if (!vstack)
2153 return 0;
2154 switch ((int) vstack->tag) {
2155 case FcVStackNone:
2156 break;
2157 case FcVStackString:
2158 case FcVStackFamily:
2159 expr = FcExprCreateString (parse->config, vstack->u.string);
2160 break;
2161 case FcVStackName:
2162 expr = FcExprCreateName (parse->config, vstack->u.name);
2163 break;
2164 case FcVStackConstant:
2165 expr = FcExprCreateConst (parse->config, vstack->u.string);
2166 break;
2167 case FcVStackGlob:
2168 /* XXX: What's the correct action here? (CDW) */
2169 break;
2170 case FcVStackPrefer:
2171 case FcVStackAccept:
2172 case FcVStackDefault:
2173 expr = vstack->u.expr;
2174 vstack->tag = FcVStackNone;
2175 break;
2176 case FcVStackInteger:
2177 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
2178 break;
2179 case FcVStackDouble:
2180 expr = FcExprCreateDouble (parse->config, vstack->u._double);
2181 break;
2182 case FcVStackMatrix:
2183 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
2184 break;
2185 case FcVStackRange:
2186 expr = FcExprCreateRange (parse->config, vstack->u.range);
2187 break;
2188 case FcVStackBool:
2189 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
2190 break;
2191 case FcVStackCharSet:
2192 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2193 break;
2194 case FcVStackLangSet:
2195 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2196 break;
2197 case FcVStackTest:
2198 break;
2199 case FcVStackExpr:
2200 expr = vstack->u.expr;
2201 vstack->tag = FcVStackNone;
2202 break;
2203 case FcVStackEdit:
2204 break;
2205 default:
2206 break;
2207 }
2208 FcVStackPopAndDestroy (parse);
2209 return expr;
2210 }
2211
2212 /*
2213 * This builds a tree of binary operations. Note
2214 * that every operator is defined so that if only
2215 * a single operand is contained, the value of the
2216 * whole expression is the value of the operand.
2217 *
2218 * This code reduces in that case to returning that
2219 * operand.
2220 */
2221 static FcExpr *
FcPopBinary(FcConfigParse * parse,FcOp op)2222 FcPopBinary (FcConfigParse *parse, FcOp op)
2223 {
2224 FcExpr *left, *expr = 0, *new;
2225
2226 while ((left = FcPopExpr (parse)))
2227 {
2228 if (expr)
2229 {
2230 new = FcExprCreateOp (parse->config, left, op, expr);
2231 if (!new)
2232 {
2233 FcConfigMessage (parse, FcSevereError, "out of memory");
2234 FcExprDestroy (left);
2235 FcExprDestroy (expr);
2236 return 0;
2237 }
2238 expr = new;
2239 }
2240 else
2241 expr = left;
2242 }
2243 return expr;
2244 }
2245
2246 static void
FcParseBinary(FcConfigParse * parse,FcOp op)2247 FcParseBinary (FcConfigParse *parse, FcOp op)
2248 {
2249 FcExpr *expr = FcPopBinary (parse, op);
2250 if (expr)
2251 FcVStackPushExpr (parse, FcVStackExpr, expr);
2252 }
2253
2254 /*
2255 * This builds a a unary operator, it consumes only
2256 * a single operand
2257 */
2258
2259 static FcExpr *
FcPopUnary(FcConfigParse * parse,FcOp op)2260 FcPopUnary (FcConfigParse *parse, FcOp op)
2261 {
2262 FcExpr *operand, *new = 0;
2263
2264 if ((operand = FcPopExpr (parse)))
2265 {
2266 new = FcExprCreateOp (parse->config, operand, op, 0);
2267 if (!new)
2268 {
2269 FcExprDestroy (operand);
2270 FcConfigMessage (parse, FcSevereError, "out of memory");
2271 }
2272 }
2273 return new;
2274 }
2275
2276 static void
FcParseUnary(FcConfigParse * parse,FcOp op)2277 FcParseUnary (FcConfigParse *parse, FcOp op)
2278 {
2279 FcExpr *expr = FcPopUnary (parse, op);
2280 if (expr)
2281 FcVStackPushExpr (parse, FcVStackExpr, expr);
2282 }
2283
2284 static void
FcParseDir(FcConfigParse * parse)2285 FcParseDir (FcConfigParse *parse)
2286 {
2287 const FcChar8 *attr, *data, *salt;
2288 FcStrSet *prefix_dirs = NULL;
2289
2290 data = FcStrBufDoneStatic (&parse->pstack->str);
2291 if (!data)
2292 {
2293 FcConfigMessage (parse, FcSevereError, "out of memory");
2294 return;
2295 }
2296 if (data[0] == 0)
2297 {
2298 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2299 return;
2300 }
2301 attr = FcConfigGetAttribute (parse, "prefix");
2302 salt = FcConfigGetAttribute (parse, "salt");
2303 prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2304 if (prefix_dirs)
2305 {
2306 FcStrList *l = FcStrListCreate (prefix_dirs);
2307 FcChar8 *prefix;
2308
2309 FcStrSetDestroy (prefix_dirs);
2310 while ((prefix = FcStrListNext (l)))
2311 {
2312 if (!prefix || prefix[0] == 0)
2313 {
2314 /* nop */
2315 }
2316 else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2317 {
2318 if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2319 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2320 }
2321 FcStrBufDestroy (&parse->pstack->str);
2322 }
2323 FcStrListDone (l);
2324 }
2325 }
2326
2327 static void
FcParseCacheDir(FcConfigParse * parse)2328 FcParseCacheDir (FcConfigParse *parse)
2329 {
2330 const FcChar8 *attr;
2331 FcChar8 *prefix = NULL, *p, *data = NULL;
2332
2333 attr = FcConfigGetAttribute (parse, "prefix");
2334 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2335 {
2336 prefix = FcConfigXdgCacheHome ();
2337 /* home directory might be disabled.
2338 * simply ignore this element.
2339 */
2340 if (!prefix)
2341 goto bail;
2342 }
2343 data = FcStrBufDone (&parse->pstack->str);
2344 if (!data)
2345 {
2346 FcConfigMessage (parse, FcSevereError, "out of memory");
2347 data = prefix;
2348 goto bail;
2349 }
2350 if (data[0] == 0)
2351 {
2352 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2353 FcStrFree (data);
2354 data = prefix;
2355 goto bail;
2356 }
2357 if (prefix)
2358 {
2359 size_t plen = strlen ((const char *)prefix);
2360 size_t dlen = strlen ((const char *)data);
2361
2362 p = realloc (prefix, plen + 1 + dlen + 1);
2363 if (!p)
2364 {
2365 FcConfigMessage (parse, FcSevereError, "out of memory");
2366 FcStrFree (prefix);
2367 goto bail;
2368 }
2369 prefix = p;
2370 prefix[plen] = FC_DIR_SEPARATOR;
2371 memcpy (&prefix[plen + 1], data, dlen);
2372 prefix[plen + 1 + dlen] = 0;
2373 FcStrFree (data);
2374 data = prefix;
2375 }
2376 #ifdef _WIN32
2377 else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2378 {
2379 size_t plen = strlen ((const char *)fontconfig_instprefix);
2380 size_t dlen = strlen ((const char *)data);
2381
2382 prefix = malloc (plen + 1 + dlen + 1);
2383 if (!prefix)
2384 {
2385 FcConfigMessage (parse, FcSevereError, "out of memory");
2386 goto bail;
2387 }
2388 strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2389 prefix[plen] = FC_DIR_SEPARATOR;
2390 memcpy (&prefix[plen + 1], data, dlen);
2391 prefix[plen + 1 + dlen] = 0;
2392 FcStrFree (data);
2393 data = prefix;
2394 }
2395 else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2396 {
2397 int rc;
2398
2399 FcStrFree (data);
2400 data = malloc (1000);
2401 if (!data)
2402 {
2403 FcConfigMessage (parse, FcSevereError, "out of memory");
2404 goto bail;
2405 }
2406 rc = GetTempPath (800, (LPSTR) data);
2407 if (rc == 0 || rc > 800)
2408 {
2409 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2410 goto bail;
2411 }
2412 if (data [strlen ((const char *) data) - 1] != '\\')
2413 strcat ((char *) data, "\\");
2414 strcat ((char *) data, "fontconfig\\cache");
2415 }
2416 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2417 {
2418 char szFPath[MAX_PATH + 1];
2419 size_t len;
2420
2421 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2422 {
2423 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2424 goto bail;
2425 }
2426 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2427 len = strlen(szFPath) + 1;
2428 FcStrFree (data);
2429 data = malloc(len);
2430 if (!data)
2431 {
2432 FcConfigMessage (parse, FcSevereError, "out of memory");
2433 goto bail;
2434 }
2435 strncpy((char *) data, szFPath, len);
2436 }
2437 #endif
2438 if (strlen ((char *) data) == 0)
2439 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2440 else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
2441 {
2442 if (!FcConfigAddCacheDir (parse->config, data))
2443 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2444 }
2445 FcStrBufDestroy (&parse->pstack->str);
2446
2447 bail:
2448 if (data)
2449 FcStrFree (data);
2450 }
2451
2452 void
FcConfigPathFini(void)2453 FcConfigPathFini (void)
2454 {
2455 FcChar8 *s;
2456
2457 retry_dir:
2458 s = fc_atomic_ptr_get (&__fc_userdir);
2459 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2460 goto retry_dir;
2461 free (s);
2462
2463 retry_conf:
2464 s = fc_atomic_ptr_get (&__fc_userconf);
2465 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2466 goto retry_conf;
2467 free (s);
2468 }
2469
2470 static void
FcParseInclude(FcConfigParse * parse)2471 FcParseInclude (FcConfigParse *parse)
2472 {
2473 FcChar8 *s;
2474 const FcChar8 *attr;
2475 FcBool ignore_missing = FcFalse;
2476 #ifndef _WIN32
2477 FcBool deprecated = FcFalse;
2478 #endif
2479 FcChar8 *prefix = NULL, *p;
2480 FcChar8 *userdir = NULL, *userconf = NULL;
2481 FcRuleSet *ruleset;
2482 FcMatchKind k;
2483
2484 s = FcStrBufDoneStatic (&parse->pstack->str);
2485 if (!s)
2486 {
2487 FcConfigMessage (parse, FcSevereError, "out of memory");
2488 goto bail;
2489 }
2490 attr = FcConfigGetAttribute (parse, "ignore_missing");
2491 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2492 ignore_missing = FcTrue;
2493 attr = FcConfigGetAttribute (parse, "deprecated");
2494 #ifndef _WIN32
2495 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2496 deprecated = FcTrue;
2497 #endif
2498 attr = FcConfigGetAttribute (parse, "prefix");
2499 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2500 {
2501 prefix = FcConfigXdgConfigHome ();
2502 /* home directory might be disabled.
2503 * simply ignore this element.
2504 */
2505 if (!prefix)
2506 goto bail;
2507 }
2508 if (prefix)
2509 {
2510 size_t plen = strlen ((const char *)prefix);
2511 size_t dlen = strlen ((const char *)s);
2512 FcChar8 *u;
2513
2514 p = realloc (prefix, plen + 1 + dlen + 1);
2515 if (!p)
2516 {
2517 FcConfigMessage (parse, FcSevereError, "out of memory");
2518 goto bail;
2519 }
2520 prefix = p;
2521 prefix[plen] = FC_DIR_SEPARATOR;
2522 memcpy (&prefix[plen + 1], s, dlen);
2523 prefix[plen + 1 + dlen] = 0;
2524 s = prefix;
2525 if (FcFileIsDir (s))
2526 {
2527 userdir:
2528 userdir = fc_atomic_ptr_get (&__fc_userdir);
2529 if (!userdir)
2530 {
2531 u = FcStrdup (s);
2532 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2533 {
2534 free (u);
2535 goto userdir;
2536 }
2537 userdir = u;
2538 }
2539 }
2540 else if (FcFileIsFile (s))
2541 {
2542 userconf:
2543 userconf = fc_atomic_ptr_get (&__fc_userconf);
2544 if (!userconf)
2545 {
2546 u = FcStrdup (s);
2547 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2548 {
2549 free (u);
2550 goto userconf;
2551 }
2552 userconf = u;
2553 }
2554 }
2555 else
2556 {
2557 /* No config dir nor file on the XDG directory spec compliant place
2558 * so need to guess what it is supposed to be.
2559 */
2560 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2561 goto userdir;
2562 else
2563 goto userconf;
2564 }
2565 }
2566 /* flush the ruleset into the queue */
2567 ruleset = parse->ruleset;
2568 parse->ruleset = FcRuleSetCreate (ruleset->name);
2569 FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2570 FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2571 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
2572 {
2573 FcPtrListIter iter;
2574
2575 FcPtrListIterInit (ruleset->subst[k], &iter);
2576 if (FcPtrListIterIsValid (ruleset->subst[k], &iter))
2577 {
2578 FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2579 FcRuleSetReference (ruleset);
2580 FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2581 }
2582 }
2583 FcRuleSetDestroy (ruleset);
2584 if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
2585 parse->error = FcTrue;
2586 #ifndef _WIN32
2587 else
2588 {
2589 FcChar8 *filename;
2590 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2591
2592 filename = FcConfigGetFilename(parse->config, s);
2593 if (deprecated == FcTrue &&
2594 filename != NULL &&
2595 userdir != NULL &&
2596 !FcFileIsLink (filename))
2597 {
2598 if (FcFileIsDir (filename))
2599 {
2600 FcChar8 *parent = FcStrDirname (userdir);
2601
2602 if (!FcFileIsDir (parent))
2603 FcMakeDirectory (parent);
2604 FcStrFree (parent);
2605 if (FcFileIsDir (userdir) ||
2606 rename ((const char *)filename, (const char *)userdir) != 0 ||
2607 symlink ((const char *)userdir, (const char *)filename) != 0)
2608 {
2609 if (!warn_confd)
2610 {
2611 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2612 warn_confd = FcTrue;
2613 }
2614 }
2615 }
2616 else
2617 {
2618 FcChar8 *parent = FcStrDirname (userconf);
2619
2620 if (!FcFileIsDir (parent))
2621 FcMakeDirectory (parent);
2622 FcStrFree (parent);
2623 if (FcFileIsFile (userconf) ||
2624 rename ((const char *)filename, (const char *)userconf) != 0 ||
2625 symlink ((const char *)userconf, (const char *)filename) != 0)
2626 {
2627 if (!warn_conf)
2628 {
2629 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2630 warn_conf = FcTrue;
2631 }
2632 }
2633 }
2634 }
2635 if(filename)
2636 FcStrFree(filename);
2637 }
2638 #endif
2639 FcStrBufDestroy (&parse->pstack->str);
2640
2641 bail:
2642 if (prefix)
2643 FcStrFree (prefix);
2644 }
2645
2646 typedef struct _FcOpMap {
2647 char name[16];
2648 FcOp op;
2649 } FcOpMap;
2650
2651 static FcOp
FcConfigLexOp(const FcChar8 * op,const FcOpMap * map,int nmap)2652 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2653 {
2654 int i;
2655
2656 for (i = 0; i < nmap; i++)
2657 if (!strcmp ((char *) op, map[i].name))
2658 return map[i].op;
2659 return FcOpInvalid;
2660 }
2661
2662 static const FcOpMap fcCompareOps[] = {
2663 { "eq", FcOpEqual },
2664 { "not_eq", FcOpNotEqual },
2665 { "less", FcOpLess },
2666 { "less_eq", FcOpLessEqual },
2667 { "more", FcOpMore },
2668 { "more_eq", FcOpMoreEqual },
2669 { "contains", FcOpContains },
2670 { "not_contains", FcOpNotContains }
2671 };
2672
2673 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2674
2675 static FcOp
FcConfigLexCompare(const FcChar8 * compare)2676 FcConfigLexCompare (const FcChar8 *compare)
2677 {
2678 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2679 }
2680
2681 static void
FcParseTest(FcConfigParse * parse)2682 FcParseTest (FcConfigParse *parse)
2683 {
2684 const FcChar8 *kind_string;
2685 FcMatchKind kind;
2686 const FcChar8 *qual_string;
2687 FcQual qual;
2688 const FcChar8 *name;
2689 const FcChar8 *compare_string;
2690 FcOp compare;
2691 FcExpr *expr;
2692 FcTest *test;
2693 const FcChar8 *iblanks_string;
2694 int flags = 0;
2695
2696 kind_string = FcConfigGetAttribute (parse, "target");
2697 if (!kind_string)
2698 kind = FcMatchDefault;
2699 else
2700 {
2701 if (!strcmp ((char *) kind_string, "pattern"))
2702 kind = FcMatchPattern;
2703 else if (!strcmp ((char *) kind_string, "font"))
2704 kind = FcMatchFont;
2705 else if (!strcmp ((char *) kind_string, "scan"))
2706 kind = FcMatchScan;
2707 else if (!strcmp ((char *) kind_string, "default"))
2708 kind = FcMatchDefault;
2709 else
2710 {
2711 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2712 return;
2713 }
2714 }
2715 qual_string = FcConfigGetAttribute (parse, "qual");
2716 if (!qual_string)
2717 qual = FcQualAny;
2718 else
2719 {
2720 if (!strcmp ((char *) qual_string, "any"))
2721 qual = FcQualAny;
2722 else if (!strcmp ((char *) qual_string, "all"))
2723 qual = FcQualAll;
2724 else if (!strcmp ((char *) qual_string, "first"))
2725 qual = FcQualFirst;
2726 else if (!strcmp ((char *) qual_string, "not_first"))
2727 qual = FcQualNotFirst;
2728 else
2729 {
2730 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2731 return;
2732 }
2733 }
2734 name = FcConfigGetAttribute (parse, "name");
2735 if (!name)
2736 {
2737 FcConfigMessage (parse, FcSevereWarning, "missing test name");
2738 return;
2739 }
2740 compare_string = FcConfigGetAttribute (parse, "compare");
2741 if (!compare_string)
2742 compare = FcOpEqual;
2743 else
2744 {
2745 compare = FcConfigLexCompare (compare_string);
2746 if (compare == FcOpInvalid)
2747 {
2748 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2749 return;
2750 }
2751 }
2752 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2753 if (iblanks_string)
2754 {
2755 FcBool f = FcFalse;
2756
2757 if (!FcNameBool (iblanks_string, &f))
2758 {
2759 FcConfigMessage (parse,
2760 FcSevereWarning,
2761 "invalid test ignore-blanks \"%s\"", iblanks_string);
2762 }
2763 if (f)
2764 flags |= FcOpFlagIgnoreBlanks;
2765 }
2766 expr = FcPopBinary (parse, FcOpComma);
2767 if (!expr)
2768 {
2769 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2770 return;
2771 }
2772 if (expr->op == FcOpComma)
2773 {
2774 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2775 }
2776 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2777 if (!test)
2778 {
2779 FcConfigMessage (parse, FcSevereError, "out of memory");
2780 return;
2781 }
2782 FcVStackPushTest (parse, test);
2783 }
2784
2785 static const FcOpMap fcModeOps[] = {
2786 { "assign", FcOpAssign },
2787 { "assign_replace", FcOpAssignReplace },
2788 { "prepend", FcOpPrepend },
2789 { "prepend_first", FcOpPrependFirst },
2790 { "append", FcOpAppend },
2791 { "append_last", FcOpAppendLast },
2792 { "delete", FcOpDelete },
2793 { "delete_all", FcOpDeleteAll },
2794 };
2795
2796 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2797
2798 static FcOp
FcConfigLexMode(const FcChar8 * mode)2799 FcConfigLexMode (const FcChar8 *mode)
2800 {
2801 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2802 }
2803
2804 static void
FcParseEdit(FcConfigParse * parse)2805 FcParseEdit (FcConfigParse *parse)
2806 {
2807 const FcChar8 *name;
2808 const FcChar8 *mode_string;
2809 FcOp mode;
2810 FcValueBinding binding;
2811 FcExpr *expr;
2812 FcEdit *edit;
2813
2814 name = FcConfigGetAttribute (parse, "name");
2815 if (!name)
2816 {
2817 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2818 return;
2819 }
2820 mode_string = FcConfigGetAttribute (parse, "mode");
2821 if (!mode_string)
2822 mode = FcOpAssign;
2823 else
2824 {
2825 mode = FcConfigLexMode (mode_string);
2826 if (mode == FcOpInvalid)
2827 {
2828 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2829 return;
2830 }
2831 }
2832 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2833 return;
2834
2835 expr = FcPopBinary (parse, FcOpComma);
2836 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2837 expr != NULL)
2838 {
2839 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2840 FcExprDestroy (expr);
2841 expr = NULL;
2842 }
2843 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2844 mode, expr, binding);
2845 if (!edit)
2846 {
2847 FcConfigMessage (parse, FcSevereError, "out of memory");
2848 FcExprDestroy (expr);
2849 return;
2850 }
2851 if (!FcVStackPushEdit (parse, edit))
2852 FcEditDestroy (edit);
2853 }
2854
2855 static void
FcParseMatch(FcConfigParse * parse)2856 FcParseMatch (FcConfigParse *parse)
2857 {
2858 const FcChar8 *kind_name;
2859 FcMatchKind kind;
2860 FcVStack *vstack;
2861 FcRule *rule = NULL, *r;
2862 int n;
2863
2864 kind_name = FcConfigGetAttribute (parse, "target");
2865 if (!kind_name)
2866 kind = FcMatchPattern;
2867 else
2868 {
2869 if (!strcmp ((char *) kind_name, "pattern"))
2870 kind = FcMatchPattern;
2871 else if (!strcmp ((char *) kind_name, "font"))
2872 kind = FcMatchFont;
2873 else if (!strcmp ((char *) kind_name, "scan"))
2874 kind = FcMatchScan;
2875 else
2876 {
2877 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2878 return;
2879 }
2880 }
2881 while ((vstack = FcVStackPeek (parse)))
2882 {
2883 switch ((int) vstack->tag) {
2884 case FcVStackTest:
2885 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2886 if (rule)
2887 r->next = rule;
2888 rule = r;
2889 vstack->tag = FcVStackNone;
2890 break;
2891 case FcVStackEdit:
2892 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2893 {
2894 FcConfigMessage (parse, FcSevereError,
2895 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2896 FcObjectName(vstack->u.edit->object));
2897 if (rule)
2898 FcRuleDestroy (rule);
2899 return;
2900 }
2901 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2902 if (rule)
2903 r->next = rule;
2904 rule = r;
2905 vstack->tag = FcVStackNone;
2906 break;
2907 default:
2908 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2909 break;
2910 }
2911 FcVStackPopAndDestroy (parse);
2912 }
2913 if (!rule)
2914 {
2915 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2916 return;
2917 }
2918 if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1)
2919 {
2920 FcConfigMessage (parse, FcSevereError, "out of memory");
2921 FcRuleDestroy (rule);
2922 }
2923 else
2924 if (parse->config->maxObjects < n)
2925 parse->config->maxObjects = n;
2926 }
2927
2928 static void
FcParseAcceptRejectFont(FcConfigParse * parse,FcElement element)2929 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2930 {
2931 FcVStack *vstack;
2932
2933 while ((vstack = FcVStackPeek (parse)))
2934 {
2935 switch ((int) vstack->tag) {
2936 case FcVStackGlob:
2937 if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2938 vstack->u.string,
2939 element == FcElementAcceptfont))
2940 {
2941 FcConfigMessage (parse, FcSevereError, "out of memory");
2942 }
2943 else
2944 {
2945 if (parse->scanOnly && vstack->u.string)
2946 {
2947 FcStrFree (vstack->u.string);
2948 vstack->tag = FcVStackNone;
2949 }
2950 }
2951 break;
2952 case FcVStackPattern:
2953 if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2954 vstack->u.pattern,
2955 element == FcElementAcceptfont))
2956 {
2957 FcConfigMessage (parse, FcSevereError, "out of memory");
2958 }
2959 else
2960 {
2961 if (parse->scanOnly && vstack->u.pattern)
2962 FcPatternDestroy (vstack->u.pattern);
2963 vstack->tag = FcVStackNone;
2964 }
2965 break;
2966 default:
2967 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2968 break;
2969 }
2970 FcVStackPopAndDestroy (parse);
2971 }
2972 }
2973
2974
2975 static FcValue
FcPopValue(FcConfigParse * parse)2976 FcPopValue (FcConfigParse *parse)
2977 {
2978 FcVStack *vstack = FcVStackPeek (parse);
2979 FcValue value;
2980
2981 value.type = FcTypeVoid;
2982
2983 if (!vstack)
2984 return value;
2985
2986 switch ((int) vstack->tag) {
2987 case FcVStackString:
2988 value.u.s = FcStrdup (vstack->u.string);
2989 if (value.u.s)
2990 value.type = FcTypeString;
2991 break;
2992 case FcVStackConstant:
2993 if (FcNameConstant (vstack->u.string, &value.u.i))
2994 value.type = FcTypeInteger;
2995 break;
2996 case FcVStackInteger:
2997 value.u.i = vstack->u.integer;
2998 value.type = FcTypeInteger;
2999 break;
3000 case FcVStackDouble:
3001 value.u.d = vstack->u._double;
3002 value.type = FcTypeDouble;
3003 break;
3004 case FcVStackBool:
3005 value.u.b = vstack->u.bool_;
3006 value.type = FcTypeBool;
3007 break;
3008 case FcVStackCharSet:
3009 value.u.c = FcCharSetCopy (vstack->u.charset);
3010 if (value.u.c)
3011 value.type = FcTypeCharSet;
3012 break;
3013 case FcVStackLangSet:
3014 value.u.l = FcLangSetCopy (vstack->u.langset);
3015 if (value.u.l)
3016 value.type = FcTypeLangSet;
3017 break;
3018 case FcVStackRange:
3019 value.u.r = FcRangeCopy (vstack->u.range);
3020 if (value.u.r)
3021 value.type = FcTypeRange;
3022 break;
3023 default:
3024 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
3025 vstack->tag);
3026 break;
3027 }
3028 FcVStackPopAndDestroy (parse);
3029
3030 return value;
3031 }
3032
3033 static void
FcParsePatelt(FcConfigParse * parse)3034 FcParsePatelt (FcConfigParse *parse)
3035 {
3036 FcValue value;
3037 FcPattern *pattern = FcPatternCreate ();
3038 const char *name;
3039
3040 if (!pattern)
3041 {
3042 FcConfigMessage (parse, FcSevereError, "out of memory");
3043 return;
3044 }
3045
3046 name = (char *) FcConfigGetAttribute (parse, "name");
3047 if (!name)
3048 {
3049 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
3050 FcPatternDestroy (pattern);
3051 return;
3052 }
3053
3054 for (;;)
3055 {
3056 value = FcPopValue (parse);
3057 if (value.type == FcTypeVoid)
3058 break;
3059 if (!FcPatternAdd (pattern, name, value, FcTrue))
3060 {
3061 FcConfigMessage (parse, FcSevereError, "out of memory");
3062 FcValueDestroy(value);
3063 break;
3064 }
3065 FcValueDestroy(value);
3066 }
3067
3068 FcVStackPushPattern (parse, pattern);
3069 }
3070
3071 static void
FcParsePattern(FcConfigParse * parse)3072 FcParsePattern (FcConfigParse *parse)
3073 {
3074 FcVStack *vstack;
3075 FcPattern *pattern = FcPatternCreate ();
3076
3077 if (!pattern)
3078 {
3079 FcConfigMessage (parse, FcSevereError, "out of memory");
3080 return;
3081 }
3082
3083 while ((vstack = FcVStackPeek (parse)))
3084 {
3085 switch ((int) vstack->tag) {
3086 case FcVStackPattern:
3087 if (!FcPatternAppend (pattern, vstack->u.pattern))
3088 {
3089 FcConfigMessage (parse, FcSevereError, "out of memory");
3090 FcPatternDestroy (pattern);
3091 return;
3092 }
3093 break;
3094 default:
3095 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
3096 break;
3097 }
3098 FcVStackPopAndDestroy (parse);
3099 }
3100
3101 FcVStackPushPattern (parse, pattern);
3102 }
3103
3104 static void
FcEndElement(void * userData,const XML_Char * name FC_UNUSED)3105 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
3106 {
3107 FcConfigParse *parse = userData;
3108 FcChar8 *data;
3109
3110 if (!parse->pstack)
3111 return;
3112 switch (parse->pstack->element) {
3113 case FcElementNone:
3114 break;
3115 case FcElementFontconfig:
3116 break;
3117 case FcElementDir:
3118 FcParseDir (parse);
3119 break;
3120 case FcElementCacheDir:
3121 FcParseCacheDir (parse);
3122 break;
3123 case FcElementCache:
3124 data = FcStrBufDoneStatic (&parse->pstack->str);
3125 if (!data)
3126 {
3127 FcConfigMessage (parse, FcSevereError, "out of memory");
3128 break;
3129 }
3130 /* discard this data; no longer used */
3131 FcStrBufDestroy (&parse->pstack->str);
3132 break;
3133 case FcElementInclude:
3134 FcParseInclude (parse);
3135 break;
3136 case FcElementConfig:
3137 break;
3138 case FcElementMatch:
3139 FcParseMatch (parse);
3140 break;
3141 case FcElementAlias:
3142 FcParseAlias (parse);
3143 break;
3144 case FcElementDescription:
3145 FcParseDescription (parse);
3146 break;
3147 case FcElementRemapDir:
3148 FcParseRemapDir (parse);
3149 break;
3150 case FcElementResetDirs:
3151 FcParseResetDirs (parse);
3152 break;
3153
3154 case FcElementRescan:
3155 FcParseRescan (parse);
3156 break;
3157
3158 case FcElementPrefer:
3159 FcParseFamilies (parse, FcVStackPrefer);
3160 break;
3161 case FcElementAccept:
3162 FcParseFamilies (parse, FcVStackAccept);
3163 break;
3164 case FcElementDefault:
3165 FcParseFamilies (parse, FcVStackDefault);
3166 break;
3167 case FcElementFamily:
3168 FcParseFamily (parse);
3169 break;
3170
3171 case FcElementTest:
3172 FcParseTest (parse);
3173 break;
3174 case FcElementEdit:
3175 FcParseEdit (parse);
3176 break;
3177
3178 case FcElementInt:
3179 FcParseInt (parse);
3180 break;
3181 case FcElementDouble:
3182 FcParseDouble (parse);
3183 break;
3184 case FcElementString:
3185 FcParseString (parse, FcVStackString);
3186 break;
3187 case FcElementMatrix:
3188 FcParseMatrix (parse);
3189 break;
3190 case FcElementRange:
3191 FcParseRange (parse);
3192 break;
3193 case FcElementBool:
3194 FcParseBool (parse);
3195 break;
3196 case FcElementCharSet:
3197 FcParseCharSet (parse);
3198 break;
3199 case FcElementLangSet:
3200 FcParseLangSet (parse);
3201 break;
3202 case FcElementSelectfont:
3203 break;
3204 case FcElementAcceptfont:
3205 case FcElementRejectfont:
3206 FcParseAcceptRejectFont (parse, parse->pstack->element);
3207 break;
3208 case FcElementGlob:
3209 FcParseString (parse, FcVStackGlob);
3210 break;
3211 case FcElementPattern:
3212 FcParsePattern (parse);
3213 break;
3214 case FcElementPatelt:
3215 FcParsePatelt (parse);
3216 break;
3217 case FcElementName:
3218 FcParseName (parse);
3219 break;
3220 case FcElementConst:
3221 FcParseString (parse, FcVStackConstant);
3222 break;
3223 case FcElementOr:
3224 FcParseBinary (parse, FcOpOr);
3225 break;
3226 case FcElementAnd:
3227 FcParseBinary (parse, FcOpAnd);
3228 break;
3229 case FcElementEq:
3230 FcParseBinary (parse, FcOpEqual);
3231 break;
3232 case FcElementNotEq:
3233 FcParseBinary (parse, FcOpNotEqual);
3234 break;
3235 case FcElementLess:
3236 FcParseBinary (parse, FcOpLess);
3237 break;
3238 case FcElementLessEq:
3239 FcParseBinary (parse, FcOpLessEqual);
3240 break;
3241 case FcElementMore:
3242 FcParseBinary (parse, FcOpMore);
3243 break;
3244 case FcElementMoreEq:
3245 FcParseBinary (parse, FcOpMoreEqual);
3246 break;
3247 case FcElementContains:
3248 FcParseBinary (parse, FcOpContains);
3249 break;
3250 case FcElementNotContains:
3251 FcParseBinary (parse, FcOpNotContains);
3252 break;
3253 case FcElementPlus:
3254 FcParseBinary (parse, FcOpPlus);
3255 break;
3256 case FcElementMinus:
3257 FcParseBinary (parse, FcOpMinus);
3258 break;
3259 case FcElementTimes:
3260 FcParseBinary (parse, FcOpTimes);
3261 break;
3262 case FcElementDivide:
3263 FcParseBinary (parse, FcOpDivide);
3264 break;
3265 case FcElementNot:
3266 FcParseUnary (parse, FcOpNot);
3267 break;
3268 case FcElementIf:
3269 FcParseBinary (parse, FcOpQuest);
3270 break;
3271 case FcElementFloor:
3272 FcParseUnary (parse, FcOpFloor);
3273 break;
3274 case FcElementCeil:
3275 FcParseUnary (parse, FcOpCeil);
3276 break;
3277 case FcElementRound:
3278 FcParseUnary (parse, FcOpRound);
3279 break;
3280 case FcElementTrunc:
3281 FcParseUnary (parse, FcOpTrunc);
3282 break;
3283 case FcElementUnknown:
3284 break;
3285 }
3286 (void) FcPStackPop (parse);
3287 }
3288
3289 static void
FcCharacterData(void * userData,const XML_Char * s,int len)3290 FcCharacterData (void *userData, const XML_Char *s, int len)
3291 {
3292 FcConfigParse *parse = userData;
3293
3294 if (!parse->pstack)
3295 return;
3296 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
3297 FcConfigMessage (parse, FcSevereError, "out of memory");
3298 }
3299
3300 static void
FcStartDoctypeDecl(void * userData,const XML_Char * doctypeName,const XML_Char * sysid FC_UNUSED,const XML_Char * pubid FC_UNUSED,int has_internal_subset FC_UNUSED)3301 FcStartDoctypeDecl (void *userData,
3302 const XML_Char *doctypeName,
3303 const XML_Char *sysid FC_UNUSED,
3304 const XML_Char *pubid FC_UNUSED,
3305 int has_internal_subset FC_UNUSED)
3306 {
3307 FcConfigParse *parse = userData;
3308
3309 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
3310 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3311 }
3312
3313 #ifdef ENABLE_LIBXML2
3314
3315 static void
FcInternalSubsetDecl(void * userData,const XML_Char * doctypeName,const XML_Char * sysid,const XML_Char * pubid)3316 FcInternalSubsetDecl (void *userData,
3317 const XML_Char *doctypeName,
3318 const XML_Char *sysid,
3319 const XML_Char *pubid)
3320 {
3321 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3322 }
3323
3324 static void
FcExternalSubsetDecl(void * userData,const XML_Char * doctypeName,const XML_Char * sysid,const XML_Char * pubid)3325 FcExternalSubsetDecl (void *userData,
3326 const XML_Char *doctypeName,
3327 const XML_Char *sysid,
3328 const XML_Char *pubid)
3329 {
3330 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3331 }
3332
3333 #else /* ENABLE_LIBXML2 */
3334
3335 static void
FcEndDoctypeDecl(void * userData FC_UNUSED)3336 FcEndDoctypeDecl (void *userData FC_UNUSED)
3337 {
3338 }
3339
3340 #endif /* ENABLE_LIBXML2 */
3341
3342 static int
FcSortCmpStr(const void * a,const void * b)3343 FcSortCmpStr (const void *a, const void *b)
3344 {
3345 const FcChar8 *as = *((FcChar8 **) a);
3346 const FcChar8 *bs = *((FcChar8 **) b);
3347 return FcStrCmp (as, bs);
3348 }
3349
3350 static FcBool
FcConfigParseAndLoadDir(FcConfig * config,const FcChar8 * name,const FcChar8 * dir,FcBool complain,FcBool load)3351 FcConfigParseAndLoadDir (FcConfig *config,
3352 const FcChar8 *name,
3353 const FcChar8 *dir,
3354 FcBool complain,
3355 FcBool load)
3356 {
3357 DIR *d;
3358 struct dirent *e;
3359 FcBool ret = FcTrue;
3360 FcChar8 *file;
3361 FcChar8 *base;
3362 FcStrSet *files;
3363
3364 d = opendir ((char *) dir);
3365 if (!d)
3366 {
3367 if (complain)
3368 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3369 name);
3370 ret = FcFalse;
3371 goto bail0;
3372 }
3373 /* freed below */
3374 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3375 if (!file)
3376 {
3377 ret = FcFalse;
3378 goto bail1;
3379 }
3380
3381 strcpy ((char *) file, (char *) dir);
3382 strcat ((char *) file, "/");
3383 base = file + strlen ((char *) file);
3384
3385 files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3386 if (!files)
3387 {
3388 ret = FcFalse;
3389 goto bail2;
3390 }
3391
3392 if (FcDebug () & FC_DBG_CONFIG)
3393 printf ("\tScanning config dir %s\n", dir);
3394
3395 if (load)
3396 FcConfigAddConfigDir (config, dir);
3397
3398 while (ret && (e = readdir (d)))
3399 {
3400 int d_len;
3401 #define TAIL ".conf"
3402 #define TAIL_LEN 5
3403 /*
3404 * Add all files of the form [0-9]*.conf
3405 */
3406 d_len = strlen (e->d_name);
3407 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3408 d_len > TAIL_LEN &&
3409 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3410 {
3411 strcpy ((char *) base, (char *) e->d_name);
3412 if (!FcStrSetAdd (files, file))
3413 {
3414 ret = FcFalse;
3415 goto bail3;
3416 }
3417 }
3418 }
3419 if (ret)
3420 {
3421 int i;
3422 qsort (files->strs, files->num, sizeof (FcChar8 *),
3423 (int (*)(const void *, const void *)) FcSortCmpStr);
3424 for (i = 0; ret && i < files->num; i++)
3425 ret = _FcConfigParse (config, files->strs[i], complain, load);
3426 }
3427 bail3:
3428 FcStrSetDestroy (files);
3429 bail2:
3430 free (file);
3431 bail1:
3432 closedir (d);
3433 bail0:
3434 return ret || !complain;
3435 }
3436
3437 #ifdef _WIN32
3438 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3439 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3440 #endif
3441
3442 static FcBool
FcConfigParseAndLoadFromMemoryInternal(FcConfig * config,const FcChar8 * filename,const FcChar8 * buffer,FcBool complain,FcBool load)3443 FcConfigParseAndLoadFromMemoryInternal (FcConfig *config,
3444 const FcChar8 *filename,
3445 const FcChar8 *buffer,
3446 FcBool complain,
3447 FcBool load)
3448 {
3449
3450 XML_Parser p;
3451 size_t len;
3452 FcConfigParse parse;
3453 FcBool error = FcTrue;
3454 FcMatchKind k;
3455 FcPtrListIter liter;
3456
3457 #ifdef ENABLE_LIBXML2
3458 xmlSAXHandler sax;
3459 #else
3460 void *buf;
3461 const FcChar8 *s;
3462 size_t buflen;
3463 #endif
3464
3465 if (!buffer)
3466 return FcFalse;
3467 len = strlen ((const char *) buffer);
3468 if (FcDebug () & FC_DBG_CONFIG)
3469 printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3470
3471 #ifdef ENABLE_LIBXML2
3472 memset(&sax, 0, sizeof(sax));
3473
3474 sax.internalSubset = FcInternalSubsetDecl;
3475 sax.externalSubset = FcExternalSubsetDecl;
3476 sax.startElement = FcStartElement;
3477 sax.endElement = FcEndElement;
3478 sax.characters = FcCharacterData;
3479
3480 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3481 #else
3482 p = XML_ParserCreate ("UTF-8");
3483 #endif
3484
3485 if (!p)
3486 goto bail1;
3487
3488 if (!FcConfigParseInit (&parse, filename, config, p, load))
3489 goto bail2;
3490
3491 #ifndef ENABLE_LIBXML2
3492
3493 XML_SetUserData (p, &parse);
3494
3495 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3496 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3497 XML_SetCharacterDataHandler (p, FcCharacterData);
3498
3499 #endif /* ENABLE_LIBXML2 */
3500
3501 #ifndef ENABLE_LIBXML2
3502 s = buffer;
3503 do {
3504 buf = XML_GetBuffer (p, BUFSIZ);
3505 if (!buf)
3506 {
3507 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3508 goto bail3;
3509 }
3510 if (len > BUFSIZ)
3511 {
3512 buflen = BUFSIZ;
3513 len -= BUFSIZ;
3514 }
3515 else
3516 {
3517 buflen = len;
3518 len = 0;
3519 }
3520 memcpy (buf, s, buflen);
3521 s = s + buflen;
3522 #endif
3523
3524 #ifdef ENABLE_LIBXML2
3525 if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3526 #else
3527 if (!XML_ParseBuffer (p, buflen, buflen == 0))
3528 #endif
3529 {
3530 FcConfigMessage (&parse, FcSevereError, "%s",
3531 XML_ErrorString (XML_GetErrorCode (p)));
3532 goto bail3;
3533 }
3534 #ifndef ENABLE_LIBXML2
3535 } while (buflen != 0);
3536 #endif
3537 error = parse.error;
3538 if (load)
3539 {
3540 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3541 {
3542 FcPtrListIter iter;
3543
3544 FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3545 if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
3546 {
3547 FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3548 FcRuleSetReference (parse.ruleset);
3549 FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3550 }
3551 }
3552 }
3553 FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3554 FcRuleSetReference (parse.ruleset);
3555 FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3556 bail3:
3557 FcConfigCleanup (&parse);
3558 bail2:
3559 XML_ParserFree (p);
3560 bail1:
3561 if (error && complain)
3562 {
3563 FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3564 return FcFalse;
3565 }
3566 if (FcDebug () & FC_DBG_CONFIG)
3567 printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3568 return FcTrue;
3569 }
3570
3571 static FcBool
_FcConfigParse(FcConfig * config,const FcChar8 * name,FcBool complain,FcBool load)3572 _FcConfigParse (FcConfig *config,
3573 const FcChar8 *name,
3574 FcBool complain,
3575 FcBool load)
3576 {
3577 FcChar8 *filename = NULL, *realfilename = NULL;
3578 int fd;
3579 int len;
3580 FcStrBuf sbuf;
3581 char buf[BUFSIZ];
3582 FcBool ret = FcFalse, complain_again = complain;
3583 FcStrBuf reason;
3584
3585 FcStrBufInit (&reason, NULL, 0);
3586 #ifdef _WIN32
3587 if (!pGetSystemWindowsDirectory)
3588 {
3589 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3590 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3591 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3592 }
3593 if (!pSHGetFolderPathA)
3594 {
3595 HMODULE hSh = LoadLibraryA("shfolder.dll");
3596 /* the check is done later, because there is no provided fallback */
3597 if (hSh)
3598 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3599 }
3600 #endif
3601
3602 filename = FcConfigGetFilename (config, name);
3603 if (!filename)
3604 {
3605 FcStrBufString (&reason, (FcChar8 *)"No such file: ");
3606 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3607 goto bail0;
3608 }
3609 realfilename = FcConfigRealFilename (config, name);
3610 if (!realfilename)
3611 {
3612 FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3613 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3614 goto bail0;
3615 }
3616 if (FcStrSetMember (config->availConfigFiles, realfilename))
3617 {
3618 FcStrFree (filename);
3619 FcStrFree (realfilename);
3620 return FcTrue;
3621 }
3622
3623 if (load)
3624 {
3625 if (!FcStrSetAdd (config->configFiles, filename))
3626 goto bail0;
3627 }
3628 if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3629 goto bail0;
3630
3631 if (FcFileIsDir (realfilename))
3632 {
3633 ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3634 FcStrFree (filename);
3635 FcStrFree (realfilename);
3636 return ret;
3637 }
3638
3639 FcStrBufInit (&sbuf, NULL, 0);
3640
3641 fd = FcOpen ((char *) realfilename, O_RDONLY);
3642 if (fd == -1)
3643 {
3644 FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3645 FcStrBufString (&reason, realfilename);
3646 goto bail1;
3647 }
3648
3649 do {
3650 len = read (fd, buf, BUFSIZ);
3651 if (len < 0)
3652 {
3653 int errno_ = errno;
3654 char ebuf[BUFSIZ+1];
3655
3656 #if HAVE_STRERROR_R
3657 strerror_r (errno_, ebuf, BUFSIZ);
3658 #elif HAVE_STRERROR
3659 char *tmp = strerror (errno_);
3660 size_t len = strlen (tmp);
3661 memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3662 ebuf[FC_MIN (BUFSIZ, len)] = 0;
3663 #else
3664 ebuf[0] = 0;
3665 #endif
3666 FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3667 close (fd);
3668 goto bail1;
3669 }
3670 FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3671 } while (len != 0);
3672 close (fd);
3673
3674 ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3675 complain_again = FcFalse; /* no need to reclaim here */
3676 bail1:
3677 FcStrBufDestroy (&sbuf);
3678 bail0:
3679 if (filename)
3680 FcStrFree (filename);
3681 if (realfilename)
3682 FcStrFree (realfilename);
3683 if (!complain)
3684 return FcTrue;
3685 if (!ret && complain_again)
3686 {
3687 if (name)
3688 FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
3689 else
3690 FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3691 FcStrBufDestroy (&reason);
3692 return FcFalse;
3693 }
3694 FcStrBufDestroy (&reason);
3695 return ret;
3696 }
3697
3698 FcBool
FcConfigParseOnly(FcConfig * config,const FcChar8 * name,FcBool complain)3699 FcConfigParseOnly (FcConfig *config,
3700 const FcChar8 *name,
3701 FcBool complain)
3702 {
3703 return _FcConfigParse (config, name, complain, FcFalse);
3704 }
3705
3706 FcBool
FcConfigParseAndLoad(FcConfig * config,const FcChar8 * name,FcBool complain)3707 FcConfigParseAndLoad (FcConfig *config,
3708 const FcChar8 *name,
3709 FcBool complain)
3710 {
3711 return _FcConfigParse (config, name, complain, FcTrue);
3712 }
3713
3714 FcBool
FcConfigParseAndLoadFromMemory(FcConfig * config,const FcChar8 * buffer,FcBool complain)3715 FcConfigParseAndLoadFromMemory (FcConfig *config,
3716 const FcChar8 *buffer,
3717 FcBool complain)
3718 {
3719 return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3720 }
3721
3722 #define __fcxml__
3723 #include "fcaliastail.h"
3724 #undef __fcxml__
3725