1 /*
2 * fontconfig/src/fccfg.c
3 *
4 * Copyright © 2000 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 /* Objects MT-safe for readonly access. */
26
27 #include "fcint.h"
28 #include <dirent.h>
29 #include <sys/types.h>
30
31 #if defined (_WIN32) && !defined (R_OK)
32 #define R_OK 4
33 #endif
34
35 static FcConfig *_fcConfig; /* MT-safe */
36
37 static FcConfig *
FcConfigEnsure(void)38 FcConfigEnsure (void)
39 {
40 FcConfig *config;
41 retry:
42 config = fc_atomic_ptr_get (&_fcConfig);
43 if (!config)
44 {
45 config = FcInitLoadConfigAndFonts ();
46
47 if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
48 FcConfigDestroy (config);
49 goto retry;
50 }
51 }
52 return config;
53 }
54
55 FcBool
FcConfigInit(void)56 FcConfigInit (void)
57 {
58 return FcConfigEnsure () ? FcTrue : FcFalse;
59 }
60
61 void
FcConfigFini(void)62 FcConfigFini (void)
63 {
64 FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
65 if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
66 FcConfigDestroy (cfg);
67 }
68
69
70 FcConfig *
FcConfigCreate(void)71 FcConfigCreate (void)
72 {
73 FcSetName set;
74 FcConfig *config;
75
76 config = malloc (sizeof (FcConfig));
77 if (!config)
78 goto bail0;
79
80 config->configDirs = FcStrSetCreate ();
81 if (!config->configDirs)
82 goto bail1;
83
84 config->configFiles = FcStrSetCreate ();
85 if (!config->configFiles)
86 goto bail2;
87
88 config->fontDirs = FcStrSetCreate ();
89 if (!config->fontDirs)
90 goto bail3;
91
92 config->acceptGlobs = FcStrSetCreate ();
93 if (!config->acceptGlobs)
94 goto bail4;
95
96 config->rejectGlobs = FcStrSetCreate ();
97 if (!config->rejectGlobs)
98 goto bail5;
99
100 config->acceptPatterns = FcFontSetCreate ();
101 if (!config->acceptPatterns)
102 goto bail6;
103
104 config->rejectPatterns = FcFontSetCreate ();
105 if (!config->rejectPatterns)
106 goto bail7;
107
108 config->cacheDirs = FcStrSetCreate ();
109 if (!config->cacheDirs)
110 goto bail8;
111
112 config->blanks = 0;
113
114 config->substPattern = 0;
115 config->substFont = 0;
116 config->substScan = 0;
117 config->maxObjects = 0;
118 for (set = FcSetSystem; set <= FcSetApplication; set++)
119 config->fonts[set] = 0;
120
121 config->rescanTime = time(0);
122 config->rescanInterval = 30;
123
124 config->expr_pool = NULL;
125
126 config->sysRoot = NULL;
127
128 FcRefInit (&config->ref, 1);
129
130 return config;
131
132 bail8:
133 FcFontSetDestroy (config->rejectPatterns);
134 bail7:
135 FcFontSetDestroy (config->acceptPatterns);
136 bail6:
137 FcStrSetDestroy (config->rejectGlobs);
138 bail5:
139 FcStrSetDestroy (config->acceptGlobs);
140 bail4:
141 FcStrSetDestroy (config->fontDirs);
142 bail3:
143 FcStrSetDestroy (config->configFiles);
144 bail2:
145 FcStrSetDestroy (config->configDirs);
146 bail1:
147 free (config);
148 bail0:
149 return 0;
150 }
151
152 static FcFileTime
FcConfigNewestFile(FcStrSet * files)153 FcConfigNewestFile (FcStrSet *files)
154 {
155 FcStrList *list = FcStrListCreate (files);
156 FcFileTime newest = { 0, FcFalse };
157 FcChar8 *file;
158 struct stat statb;
159
160 if (list)
161 {
162 while ((file = FcStrListNext (list)))
163 if (FcStat (file, &statb) == 0)
164 if (!newest.set || statb.st_mtime - newest.time > 0)
165 {
166 newest.set = FcTrue;
167 newest.time = statb.st_mtime;
168 }
169 FcStrListDone (list);
170 }
171 return newest;
172 }
173
174 FcBool
FcConfigUptoDate(FcConfig * config)175 FcConfigUptoDate (FcConfig *config)
176 {
177 FcFileTime config_time, config_dir_time, font_time;
178 time_t now = time(0);
179 if (!config)
180 {
181 config = FcConfigGetCurrent ();
182 if (!config)
183 return FcFalse;
184 }
185 config_time = FcConfigNewestFile (config->configFiles);
186 config_dir_time = FcConfigNewestFile (config->configDirs);
187 font_time = FcConfigNewestFile (config->fontDirs);
188 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
189 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
190 (font_time.set && (font_time.time - config->rescanTime) > 0))
191 {
192 /* We need to check for potential clock problems here (OLPC ticket #6046) */
193 if ((config_time.set && (config_time.time - now) > 0) ||
194 (config_dir_time.set && (config_dir_time.time - now) > 0) ||
195 (font_time.set && (font_time.time - now) > 0))
196 {
197 fprintf (stderr,
198 "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
199 config->rescanTime = now;
200 return FcTrue;
201 }
202 else
203 return FcFalse;
204 }
205 config->rescanTime = now;
206 return FcTrue;
207 }
208
209 static void
FcSubstDestroy(FcSubst * s)210 FcSubstDestroy (FcSubst *s)
211 {
212 FcSubst *n;
213
214 while (s)
215 {
216 n = s->next;
217 if (s->rule)
218 FcRuleDestroy (s->rule);
219 free (s);
220 s = n;
221 }
222 }
223
224 FcExpr *
FcConfigAllocExpr(FcConfig * config)225 FcConfigAllocExpr (FcConfig *config)
226 {
227 if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
228 {
229 FcExprPage *new_page;
230
231 new_page = malloc (sizeof (FcExprPage));
232 if (!new_page)
233 return 0;
234
235 new_page->next_page = config->expr_pool;
236 new_page->next = new_page->exprs;
237 config->expr_pool = new_page;
238 }
239
240 return config->expr_pool->next++;
241 }
242
243 FcConfig *
FcConfigReference(FcConfig * config)244 FcConfigReference (FcConfig *config)
245 {
246 if (!config)
247 {
248 config = FcConfigGetCurrent ();
249 if (!config)
250 return 0;
251 }
252
253 FcRefInc (&config->ref);
254
255 return config;
256 }
257
258 void
FcConfigDestroy(FcConfig * config)259 FcConfigDestroy (FcConfig *config)
260 {
261 FcSetName set;
262 FcExprPage *page;
263
264 if (FcRefDec (&config->ref) != 1)
265 return;
266
267 (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
268
269 FcStrSetDestroy (config->configDirs);
270 FcStrSetDestroy (config->fontDirs);
271 FcStrSetDestroy (config->cacheDirs);
272 FcStrSetDestroy (config->configFiles);
273 FcStrSetDestroy (config->acceptGlobs);
274 FcStrSetDestroy (config->rejectGlobs);
275 FcFontSetDestroy (config->acceptPatterns);
276 FcFontSetDestroy (config->rejectPatterns);
277
278 if (config->blanks)
279 FcBlanksDestroy (config->blanks);
280
281 FcSubstDestroy (config->substPattern);
282 FcSubstDestroy (config->substFont);
283 FcSubstDestroy (config->substScan);
284 for (set = FcSetSystem; set <= FcSetApplication; set++)
285 if (config->fonts[set])
286 FcFontSetDestroy (config->fonts[set]);
287
288 page = config->expr_pool;
289 while (page)
290 {
291 FcExprPage *next = page->next_page;
292 free (page);
293 page = next;
294 }
295 if (config->sysRoot)
296 FcStrFree (config->sysRoot);
297
298 free (config);
299 }
300
301 /*
302 * Add cache to configuration, adding fonts and directories
303 */
304
305 FcBool
FcConfigAddCache(FcConfig * config,FcCache * cache,FcSetName set,FcStrSet * dirSet)306 FcConfigAddCache (FcConfig *config, FcCache *cache,
307 FcSetName set, FcStrSet *dirSet)
308 {
309 FcFontSet *fs;
310 intptr_t *dirs;
311 int i;
312
313 /*
314 * Add fonts
315 */
316 fs = FcCacheSet (cache);
317 if (fs)
318 {
319 int nref = 0;
320
321 for (i = 0; i < fs->nfont; i++)
322 {
323 FcPattern *font = FcFontSetFont (fs, i);
324 FcChar8 *font_file;
325
326 /*
327 * Check to see if font is banned by filename
328 */
329 if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
330 0, &font_file) == FcResultMatch &&
331 !FcConfigAcceptFilename (config, font_file))
332 {
333 continue;
334 }
335
336 /*
337 * Check to see if font is banned by pattern
338 */
339 if (!FcConfigAcceptFont (config, font))
340 continue;
341
342 if (FcFontSetAdd (config->fonts[set], font))
343 nref++;
344 }
345 FcDirCacheReference (cache, nref);
346 }
347
348 /*
349 * Add directories
350 */
351 dirs = FcCacheDirs (cache);
352 if (dirs)
353 {
354 for (i = 0; i < cache->dirs_count; i++)
355 {
356 FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
357 if (FcConfigAcceptFilename (config, dir))
358 FcStrSetAddFilename (dirSet, dir);
359 }
360 }
361 return FcTrue;
362 }
363
364 static FcBool
FcConfigAddDirList(FcConfig * config,FcSetName set,FcStrSet * dirSet)365 FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
366 {
367 FcStrList *dirlist;
368 FcChar8 *dir;
369 FcCache *cache;
370
371 dirlist = FcStrListCreate (dirSet);
372 if (!dirlist)
373 return FcFalse;
374
375 while ((dir = FcStrListNext (dirlist)))
376 {
377 if (FcDebug () & FC_DBG_FONTSET)
378 printf ("adding fonts from%s\n", dir);
379 cache = FcDirCacheRead (dir, FcFalse, config);
380 if (!cache)
381 continue;
382 FcConfigAddCache (config, cache, set, dirSet);
383 FcDirCacheUnload (cache);
384 }
385 FcStrListDone (dirlist);
386 return FcTrue;
387 }
388
389 /*
390 * Scan the current list of directories in the configuration
391 * and build the set of available fonts.
392 */
393
394 FcBool
FcConfigBuildFonts(FcConfig * config)395 FcConfigBuildFonts (FcConfig *config)
396 {
397 FcFontSet *fonts;
398
399 if (!config)
400 {
401 config = FcConfigGetCurrent ();
402 if (!config)
403 return FcFalse;
404 }
405
406 fonts = FcFontSetCreate ();
407 if (!fonts)
408 return FcFalse;
409
410 FcConfigSetFonts (config, fonts, FcSetSystem);
411
412 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
413 return FcFalse;
414 if (FcDebug () & FC_DBG_FONTSET)
415 FcFontSetPrint (fonts);
416 return FcTrue;
417 }
418
419 FcBool
FcConfigSetCurrent(FcConfig * config)420 FcConfigSetCurrent (FcConfig *config)
421 {
422 FcConfig *cfg;
423
424 retry:
425 cfg = fc_atomic_ptr_get (&_fcConfig);
426
427 if (config == cfg)
428 return FcTrue;
429
430 if (config && !config->fonts[FcSetSystem])
431 if (!FcConfigBuildFonts (config))
432 return FcFalse;
433
434 if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
435 goto retry;
436
437 if (cfg)
438 FcConfigDestroy (cfg);
439
440 return FcTrue;
441 }
442
443 FcConfig *
FcConfigGetCurrent(void)444 FcConfigGetCurrent (void)
445 {
446 return FcConfigEnsure ();
447 }
448
449 FcBool
FcConfigAddConfigDir(FcConfig * config,const FcChar8 * d)450 FcConfigAddConfigDir (FcConfig *config,
451 const FcChar8 *d)
452 {
453 return FcStrSetAddFilename (config->configDirs, d);
454 }
455
456 FcStrList *
FcConfigGetConfigDirs(FcConfig * config)457 FcConfigGetConfigDirs (FcConfig *config)
458 {
459 if (!config)
460 {
461 config = FcConfigGetCurrent ();
462 if (!config)
463 return 0;
464 }
465 return FcStrListCreate (config->configDirs);
466 }
467
468 FcBool
FcConfigAddFontDir(FcConfig * config,const FcChar8 * d)469 FcConfigAddFontDir (FcConfig *config,
470 const FcChar8 *d)
471 {
472 return FcStrSetAddFilename (config->fontDirs, d);
473 }
474
475 FcBool
FcConfigAddDir(FcConfig * config,const FcChar8 * d)476 FcConfigAddDir (FcConfig *config,
477 const FcChar8 *d)
478 {
479 return (FcConfigAddConfigDir (config, d) &&
480 FcConfigAddFontDir (config, d));
481 }
482
483 FcStrList *
FcConfigGetFontDirs(FcConfig * config)484 FcConfigGetFontDirs (FcConfig *config)
485 {
486 if (!config)
487 {
488 config = FcConfigGetCurrent ();
489 if (!config)
490 return 0;
491 }
492 return FcStrListCreate (config->fontDirs);
493 }
494
495 FcBool
FcConfigAddCacheDir(FcConfig * config,const FcChar8 * d)496 FcConfigAddCacheDir (FcConfig *config,
497 const FcChar8 *d)
498 {
499 return FcStrSetAddFilename (config->cacheDirs, d);
500 }
501
502 FcStrList *
FcConfigGetCacheDirs(const FcConfig * config)503 FcConfigGetCacheDirs (const FcConfig *config)
504 {
505 if (!config)
506 {
507 config = FcConfigGetCurrent ();
508 if (!config)
509 return 0;
510 }
511 return FcStrListCreate (config->cacheDirs);
512 }
513
514 FcBool
FcConfigAddConfigFile(FcConfig * config,const FcChar8 * f)515 FcConfigAddConfigFile (FcConfig *config,
516 const FcChar8 *f)
517 {
518 FcBool ret;
519 FcChar8 *file = FcConfigFilename (f);
520
521 if (!file)
522 return FcFalse;
523
524 ret = FcStrSetAdd (config->configFiles, file);
525 FcStrFree (file);
526 return ret;
527 }
528
529 FcStrList *
FcConfigGetConfigFiles(FcConfig * config)530 FcConfigGetConfigFiles (FcConfig *config)
531 {
532 if (!config)
533 {
534 config = FcConfigGetCurrent ();
535 if (!config)
536 return 0;
537 }
538 return FcStrListCreate (config->configFiles);
539 }
540
541 FcChar8 *
FcConfigGetCache(FcConfig * config FC_UNUSED)542 FcConfigGetCache (FcConfig *config FC_UNUSED)
543 {
544 return NULL;
545 }
546
547 FcFontSet *
FcConfigGetFonts(FcConfig * config,FcSetName set)548 FcConfigGetFonts (FcConfig *config,
549 FcSetName set)
550 {
551 if (!config)
552 {
553 config = FcConfigGetCurrent ();
554 if (!config)
555 return 0;
556 }
557 return config->fonts[set];
558 }
559
560 void
FcConfigSetFonts(FcConfig * config,FcFontSet * fonts,FcSetName set)561 FcConfigSetFonts (FcConfig *config,
562 FcFontSet *fonts,
563 FcSetName set)
564 {
565 if (config->fonts[set])
566 FcFontSetDestroy (config->fonts[set]);
567 config->fonts[set] = fonts;
568 }
569
570 FcBlanks *
FcConfigGetBlanks(FcConfig * config)571 FcConfigGetBlanks (FcConfig *config)
572 {
573 if (!config)
574 {
575 config = FcConfigGetCurrent ();
576 if (!config)
577 return 0;
578 }
579 return config->blanks;
580 }
581
582 FcBool
FcConfigAddBlank(FcConfig * config,FcChar32 blank)583 FcConfigAddBlank (FcConfig *config,
584 FcChar32 blank)
585 {
586 FcBlanks *b, *freeme = 0;
587
588 b = config->blanks;
589 if (!b)
590 {
591 freeme = b = FcBlanksCreate ();
592 if (!b)
593 return FcFalse;
594 }
595 if (!FcBlanksAdd (b, blank))
596 {
597 if (freeme)
598 FcBlanksDestroy (freeme);
599 return FcFalse;
600 }
601 config->blanks = b;
602 return FcTrue;
603 }
604
605 int
FcConfigGetRescanInterval(FcConfig * config)606 FcConfigGetRescanInterval (FcConfig *config)
607 {
608 if (!config)
609 {
610 config = FcConfigGetCurrent ();
611 if (!config)
612 return 0;
613 }
614 return config->rescanInterval;
615 }
616
617 FcBool
FcConfigSetRescanInterval(FcConfig * config,int rescanInterval)618 FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
619 {
620 if (!config)
621 {
622 config = FcConfigGetCurrent ();
623 if (!config)
624 return FcFalse;
625 }
626 config->rescanInterval = rescanInterval;
627 return FcTrue;
628 }
629
630 /*
631 * A couple of typos escaped into the library
632 */
633 int
FcConfigGetRescanInverval(FcConfig * config)634 FcConfigGetRescanInverval (FcConfig *config)
635 {
636 return FcConfigGetRescanInterval (config);
637 }
638
639 FcBool
FcConfigSetRescanInverval(FcConfig * config,int rescanInterval)640 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
641 {
642 return FcConfigSetRescanInterval (config, rescanInterval);
643 }
644
645 FcBool
FcConfigAddRule(FcConfig * config,FcRule * rule,FcMatchKind kind)646 FcConfigAddRule (FcConfig *config,
647 FcRule *rule,
648 FcMatchKind kind)
649 {
650 FcSubst *subst, **prev;
651 FcRule *r;
652 int n = 0;
653
654 if (!rule)
655 return FcFalse;
656 switch (kind) {
657 case FcMatchPattern:
658 prev = &config->substPattern;
659 break;
660 case FcMatchFont:
661 prev = &config->substFont;
662 break;
663 case FcMatchScan:
664 prev = &config->substScan;
665 break;
666 default:
667 return FcFalse;
668 }
669 subst = (FcSubst *) malloc (sizeof (FcSubst));
670 if (!subst)
671 return FcFalse;
672 for (; *prev; prev = &(*prev)->next);
673 *prev = subst;
674 subst->next = NULL;
675 subst->rule = rule;
676 for (r = rule; r; r = r->next)
677 {
678 switch (r->type)
679 {
680 case FcRuleTest:
681 if (r->u.test &&
682 r->u.test->kind == FcMatchDefault)
683 r->u.test->kind = kind;
684
685 if (n < r->u.test->object)
686 n = r->u.test->object;
687 break;
688 case FcRuleEdit:
689 if (n < r->u.edit->object)
690 n = r->u.edit->object;
691 break;
692 default:
693 break;
694 }
695 }
696 n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
697 if (config->maxObjects < n)
698 config->maxObjects = n;
699 if (FcDebug () & FC_DBG_EDIT)
700 {
701 printf ("Add Subst ");
702 FcSubstPrint (subst);
703 }
704 return FcTrue;
705 }
706
707 static FcValue
FcConfigPromote(FcValue v,FcValue u,FcValuePromotionBuffer * buf)708 FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
709 {
710 if (v.type == FcTypeInteger)
711 {
712 v.type = FcTypeDouble;
713 v.u.d = (double) v.u.i;
714 }
715 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
716 {
717 v.u.m = &FcIdentityMatrix;
718 v.type = FcTypeMatrix;
719 }
720 else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
721 {
722 v.u.l = FcLangSetPromote (v.u.s, buf);
723 v.type = FcTypeLangSet;
724 }
725 return v;
726 }
727
728 FcBool
FcConfigCompareValue(const FcValue * left_o,unsigned int op_,const FcValue * right_o)729 FcConfigCompareValue (const FcValue *left_o,
730 unsigned int op_,
731 const FcValue *right_o)
732 {
733 FcValue left = FcValueCanonicalize(left_o);
734 FcValue right = FcValueCanonicalize(right_o);
735 FcBool ret = FcFalse;
736 FcOp op = FC_OP_GET_OP (op_);
737 int flags = FC_OP_GET_FLAGS (op_);
738 FcValuePromotionBuffer buf1, buf2;
739
740 left = FcConfigPromote (left, right, &buf1);
741 right = FcConfigPromote (right, left, &buf2);
742 if (left.type == right.type)
743 {
744 switch (left.type) {
745 case FcTypeUnknown:
746 break; /* No way to guess how to compare for this object */
747 case FcTypeInteger:
748 break; /* FcConfigPromote prevents this from happening */
749 case FcTypeDouble:
750 switch ((int) op) {
751 case FcOpEqual:
752 case FcOpContains:
753 case FcOpListing:
754 ret = left.u.d == right.u.d;
755 break;
756 case FcOpNotEqual:
757 case FcOpNotContains:
758 ret = left.u.d != right.u.d;
759 break;
760 case FcOpLess:
761 ret = left.u.d < right.u.d;
762 break;
763 case FcOpLessEqual:
764 ret = left.u.d <= right.u.d;
765 break;
766 case FcOpMore:
767 ret = left.u.d > right.u.d;
768 break;
769 case FcOpMoreEqual:
770 ret = left.u.d >= right.u.d;
771 break;
772 default:
773 break;
774 }
775 break;
776 case FcTypeBool:
777 switch ((int) op) {
778 case FcOpEqual:
779 case FcOpContains:
780 case FcOpListing:
781 ret = left.u.b == right.u.b;
782 break;
783 case FcOpNotEqual:
784 case FcOpNotContains:
785 ret = left.u.b != right.u.b;
786 break;
787 default:
788 break;
789 }
790 break;
791 case FcTypeString:
792 switch ((int) op) {
793 case FcOpEqual:
794 case FcOpListing:
795 if (flags & FcOpFlagIgnoreBlanks)
796 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
797 else
798 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
799 break;
800 case FcOpContains:
801 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
802 break;
803 case FcOpNotEqual:
804 if (flags & FcOpFlagIgnoreBlanks)
805 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
806 else
807 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
808 break;
809 case FcOpNotContains:
810 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
811 break;
812 default:
813 break;
814 }
815 break;
816 case FcTypeMatrix:
817 switch ((int) op) {
818 case FcOpEqual:
819 case FcOpContains:
820 case FcOpListing:
821 ret = FcMatrixEqual (left.u.m, right.u.m);
822 break;
823 case FcOpNotEqual:
824 case FcOpNotContains:
825 ret = !FcMatrixEqual (left.u.m, right.u.m);
826 break;
827 default:
828 break;
829 }
830 break;
831 case FcTypeCharSet:
832 switch ((int) op) {
833 case FcOpContains:
834 case FcOpListing:
835 /* left contains right if right is a subset of left */
836 ret = FcCharSetIsSubset (right.u.c, left.u.c);
837 break;
838 case FcOpNotContains:
839 /* left contains right if right is a subset of left */
840 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
841 break;
842 case FcOpEqual:
843 ret = FcCharSetEqual (left.u.c, right.u.c);
844 break;
845 case FcOpNotEqual:
846 ret = !FcCharSetEqual (left.u.c, right.u.c);
847 break;
848 default:
849 break;
850 }
851 break;
852 case FcTypeLangSet:
853 switch ((int) op) {
854 case FcOpContains:
855 case FcOpListing:
856 ret = FcLangSetContains (left.u.l, right.u.l);
857 break;
858 case FcOpNotContains:
859 ret = !FcLangSetContains (left.u.l, right.u.l);
860 break;
861 case FcOpEqual:
862 ret = FcLangSetEqual (left.u.l, right.u.l);
863 break;
864 case FcOpNotEqual:
865 ret = !FcLangSetEqual (left.u.l, right.u.l);
866 break;
867 default:
868 break;
869 }
870 break;
871 case FcTypeVoid:
872 switch ((int) op) {
873 case FcOpEqual:
874 case FcOpContains:
875 case FcOpListing:
876 ret = FcTrue;
877 break;
878 default:
879 break;
880 }
881 break;
882 case FcTypeFTFace:
883 switch ((int) op) {
884 case FcOpEqual:
885 case FcOpContains:
886 case FcOpListing:
887 ret = left.u.f == right.u.f;
888 break;
889 case FcOpNotEqual:
890 case FcOpNotContains:
891 ret = left.u.f != right.u.f;
892 break;
893 default:
894 break;
895 }
896 break;
897 }
898 }
899 else
900 {
901 if (op == FcOpNotEqual || op == FcOpNotContains)
902 ret = FcTrue;
903 }
904 return ret;
905 }
906
907
908 #define _FcDoubleFloor(d) ((int) (d))
909 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
910 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
911 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
912 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
913 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
914
915 static FcValue
FcConfigEvaluate(FcPattern * p,FcPattern * p_pat,FcMatchKind kind,FcExpr * e)916 FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
917 {
918 FcValue v, vl, vr;
919 FcMatrix *m;
920 FcChar8 *str;
921 FcOp op = FC_OP_GET_OP (e->op);
922
923 switch ((int) op) {
924 case FcOpInteger:
925 v.type = FcTypeInteger;
926 v.u.i = e->u.ival;
927 break;
928 case FcOpDouble:
929 v.type = FcTypeDouble;
930 v.u.d = e->u.dval;
931 break;
932 case FcOpString:
933 v.type = FcTypeString;
934 v.u.s = e->u.sval;
935 v = FcValueSave (v);
936 break;
937 case FcOpMatrix:
938 {
939 FcMatrix m;
940 FcValue xx, xy, yx, yy;
941 v.type = FcTypeMatrix;
942 xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
943 xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
944 yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
945 yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
946 if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
947 yx.type == FcTypeDouble && yy.type == FcTypeDouble)
948 {
949 m.xx = xx.u.d;
950 m.xy = xy.u.d;
951 m.yx = yx.u.d;
952 m.yy = yy.u.d;
953 v.u.m = &m;
954 }
955 else
956 v.type = FcTypeVoid;
957 v = FcValueSave (v);
958 }
959 break;
960 case FcOpCharSet:
961 v.type = FcTypeCharSet;
962 v.u.c = e->u.cval;
963 v = FcValueSave (v);
964 break;
965 case FcOpLangSet:
966 v.type = FcTypeLangSet;
967 v.u.l = e->u.lval;
968 v = FcValueSave (v);
969 break;
970 case FcOpBool:
971 v.type = FcTypeBool;
972 v.u.b = e->u.bval;
973 break;
974 case FcOpField:
975 if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
976 {
977 if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
978 v.type = FcTypeVoid;
979 }
980 else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
981 {
982 fprintf (stderr,
983 "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
984 v.type = FcTypeVoid;
985 }
986 else
987 {
988 if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
989 v.type = FcTypeVoid;
990 }
991 v = FcValueSave (v);
992 break;
993 case FcOpConst:
994 if (FcNameConstant (e->u.constant, &v.u.i))
995 v.type = FcTypeInteger;
996 else
997 v.type = FcTypeVoid;
998 break;
999 case FcOpQuest:
1000 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1001 if (vl.type == FcTypeBool)
1002 {
1003 if (vl.u.b)
1004 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
1005 else
1006 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
1007 }
1008 else
1009 v.type = FcTypeVoid;
1010 FcValueDestroy (vl);
1011 break;
1012 case FcOpEqual:
1013 case FcOpNotEqual:
1014 case FcOpLess:
1015 case FcOpLessEqual:
1016 case FcOpMore:
1017 case FcOpMoreEqual:
1018 case FcOpContains:
1019 case FcOpNotContains:
1020 case FcOpListing:
1021 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1022 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1023 v.type = FcTypeBool;
1024 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
1025 FcValueDestroy (vl);
1026 FcValueDestroy (vr);
1027 break;
1028 case FcOpOr:
1029 case FcOpAnd:
1030 case FcOpPlus:
1031 case FcOpMinus:
1032 case FcOpTimes:
1033 case FcOpDivide:
1034 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1035 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1036 vl = FcConfigPromote (vl, vr, NULL);
1037 vr = FcConfigPromote (vr, vl, NULL);
1038 if (vl.type == vr.type)
1039 {
1040 switch ((int) vl.type) {
1041 case FcTypeDouble:
1042 switch ((int) op) {
1043 case FcOpPlus:
1044 v.type = FcTypeDouble;
1045 v.u.d = vl.u.d + vr.u.d;
1046 break;
1047 case FcOpMinus:
1048 v.type = FcTypeDouble;
1049 v.u.d = vl.u.d - vr.u.d;
1050 break;
1051 case FcOpTimes:
1052 v.type = FcTypeDouble;
1053 v.u.d = vl.u.d * vr.u.d;
1054 break;
1055 case FcOpDivide:
1056 v.type = FcTypeDouble;
1057 v.u.d = vl.u.d / vr.u.d;
1058 break;
1059 default:
1060 v.type = FcTypeVoid;
1061 break;
1062 }
1063 if (v.type == FcTypeDouble &&
1064 v.u.d == (double) (int) v.u.d)
1065 {
1066 v.type = FcTypeInteger;
1067 v.u.i = (int) v.u.d;
1068 }
1069 break;
1070 case FcTypeBool:
1071 switch ((int) op) {
1072 case FcOpOr:
1073 v.type = FcTypeBool;
1074 v.u.b = vl.u.b || vr.u.b;
1075 break;
1076 case FcOpAnd:
1077 v.type = FcTypeBool;
1078 v.u.b = vl.u.b && vr.u.b;
1079 break;
1080 default:
1081 v.type = FcTypeVoid;
1082 break;
1083 }
1084 break;
1085 case FcTypeString:
1086 switch ((int) op) {
1087 case FcOpPlus:
1088 v.type = FcTypeString;
1089 str = FcStrPlus (vl.u.s, vr.u.s);
1090 v.u.s = FcStrdup (str);
1091 FcStrFree (str);
1092
1093 if (!v.u.s)
1094 v.type = FcTypeVoid;
1095 break;
1096 default:
1097 v.type = FcTypeVoid;
1098 break;
1099 }
1100 break;
1101 case FcTypeMatrix:
1102 switch ((int) op) {
1103 case FcOpTimes:
1104 v.type = FcTypeMatrix;
1105 m = malloc (sizeof (FcMatrix));
1106 if (m)
1107 {
1108 FcMatrixMultiply (m, vl.u.m, vr.u.m);
1109 v.u.m = m;
1110 }
1111 else
1112 {
1113 v.type = FcTypeVoid;
1114 }
1115 break;
1116 default:
1117 v.type = FcTypeVoid;
1118 break;
1119 }
1120 break;
1121 case FcTypeCharSet:
1122 switch ((int) op) {
1123 case FcOpPlus:
1124 v.type = FcTypeCharSet;
1125 v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
1126 if (!v.u.c)
1127 v.type = FcTypeVoid;
1128 break;
1129 case FcOpMinus:
1130 v.type = FcTypeCharSet;
1131 v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
1132 if (!v.u.c)
1133 v.type = FcTypeVoid;
1134 break;
1135 default:
1136 v.type = FcTypeVoid;
1137 break;
1138 }
1139 break;
1140 case FcTypeLangSet:
1141 switch ((int) op) {
1142 case FcOpPlus:
1143 v.type = FcTypeLangSet;
1144 v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
1145 if (!v.u.l)
1146 v.type = FcTypeVoid;
1147 break;
1148 case FcOpMinus:
1149 v.type = FcTypeLangSet;
1150 v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
1151 if (!v.u.l)
1152 v.type = FcTypeVoid;
1153 break;
1154 default:
1155 v.type = FcTypeVoid;
1156 break;
1157 }
1158 break;
1159 default:
1160 v.type = FcTypeVoid;
1161 break;
1162 }
1163 }
1164 else
1165 v.type = FcTypeVoid;
1166 FcValueDestroy (vl);
1167 FcValueDestroy (vr);
1168 break;
1169 case FcOpNot:
1170 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1171 switch ((int) vl.type) {
1172 case FcTypeBool:
1173 v.type = FcTypeBool;
1174 v.u.b = !vl.u.b;
1175 break;
1176 default:
1177 v.type = FcTypeVoid;
1178 break;
1179 }
1180 FcValueDestroy (vl);
1181 break;
1182 case FcOpFloor:
1183 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1184 switch ((int) vl.type) {
1185 case FcTypeInteger:
1186 v = vl;
1187 break;
1188 case FcTypeDouble:
1189 v.type = FcTypeInteger;
1190 v.u.i = FcDoubleFloor (vl.u.d);
1191 break;
1192 default:
1193 v.type = FcTypeVoid;
1194 break;
1195 }
1196 FcValueDestroy (vl);
1197 break;
1198 case FcOpCeil:
1199 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1200 switch ((int) vl.type) {
1201 case FcTypeInteger:
1202 v = vl;
1203 break;
1204 case FcTypeDouble:
1205 v.type = FcTypeInteger;
1206 v.u.i = FcDoubleCeil (vl.u.d);
1207 break;
1208 default:
1209 v.type = FcTypeVoid;
1210 break;
1211 }
1212 FcValueDestroy (vl);
1213 break;
1214 case FcOpRound:
1215 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1216 switch ((int) vl.type) {
1217 case FcTypeInteger:
1218 v = vl;
1219 break;
1220 case FcTypeDouble:
1221 v.type = FcTypeInteger;
1222 v.u.i = FcDoubleRound (vl.u.d);
1223 break;
1224 default:
1225 v.type = FcTypeVoid;
1226 break;
1227 }
1228 FcValueDestroy (vl);
1229 break;
1230 case FcOpTrunc:
1231 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1232 switch ((int) vl.type) {
1233 case FcTypeInteger:
1234 v = vl;
1235 break;
1236 case FcTypeDouble:
1237 v.type = FcTypeInteger;
1238 v.u.i = FcDoubleTrunc (vl.u.d);
1239 break;
1240 default:
1241 v.type = FcTypeVoid;
1242 break;
1243 }
1244 FcValueDestroy (vl);
1245 break;
1246 default:
1247 v.type = FcTypeVoid;
1248 break;
1249 }
1250 return v;
1251 }
1252
1253 static FcValueList *
FcConfigMatchValueList(FcPattern * p,FcPattern * p_pat,FcMatchKind kind,FcTest * t,FcValueList * values)1254 FcConfigMatchValueList (FcPattern *p,
1255 FcPattern *p_pat,
1256 FcMatchKind kind,
1257 FcTest *t,
1258 FcValueList *values)
1259 {
1260 FcValueList *ret = 0;
1261 FcExpr *e = t->expr;
1262 FcValue value;
1263 FcValueList *v;
1264
1265 while (e)
1266 {
1267 /* Compute the value of the match expression */
1268 if (FC_OP_GET_OP (e->op) == FcOpComma)
1269 {
1270 value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1271 e = e->u.tree.right;
1272 }
1273 else
1274 {
1275 value = FcConfigEvaluate (p, p_pat, kind, e);
1276 e = 0;
1277 }
1278
1279 for (v = values; v; v = FcValueListNext(v))
1280 {
1281 /* Compare the pattern value to the match expression value */
1282 if (FcConfigCompareValue (&v->value, t->op, &value))
1283 {
1284 if (!ret)
1285 ret = v;
1286 }
1287 else
1288 {
1289 if (t->qual == FcQualAll)
1290 {
1291 ret = 0;
1292 break;
1293 }
1294 }
1295 }
1296 FcValueDestroy (value);
1297 }
1298 return ret;
1299 }
1300
1301 static FcValueList *
FcConfigValues(FcPattern * p,FcPattern * p_pat,FcMatchKind kind,FcExpr * e,FcValueBinding binding)1302 FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
1303 {
1304 FcValueList *l;
1305
1306 if (!e)
1307 return 0;
1308 l = (FcValueList *) malloc (sizeof (FcValueList));
1309 if (!l)
1310 return 0;
1311 if (FC_OP_GET_OP (e->op) == FcOpComma)
1312 {
1313 l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1314 l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
1315 }
1316 else
1317 {
1318 l->value = FcConfigEvaluate (p, p_pat, kind, e);
1319 l->next = NULL;
1320 }
1321 l->binding = binding;
1322 if (l->value.type == FcTypeVoid)
1323 {
1324 FcValueList *next = FcValueListNext(l);
1325
1326 free (l);
1327 l = next;
1328 }
1329
1330 return l;
1331 }
1332
1333 static FcBool
FcConfigAdd(FcValueListPtr * head,FcValueList * position,FcBool append,FcValueList * new,FcObject object)1334 FcConfigAdd (FcValueListPtr *head,
1335 FcValueList *position,
1336 FcBool append,
1337 FcValueList *new,
1338 FcObject object)
1339 {
1340 FcValueListPtr *prev, l, last, v;
1341 FcValueBinding sameBinding;
1342
1343 /*
1344 * Make sure the stored type is valid for built-in objects
1345 */
1346 for (l = new; l != NULL; l = FcValueListNext (l))
1347 {
1348 if (!FcObjectValidType (object, l->value.type))
1349 {
1350 fprintf (stderr,
1351 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1352 FcValuePrintFile (stderr, l->value);
1353 fprintf (stderr, "\n");
1354
1355 if (FcDebug () & FC_DBG_EDIT)
1356 {
1357 printf ("Not adding\n");
1358 }
1359
1360 return FcFalse;
1361 }
1362 }
1363
1364 if (position)
1365 sameBinding = position->binding;
1366 else
1367 sameBinding = FcValueBindingWeak;
1368 for (v = new; v != NULL; v = FcValueListNext(v))
1369 if (v->binding == FcValueBindingSame)
1370 v->binding = sameBinding;
1371 if (append)
1372 {
1373 if (position)
1374 prev = &position->next;
1375 else
1376 for (prev = head; *prev != NULL;
1377 prev = &(*prev)->next)
1378 ;
1379 }
1380 else
1381 {
1382 if (position)
1383 {
1384 for (prev = head; *prev != NULL;
1385 prev = &(*prev)->next)
1386 {
1387 if (*prev == position)
1388 break;
1389 }
1390 }
1391 else
1392 prev = head;
1393
1394 if (FcDebug () & FC_DBG_EDIT)
1395 {
1396 if (*prev == NULL)
1397 printf ("position not on list\n");
1398 }
1399 }
1400
1401 if (FcDebug () & FC_DBG_EDIT)
1402 {
1403 printf ("%s list before ", append ? "Append" : "Prepend");
1404 FcValueListPrintWithPosition (*head, *prev);
1405 printf ("\n");
1406 }
1407
1408 if (new)
1409 {
1410 last = new;
1411 while (last->next != NULL)
1412 last = last->next;
1413
1414 last->next = *prev;
1415 *prev = new;
1416 }
1417
1418 if (FcDebug () & FC_DBG_EDIT)
1419 {
1420 printf ("%s list after ", append ? "Append" : "Prepend");
1421 FcValueListPrint (*head);
1422 printf ("\n");
1423 }
1424
1425 return FcTrue;
1426 }
1427
1428 static void
FcConfigDel(FcValueListPtr * head,FcValueList * position)1429 FcConfigDel (FcValueListPtr *head,
1430 FcValueList *position)
1431 {
1432 FcValueListPtr *prev;
1433
1434 for (prev = head; *prev != NULL; prev = &(*prev)->next)
1435 {
1436 if (*prev == position)
1437 {
1438 *prev = position->next;
1439 position->next = NULL;
1440 FcValueListDestroy (position);
1441 break;
1442 }
1443 }
1444 }
1445
1446 static void
FcConfigPatternAdd(FcPattern * p,FcObject object,FcValueList * list,FcBool append)1447 FcConfigPatternAdd (FcPattern *p,
1448 FcObject object,
1449 FcValueList *list,
1450 FcBool append)
1451 {
1452 if (list)
1453 {
1454 FcPatternElt *e = FcPatternObjectInsertElt (p, object);
1455
1456 if (!e)
1457 return;
1458 FcConfigAdd (&e->values, 0, append, list, object);
1459 }
1460 }
1461
1462 /*
1463 * Delete all values associated with a field
1464 */
1465 static void
FcConfigPatternDel(FcPattern * p,FcObject object)1466 FcConfigPatternDel (FcPattern *p,
1467 FcObject object)
1468 {
1469 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1470 if (!e)
1471 return;
1472 while (e->values != NULL)
1473 FcConfigDel (&e->values, e->values);
1474 }
1475
1476 static void
FcConfigPatternCanon(FcPattern * p,FcObject object)1477 FcConfigPatternCanon (FcPattern *p,
1478 FcObject object)
1479 {
1480 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1481 if (!e)
1482 return;
1483 if (e->values == NULL)
1484 FcPatternObjectDel (p, object);
1485 }
1486
1487 FcBool
FcConfigSubstituteWithPat(FcConfig * config,FcPattern * p,FcPattern * p_pat,FcMatchKind kind)1488 FcConfigSubstituteWithPat (FcConfig *config,
1489 FcPattern *p,
1490 FcPattern *p_pat,
1491 FcMatchKind kind)
1492 {
1493 FcValue v;
1494 FcSubst *s;
1495 FcRule *r;
1496 FcValueList *l, **value = NULL, *vl;
1497 FcPattern *m;
1498 FcStrSet *strs;
1499 FcObject object = FC_INVALID_OBJECT;
1500 FcPatternElt **elt = NULL, *e;
1501 int i, nobjs;
1502 FcBool retval = FcTrue;
1503 FcTest **tst = NULL;
1504
1505 if (!config)
1506 {
1507 config = FcConfigGetCurrent ();
1508 if (!config)
1509 return FcFalse;
1510 }
1511
1512 switch (kind) {
1513 case FcMatchPattern:
1514 s = config->substPattern;
1515 strs = FcGetDefaultLangs ();
1516 if (strs)
1517 {
1518 FcStrList *l = FcStrListCreate (strs);
1519 FcChar8 *lang;
1520 FcValue v;
1521
1522 FcStrSetDestroy (strs);
1523 while (l && (lang = FcStrListNext (l)))
1524 {
1525 v.type = FcTypeString;
1526 v.u.s = lang;
1527 FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1528 }
1529 FcStrListDone (l);
1530 }
1531 if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1532 {
1533 FcChar8 *prgname = FcGetPrgname ();
1534 if (prgname)
1535 FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1536 }
1537 break;
1538 case FcMatchFont:
1539 s = config->substFont;
1540 break;
1541 case FcMatchScan:
1542 s = config->substScan;
1543 break;
1544 default:
1545 return FcFalse;
1546 }
1547
1548 nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
1549 value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
1550 if (!value)
1551 {
1552 retval = FcFalse;
1553 goto bail1;
1554 }
1555 elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
1556 if (!elt)
1557 {
1558 retval = FcFalse;
1559 goto bail1;
1560 }
1561 tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
1562 if (!tst)
1563 {
1564 retval = FcFalse;
1565 goto bail1;
1566 }
1567
1568 if (FcDebug () & FC_DBG_EDIT)
1569 {
1570 printf ("FcConfigSubstitute ");
1571 FcPatternPrint (p);
1572 }
1573 for (; s; s = s->next)
1574 {
1575 r = s->rule;
1576 for (i = 0; i < nobjs; i++)
1577 {
1578 elt[i] = NULL;
1579 value[i] = NULL;
1580 tst[i] = NULL;
1581 }
1582 for (; r; r = r->next)
1583 {
1584 switch (r->type) {
1585 case FcRuleUnknown:
1586 /* shouldn't be reached */
1587 break;
1588 case FcRuleTest:
1589 object = FC_OBJ_ID (r->u.test->object);
1590 /*
1591 * Check the tests to see if
1592 * they all match the pattern
1593 */
1594 if (FcDebug () & FC_DBG_EDIT)
1595 {
1596 printf ("FcConfigSubstitute test ");
1597 FcTestPrint (r->u.test);
1598 }
1599 if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
1600 m = p_pat;
1601 else
1602 m = p;
1603 if (m)
1604 e = FcPatternObjectFindElt (m, r->u.test->object);
1605 else
1606 e = NULL;
1607 /* different 'kind' won't be the target of edit */
1608 if (!elt[object] && kind == r->u.test->kind)
1609 {
1610 elt[object] = e;
1611 tst[object] = r->u.test;
1612 }
1613 /*
1614 * If there's no such field in the font,
1615 * then FcQualAll matches while FcQualAny does not
1616 */
1617 if (!e)
1618 {
1619 if (r->u.test->qual == FcQualAll)
1620 {
1621 value[object] = NULL;
1622 continue;
1623 }
1624 else
1625 {
1626 if (FcDebug () & FC_DBG_EDIT)
1627 printf ("No match\n");
1628 goto bail;
1629 }
1630 }
1631 /*
1632 * Check to see if there is a match, mark the location
1633 * to apply match-relative edits
1634 */
1635 vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
1636 /* different 'kind' won't be the target of edit */
1637 if (!value[object] && kind == r->u.test->kind)
1638 value[object] = vl;
1639 if (!vl ||
1640 (r->u.test->qual == FcQualFirst && vl != e->values) ||
1641 (r->u.test->qual == FcQualNotFirst && vl == e->values))
1642 {
1643 if (FcDebug () & FC_DBG_EDIT)
1644 printf ("No match\n");
1645 goto bail;
1646 }
1647 break;
1648 case FcRuleEdit:
1649 object = FC_OBJ_ID (r->u.edit->object);
1650 if (FcDebug () & FC_DBG_EDIT)
1651 {
1652 printf ("Substitute ");
1653 FcEditPrint (r->u.edit);
1654 printf ("\n\n");
1655 }
1656 /*
1657 * Evaluate the list of expressions
1658 */
1659 l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
1660 if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
1661 elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
1662
1663 switch (FC_OP_GET_OP (r->u.edit->op)) {
1664 case FcOpAssign:
1665 /*
1666 * If there was a test, then replace the matched
1667 * value with the new list of values
1668 */
1669 if (value[object])
1670 {
1671 FcValueList *thisValue = value[object];
1672 FcValueList *nextValue = l;
1673
1674 /*
1675 * Append the new list of values after the current value
1676 */
1677 FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
1678 /*
1679 * Delete the marked value
1680 */
1681 if (thisValue)
1682 FcConfigDel (&elt[object]->values, thisValue);
1683 /*
1684 * Adjust a pointer into the value list to ensure
1685 * future edits occur at the same place
1686 */
1687 value[object] = nextValue;
1688 break;
1689 }
1690 /* fall through ... */
1691 case FcOpAssignReplace:
1692 /*
1693 * Delete all of the values and insert
1694 * the new set
1695 */
1696 FcConfigPatternDel (p, r->u.edit->object);
1697 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1698 /*
1699 * Adjust a pointer into the value list as they no
1700 * longer point to anything valid
1701 */
1702 value[object] = NULL;
1703 break;
1704 case FcOpPrepend:
1705 if (value[object])
1706 {
1707 FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
1708 break;
1709 }
1710 /* fall through ... */
1711 case FcOpPrependFirst:
1712 FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
1713 break;
1714 case FcOpAppend:
1715 if (value[object])
1716 {
1717 FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
1718 break;
1719 }
1720 /* fall through ... */
1721 case FcOpAppendLast:
1722 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1723 break;
1724 case FcOpDelete:
1725 if (value[object])
1726 {
1727 FcConfigDel (&elt[object]->values, value[object]);
1728 break;
1729 }
1730 /* fall through ... */
1731 case FcOpDeleteAll:
1732 FcConfigPatternDel (p, r->u.edit->object);
1733 break;
1734 default:
1735 FcValueListDestroy (l);
1736 break;
1737 }
1738 /*
1739 * Now go through the pattern and eliminate
1740 * any properties without data
1741 */
1742 FcConfigPatternCanon (p, r->u.edit->object);
1743
1744 if (FcDebug () & FC_DBG_EDIT)
1745 {
1746 printf ("FcConfigSubstitute edit");
1747 FcPatternPrint (p);
1748 }
1749 break;
1750 }
1751 }
1752 bail:;
1753 }
1754 if (FcDebug () & FC_DBG_EDIT)
1755 {
1756 printf ("FcConfigSubstitute done");
1757 FcPatternPrint (p);
1758 }
1759 bail1:
1760 if (elt)
1761 free (elt);
1762 if (value)
1763 free (value);
1764 if (tst)
1765 free (tst);
1766
1767 return retval;
1768 }
1769
1770 FcBool
FcConfigSubstitute(FcConfig * config,FcPattern * p,FcMatchKind kind)1771 FcConfigSubstitute (FcConfig *config,
1772 FcPattern *p,
1773 FcMatchKind kind)
1774 {
1775 return FcConfigSubstituteWithPat (config, p, 0, kind);
1776 }
1777
1778 #if defined (_WIN32)
1779
1780 static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
1781
1782 # if (defined (PIC) || defined (DLL_EXPORT))
1783
1784 BOOL WINAPI
1785 DllMain (HINSTANCE hinstDLL,
1786 DWORD fdwReason,
1787 LPVOID lpvReserved);
1788
1789 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)1790 DllMain (HINSTANCE hinstDLL,
1791 DWORD fdwReason,
1792 LPVOID lpvReserved)
1793 {
1794 FcChar8 *p;
1795
1796 switch (fdwReason) {
1797 case DLL_PROCESS_ATTACH:
1798 if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
1799 sizeof (fontconfig_path)))
1800 break;
1801
1802 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1803 * assume it's a Unix-style installation tree, and use
1804 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1805 * folder where the DLL is as FONTCONFIG_PATH.
1806 */
1807 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1808 if (p)
1809 {
1810 *p = '\0';
1811 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1812 if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1813 FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
1814 *p = '\0';
1815 strcat ((char *) fontconfig_path, "\\etc\\fonts");
1816 }
1817 else
1818 fontconfig_path[0] = '\0';
1819
1820 break;
1821 }
1822
1823 return TRUE;
1824 }
1825
1826 # endif /* !PIC */
1827
1828 #undef FONTCONFIG_PATH
1829 #define FONTCONFIG_PATH fontconfig_path
1830
1831 #endif /* !_WIN32 */
1832
1833 #ifndef FONTCONFIG_FILE
1834 #define FONTCONFIG_FILE "fonts.conf"
1835 #endif
1836
1837 static FcChar8 *
FcConfigFileExists(const FcChar8 * dir,const FcChar8 * file)1838 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1839 {
1840 FcChar8 *path;
1841 int size, osize;
1842
1843 if (!dir)
1844 dir = (FcChar8 *) "";
1845
1846 osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1847 /*
1848 * workaround valgrind warning because glibc takes advantage of how it knows memory is
1849 * allocated to implement strlen by reading in groups of 4
1850 */
1851 size = (osize + 3) & ~3;
1852
1853 path = malloc (size);
1854 if (!path)
1855 return 0;
1856
1857 strcpy ((char *) path, (const char *) dir);
1858 /* make sure there's a single separator */
1859 #ifdef _WIN32
1860 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1861 path[strlen((char *) path)-1] != '\\')) &&
1862 !(file[0] == '/' ||
1863 file[0] == '\\' ||
1864 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1865 strcat ((char *) path, "\\");
1866 #else
1867 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1868 strcat ((char *) path, "/");
1869 else
1870 osize--;
1871 #endif
1872 strcat ((char *) path, (char *) file);
1873
1874 if (access ((char *) path, R_OK) == 0)
1875 return path;
1876
1877 FcStrFree (path);
1878
1879 return 0;
1880 }
1881
1882 static FcChar8 **
FcConfigGetPath(void)1883 FcConfigGetPath (void)
1884 {
1885 FcChar8 **path;
1886 FcChar8 *env, *e, *colon;
1887 FcChar8 *dir;
1888 int npath;
1889 int i;
1890
1891 npath = 2; /* default dir + null */
1892 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1893 if (env)
1894 {
1895 e = env;
1896 npath++;
1897 while (*e)
1898 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1899 npath++;
1900 }
1901 path = calloc (npath, sizeof (FcChar8 *));
1902 if (!path)
1903 goto bail0;
1904 i = 0;
1905
1906 if (env)
1907 {
1908 e = env;
1909 while (*e)
1910 {
1911 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1912 if (!colon)
1913 colon = e + strlen ((char *) e);
1914 path[i] = malloc (colon - e + 1);
1915 if (!path[i])
1916 goto bail1;
1917 strncpy ((char *) path[i], (const char *) e, colon - e);
1918 path[i][colon - e] = '\0';
1919 if (*colon)
1920 e = colon + 1;
1921 else
1922 e = colon;
1923 i++;
1924 }
1925 }
1926
1927 #ifdef _WIN32
1928 if (fontconfig_path[0] == '\0')
1929 {
1930 char *p;
1931 if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
1932 goto bail1;
1933 p = strrchr ((const char *) fontconfig_path, '\\');
1934 if (p) *p = '\0';
1935 strcat ((char *) fontconfig_path, "\\fonts");
1936 }
1937 #endif
1938 dir = (FcChar8 *) FONTCONFIG_PATH;
1939 path[i] = malloc (strlen ((char *) dir) + 1);
1940 if (!path[i])
1941 goto bail1;
1942 strcpy ((char *) path[i], (const char *) dir);
1943 return path;
1944
1945 bail1:
1946 for (i = 0; path[i]; i++)
1947 free (path[i]);
1948 free (path);
1949 bail0:
1950 return 0;
1951 }
1952
1953 static void
FcConfigFreePath(FcChar8 ** path)1954 FcConfigFreePath (FcChar8 **path)
1955 {
1956 FcChar8 **p;
1957
1958 for (p = path; *p; p++)
1959 free (*p);
1960 free (path);
1961 }
1962
1963 static FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
1964
1965 FcChar8 *
FcConfigHome(void)1966 FcConfigHome (void)
1967 {
1968 if (_FcConfigHomeEnabled)
1969 {
1970 char *home = getenv ("HOME");
1971
1972 #ifdef _WIN32
1973 if (home == NULL)
1974 home = getenv ("USERPROFILE");
1975 #endif
1976
1977 return (FcChar8 *) home;
1978 }
1979 return 0;
1980 }
1981
1982 FcChar8 *
FcConfigXdgCacheHome(void)1983 FcConfigXdgCacheHome (void)
1984 {
1985 const char *env = getenv ("XDG_CACHE_HOME");
1986 FcChar8 *ret = NULL;
1987
1988 if (env)
1989 ret = FcStrCopy ((const FcChar8 *)env);
1990 else
1991 {
1992 const FcChar8 *home = FcConfigHome ();
1993 size_t len = home ? strlen ((const char *)home) : 0;
1994
1995 ret = malloc (len + 7 + 1);
1996 if (ret)
1997 {
1998 memcpy (ret, home, len);
1999 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
2000 ret[len + 7] = 0;
2001 }
2002 }
2003
2004 return ret;
2005 }
2006
2007 FcChar8 *
FcConfigXdgConfigHome(void)2008 FcConfigXdgConfigHome (void)
2009 {
2010 const char *env = getenv ("XDG_CONFIG_HOME");
2011 FcChar8 *ret = NULL;
2012
2013 if (env)
2014 ret = FcStrCopy ((const FcChar8 *)env);
2015 else
2016 {
2017 const FcChar8 *home = FcConfigHome ();
2018 size_t len = home ? strlen ((const char *)home) : 0;
2019
2020 ret = malloc (len + 8 + 1);
2021 if (ret)
2022 {
2023 memcpy (ret, home, len);
2024 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2025 ret[len + 8] = 0;
2026 }
2027 }
2028
2029 return ret;
2030 }
2031
2032 FcChar8 *
FcConfigXdgDataHome(void)2033 FcConfigXdgDataHome (void)
2034 {
2035 const char *env = getenv ("XDG_DATA_HOME");
2036 FcChar8 *ret = NULL;
2037
2038 if (env)
2039 ret = FcStrCopy ((const FcChar8 *)env);
2040 else
2041 {
2042 const FcChar8 *home = FcConfigHome ();
2043 size_t len = home ? strlen ((const char *)home) : 0;
2044
2045 ret = malloc (len + 13 + 1);
2046 if (ret)
2047 {
2048 memcpy (ret, home, len);
2049 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2050 ret[len + 13] = 0;
2051 }
2052 }
2053
2054 return ret;
2055 }
2056
2057 FcBool
FcConfigEnableHome(FcBool enable)2058 FcConfigEnableHome (FcBool enable)
2059 {
2060 FcBool prev = _FcConfigHomeEnabled;
2061 _FcConfigHomeEnabled = enable;
2062 return prev;
2063 }
2064
2065 FcChar8 *
FcConfigFilename(const FcChar8 * url)2066 FcConfigFilename (const FcChar8 *url)
2067 {
2068 FcChar8 *file, *dir, **path, **p;
2069
2070 if (!url || !*url)
2071 {
2072 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
2073 if (!url)
2074 url = (FcChar8 *) FONTCONFIG_FILE;
2075 }
2076 file = 0;
2077
2078 #ifdef _WIN32
2079 if (isalpha (*url) &&
2080 url[1] == ':' &&
2081 (url[2] == '/' || url[2] == '\\'))
2082 goto absolute_path;
2083 #endif
2084
2085 switch (*url) {
2086 case '~':
2087 dir = FcConfigHome ();
2088 if (dir)
2089 file = FcConfigFileExists (dir, url + 1);
2090 else
2091 file = 0;
2092 break;
2093 #ifdef _WIN32
2094 case '\\':
2095 absolute_path:
2096 #endif
2097 case '/':
2098 file = FcConfigFileExists (0, url);
2099 break;
2100 default:
2101 path = FcConfigGetPath ();
2102 if (!path)
2103 return NULL;
2104 for (p = path; *p; p++)
2105 {
2106 file = FcConfigFileExists (*p, url);
2107 if (file)
2108 break;
2109 }
2110 FcConfigFreePath (path);
2111 break;
2112 }
2113
2114 return file;
2115 }
2116
2117 /*
2118 * Manage the application-specific fonts
2119 */
2120
2121 FcBool
FcConfigAppFontAddFile(FcConfig * config,const FcChar8 * file)2122 FcConfigAppFontAddFile (FcConfig *config,
2123 const FcChar8 *file)
2124 {
2125 FcFontSet *set;
2126 FcStrSet *subdirs;
2127 FcStrList *sublist;
2128 FcChar8 *subdir;
2129
2130 if (!config)
2131 {
2132 config = FcConfigGetCurrent ();
2133 if (!config)
2134 return FcFalse;
2135 }
2136
2137 subdirs = FcStrSetCreate ();
2138 if (!subdirs)
2139 return FcFalse;
2140
2141 set = FcConfigGetFonts (config, FcSetApplication);
2142 if (!set)
2143 {
2144 set = FcFontSetCreate ();
2145 if (!set)
2146 {
2147 FcStrSetDestroy (subdirs);
2148 return FcFalse;
2149 }
2150 FcConfigSetFonts (config, set, FcSetApplication);
2151 }
2152
2153 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
2154 {
2155 FcStrSetDestroy (subdirs);
2156 return FcFalse;
2157 }
2158 if ((sublist = FcStrListCreate (subdirs)))
2159 {
2160 while ((subdir = FcStrListNext (sublist)))
2161 {
2162 FcConfigAppFontAddDir (config, subdir);
2163 }
2164 FcStrListDone (sublist);
2165 }
2166 FcStrSetDestroy (subdirs);
2167 return FcTrue;
2168 }
2169
2170 FcBool
FcConfigAppFontAddDir(FcConfig * config,const FcChar8 * dir)2171 FcConfigAppFontAddDir (FcConfig *config,
2172 const FcChar8 *dir)
2173 {
2174 FcFontSet *set;
2175 FcStrSet *dirs;
2176
2177 if (!config)
2178 {
2179 config = FcConfigGetCurrent ();
2180 if (!config)
2181 return FcFalse;
2182 }
2183
2184 dirs = FcStrSetCreate ();
2185 if (!dirs)
2186 return FcFalse;
2187
2188 set = FcConfigGetFonts (config, FcSetApplication);
2189 if (!set)
2190 {
2191 set = FcFontSetCreate ();
2192 if (!set)
2193 {
2194 FcStrSetDestroy (dirs);
2195 return FcFalse;
2196 }
2197 FcConfigSetFonts (config, set, FcSetApplication);
2198 }
2199
2200 FcStrSetAddFilename (dirs, dir);
2201
2202 if (!FcConfigAddDirList (config, FcSetApplication, dirs))
2203 {
2204 FcStrSetDestroy (dirs);
2205 return FcFalse;
2206 }
2207 FcStrSetDestroy (dirs);
2208 return FcTrue;
2209 }
2210
2211 void
FcConfigAppFontClear(FcConfig * config)2212 FcConfigAppFontClear (FcConfig *config)
2213 {
2214 if (!config)
2215 {
2216 config = FcConfigGetCurrent ();
2217 if (!config)
2218 return;
2219 }
2220
2221 FcConfigSetFonts (config, 0, FcSetApplication);
2222 }
2223
2224 /*
2225 * Manage filename-based font source selectors
2226 */
2227
2228 FcBool
FcConfigGlobAdd(FcConfig * config,const FcChar8 * glob,FcBool accept)2229 FcConfigGlobAdd (FcConfig *config,
2230 const FcChar8 *glob,
2231 FcBool accept)
2232 {
2233 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
2234
2235 return FcStrSetAdd (set, glob);
2236 }
2237
2238 static FcBool
FcConfigGlobsMatch(const FcStrSet * globs,const FcChar8 * string)2239 FcConfigGlobsMatch (const FcStrSet *globs,
2240 const FcChar8 *string)
2241 {
2242 int i;
2243
2244 for (i = 0; i < globs->num; i++)
2245 if (FcStrGlobMatch (globs->strs[i], string))
2246 return FcTrue;
2247 return FcFalse;
2248 }
2249
2250 FcBool
FcConfigAcceptFilename(FcConfig * config,const FcChar8 * filename)2251 FcConfigAcceptFilename (FcConfig *config,
2252 const FcChar8 *filename)
2253 {
2254 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2255 return FcTrue;
2256 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2257 return FcFalse;
2258 return FcTrue;
2259 }
2260
2261 /*
2262 * Manage font-pattern based font source selectors
2263 */
2264
2265 FcBool
FcConfigPatternsAdd(FcConfig * config,FcPattern * pattern,FcBool accept)2266 FcConfigPatternsAdd (FcConfig *config,
2267 FcPattern *pattern,
2268 FcBool accept)
2269 {
2270 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
2271
2272 return FcFontSetAdd (set, pattern);
2273 }
2274
2275 static FcBool
FcConfigPatternsMatch(const FcFontSet * patterns,const FcPattern * font)2276 FcConfigPatternsMatch (const FcFontSet *patterns,
2277 const FcPattern *font)
2278 {
2279 int i;
2280
2281 for (i = 0; i < patterns->nfont; i++)
2282 if (FcListPatternMatchAny (patterns->fonts[i], font))
2283 return FcTrue;
2284 return FcFalse;
2285 }
2286
2287 FcBool
FcConfigAcceptFont(FcConfig * config,const FcPattern * font)2288 FcConfigAcceptFont (FcConfig *config,
2289 const FcPattern *font)
2290 {
2291 if (FcConfigPatternsMatch (config->acceptPatterns, font))
2292 return FcTrue;
2293 if (FcConfigPatternsMatch (config->rejectPatterns, font))
2294 return FcFalse;
2295 return FcTrue;
2296 }
2297
2298 const FcChar8 *
FcConfigGetSysRoot(const FcConfig * config)2299 FcConfigGetSysRoot (const FcConfig *config)
2300 {
2301 if (!config)
2302 {
2303 config = FcConfigGetCurrent ();
2304 if (!config)
2305 return NULL;
2306 }
2307
2308 return config->sysRoot;
2309 }
2310
2311 void
FcConfigSetSysRoot(FcConfig * config,const FcChar8 * sysroot)2312 FcConfigSetSysRoot (FcConfig *config,
2313 const FcChar8 *sysroot)
2314 {
2315 FcChar8 *s;
2316 FcBool init = FcFalse;
2317
2318 if (!config)
2319 {
2320 /* We can't use FcConfigGetCurrent() here to ensure
2321 * the sysroot is set prior to initialize FcConfig,
2322 * to avoid loading caches from non-sysroot dirs.
2323 * So postpone the initialization later.
2324 */
2325 config = fc_atomic_ptr_get (&_fcConfig);
2326 if (!config)
2327 {
2328 config = FcConfigCreate ();
2329 if (!config)
2330 return;
2331 init = FcTrue;
2332 }
2333 }
2334
2335 s = FcStrCopyFilename (sysroot);
2336 if (!s)
2337 return;
2338
2339 if (config->sysRoot)
2340 FcStrFree (config->sysRoot);
2341
2342 config->sysRoot = s;
2343 if (init)
2344 {
2345 config = FcInitLoadOwnConfigAndFonts (config);
2346 FcConfigSetCurrent (config);
2347 }
2348 }
2349
2350 #define __fccfg__
2351 #include "fcaliastail.h"
2352 #undef __fccfg__
2353