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