File: | src/fcxml.c |
Location: | line 1919, column 14 |
Description: | Potential leak of memory pointed to by 'edit' |
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; | |||
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__ |