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