fccfg.c revision 18bd4a06
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
36static FcConfig    *_fcConfig; /* MT-safe */
37
38static FcConfig *
39FcConfigEnsure (void)
40{
41    FcConfig	*config;
42retry:
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
56FcBool
57FcConfigInit (void)
58{
59  return FcConfigEnsure () ? FcTrue : FcFalse;
60}
61
62void
63FcConfigFini (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
71FcConfig *
72FcConfigCreate (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
133bail8:
134    FcFontSetDestroy (config->rejectPatterns);
135bail7:
136    FcFontSetDestroy (config->acceptPatterns);
137bail6:
138    FcStrSetDestroy (config->rejectGlobs);
139bail5:
140    FcStrSetDestroy (config->acceptGlobs);
141bail4:
142    FcStrSetDestroy (config->fontDirs);
143bail3:
144    FcStrSetDestroy (config->configFiles);
145bail2:
146    FcStrSetDestroy (config->configDirs);
147bail1:
148    free (config);
149bail0:
150    return 0;
151}
152
153static FcFileTime
154FcConfigNewestFile (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
175FcBool
176FcConfigUptoDate (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
210static void
211FcSubstDestroy (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
225FcExpr *
226FcConfigAllocExpr (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
244FcConfig *
245FcConfigReference (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
259void
260FcConfigDestroy (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
306FcBool
307FcConfigAddCache (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
365static FcBool
366FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
367{
368    FcStrList	    *dirlist;
369    FcChar8	    *dir;
370    FcCache	    *cache;
371
372    dirlist = FcStrListCreate (dirSet);
373    if (!dirlist)
374        return FcFalse;
375
376    while ((dir = FcStrListNext (dirlist)))
377    {
378	if (FcDebug () & FC_DBG_FONTSET)
379	    printf ("adding fonts from %s\n", dir);
380	cache = FcDirCacheRead (dir, FcFalse, config);
381	if (!cache)
382	    continue;
383	FcConfigAddCache (config, cache, set, dirSet);
384	FcDirCacheUnload (cache);
385    }
386    FcStrListDone (dirlist);
387    return FcTrue;
388}
389
390/*
391 * Scan the current list of directories in the configuration
392 * and build the set of available fonts.
393 */
394
395FcBool
396FcConfigBuildFonts (FcConfig *config)
397{
398    FcFontSet	    *fonts;
399
400    if (!config)
401    {
402	config = FcConfigGetCurrent ();
403	if (!config)
404	    return FcFalse;
405    }
406
407    fonts = FcFontSetCreate ();
408    if (!fonts)
409	return FcFalse;
410
411    FcConfigSetFonts (config, fonts, FcSetSystem);
412
413    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
414	return FcFalse;
415    if (FcDebug () & FC_DBG_FONTSET)
416	FcFontSetPrint (fonts);
417    return FcTrue;
418}
419
420FcBool
421FcConfigSetCurrent (FcConfig *config)
422{
423    FcConfig *cfg;
424
425retry:
426    cfg = fc_atomic_ptr_get (&_fcConfig);
427
428    if (config == cfg)
429	return FcTrue;
430
431    if (config && !config->fonts[FcSetSystem])
432	if (!FcConfigBuildFonts (config))
433	    return FcFalse;
434
435    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
436	goto retry;
437
438    FcConfigReference (config);
439    if (cfg)
440	FcConfigDestroy (cfg);
441
442    return FcTrue;
443}
444
445FcConfig *
446FcConfigGetCurrent (void)
447{
448    return FcConfigEnsure ();
449}
450
451FcBool
452FcConfigAddConfigDir (FcConfig	    *config,
453		      const FcChar8 *d)
454{
455    return FcStrSetAddFilename (config->configDirs, d);
456}
457
458FcStrList *
459FcConfigGetConfigDirs (FcConfig   *config)
460{
461    if (!config)
462    {
463	config = FcConfigGetCurrent ();
464	if (!config)
465	    return 0;
466    }
467    return FcStrListCreate (config->configDirs);
468}
469
470FcBool
471FcConfigAddFontDir (FcConfig	    *config,
472		    const FcChar8   *d)
473{
474    return FcStrSetAddFilename (config->fontDirs, d);
475}
476
477FcBool
478FcConfigAddDir (FcConfig	    *config,
479		const FcChar8	    *d)
480{
481    return (FcConfigAddConfigDir (config, d) &&
482	    FcConfigAddFontDir (config, d));
483}
484
485FcStrList *
486FcConfigGetFontDirs (FcConfig	*config)
487{
488    if (!config)
489    {
490	config = FcConfigGetCurrent ();
491	if (!config)
492	    return 0;
493    }
494    return FcStrListCreate (config->fontDirs);
495}
496
497FcBool
498FcConfigAddCacheDir (FcConfig	    *config,
499		     const FcChar8  *d)
500{
501    return FcStrSetAddFilename (config->cacheDirs, d);
502}
503
504FcStrList *
505FcConfigGetCacheDirs (const FcConfig *config)
506{
507    if (!config)
508    {
509	config = FcConfigGetCurrent ();
510	if (!config)
511	    return 0;
512    }
513    return FcStrListCreate (config->cacheDirs);
514}
515
516FcBool
517FcConfigAddConfigFile (FcConfig	    *config,
518		       const FcChar8   *f)
519{
520    FcBool	ret;
521    FcChar8	*file = FcConfigFilename (f);
522
523    if (!file)
524	return FcFalse;
525
526    ret = FcStrSetAdd (config->configFiles, file);
527    FcStrFree (file);
528    return ret;
529}
530
531FcStrList *
532FcConfigGetConfigFiles (FcConfig    *config)
533{
534    if (!config)
535    {
536	config = FcConfigGetCurrent ();
537	if (!config)
538	    return 0;
539    }
540    return FcStrListCreate (config->configFiles);
541}
542
543FcChar8 *
544FcConfigGetCache (FcConfig  *config FC_UNUSED)
545{
546    return NULL;
547}
548
549FcFontSet *
550FcConfigGetFonts (FcConfig	*config,
551		  FcSetName	set)
552{
553    if (!config)
554    {
555	config = FcConfigGetCurrent ();
556	if (!config)
557	    return 0;
558    }
559    return config->fonts[set];
560}
561
562void
563FcConfigSetFonts (FcConfig	*config,
564		  FcFontSet	*fonts,
565		  FcSetName	set)
566{
567    if (config->fonts[set])
568	FcFontSetDestroy (config->fonts[set]);
569    config->fonts[set] = fonts;
570}
571
572FcBlanks *
573FcConfigGetBlanks (FcConfig	*config)
574{
575    if (!config)
576    {
577	config = FcConfigGetCurrent ();
578	if (!config)
579	    return 0;
580    }
581    return config->blanks;
582}
583
584FcBool
585FcConfigAddBlank (FcConfig	*config,
586		  FcChar32    	blank)
587{
588    FcBlanks	*b, *freeme = 0;
589
590    b = config->blanks;
591    if (!b)
592    {
593	freeme = b = FcBlanksCreate ();
594	if (!b)
595	    return FcFalse;
596    }
597    if (!FcBlanksAdd (b, blank))
598    {
599        if (freeme)
600            FcBlanksDestroy (freeme);
601	return FcFalse;
602    }
603    config->blanks = b;
604    return FcTrue;
605}
606
607int
608FcConfigGetRescanInterval (FcConfig *config)
609{
610    if (!config)
611    {
612	config = FcConfigGetCurrent ();
613	if (!config)
614	    return 0;
615    }
616    return config->rescanInterval;
617}
618
619FcBool
620FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
621{
622    if (!config)
623    {
624	config = FcConfigGetCurrent ();
625	if (!config)
626	    return FcFalse;
627    }
628    config->rescanInterval = rescanInterval;
629    return FcTrue;
630}
631
632/*
633 * A couple of typos escaped into the library
634 */
635int
636FcConfigGetRescanInverval (FcConfig *config)
637{
638    return FcConfigGetRescanInterval (config);
639}
640
641FcBool
642FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
643{
644    return FcConfigSetRescanInterval (config, rescanInterval);
645}
646
647FcBool
648FcConfigAddRule (FcConfig	*config,
649		 FcRule		*rule,
650		 FcMatchKind	kind)
651{
652    FcSubst	*subst, **prev;
653    FcRule	*r;
654    int		n = 0;
655
656    if (!rule)
657	return FcFalse;
658    switch (kind) {
659    case FcMatchPattern:
660	prev = &config->substPattern;
661	break;
662    case FcMatchFont:
663	prev = &config->substFont;
664	break;
665    case FcMatchScan:
666	prev = &config->substScan;
667	break;
668    default:
669	return FcFalse;
670    }
671    subst = (FcSubst *) malloc (sizeof (FcSubst));
672    if (!subst)
673	return FcFalse;
674    for (; *prev; prev = &(*prev)->next);
675    *prev = subst;
676    subst->next = NULL;
677    subst->rule = rule;
678    for (r = rule; r; r = r->next)
679    {
680	switch (r->type)
681	{
682	case FcRuleTest:
683	    if (r->u.test &&
684		r->u.test->kind == FcMatchDefault)
685		r->u.test->kind = kind;
686
687	    if (n < r->u.test->object)
688		n = r->u.test->object;
689	    break;
690	case FcRuleEdit:
691	    if (n < r->u.edit->object)
692		n = r->u.edit->object;
693	    break;
694	default:
695	    break;
696	}
697    }
698    n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
699    if (config->maxObjects < n)
700	config->maxObjects = n;
701    if (FcDebug () & FC_DBG_EDIT)
702    {
703	printf ("Add Subst ");
704	FcSubstPrint (subst);
705    }
706    return FcTrue;
707}
708
709static FcValue
710FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
711{
712    if (v.type == FcTypeInteger)
713    {
714	v.type = FcTypeDouble;
715	v.u.d = (double) v.u.i;
716    }
717    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
718    {
719	v.u.m = &FcIdentityMatrix;
720	v.type = FcTypeMatrix;
721    }
722    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
723    {
724	v.u.l = FcLangSetPromote (v.u.s, buf);
725	v.type = FcTypeLangSet;
726    }
727    else if (v.type == FcTypeVoid && u.type == FcTypeLangSet)
728    {
729	v.u.l = FcLangSetPromote (NULL, buf);
730	v.type = FcTypeLangSet;
731    }
732    else if (v.type == FcTypeVoid && u.type == FcTypeCharSet)
733    {
734	v.u.c = FcCharSetPromote (buf);
735	v.type = FcTypeCharSet;
736    }
737    if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
738    {
739	v.u.r = FcRangePromote (v.u.d, buf);
740	v.type = FcTypeRange;
741    }
742    return v;
743}
744
745FcBool
746FcConfigCompareValue (const FcValue	*left_o,
747		      unsigned int      op_,
748		      const FcValue	*right_o)
749{
750    FcValue	left = FcValueCanonicalize(left_o);
751    FcValue	right = FcValueCanonicalize(right_o);
752    FcBool	ret = FcFalse;
753    FcOp	op = FC_OP_GET_OP (op_);
754    int		flags = FC_OP_GET_FLAGS (op_);
755    FcValuePromotionBuffer buf1, buf2;
756
757    left = FcConfigPromote (left, right, &buf1);
758    right = FcConfigPromote (right, left, &buf2);
759    if (left.type == right.type)
760    {
761	switch (left.type) {
762	case FcTypeUnknown:
763	    break;	/* No way to guess how to compare for this object */
764	case FcTypeInteger:
765	    break;	/* FcConfigPromote prevents this from happening */
766	case FcTypeDouble:
767	    switch ((int) op) {
768	    case FcOpEqual:
769	    case FcOpContains:
770	    case FcOpListing:
771		ret = left.u.d == right.u.d;
772		break;
773	    case FcOpNotEqual:
774	    case FcOpNotContains:
775		ret = left.u.d != right.u.d;
776		break;
777	    case FcOpLess:
778		ret = left.u.d < right.u.d;
779		break;
780	    case FcOpLessEqual:
781		ret = left.u.d <= right.u.d;
782		break;
783	    case FcOpMore:
784		ret = left.u.d > right.u.d;
785		break;
786	    case FcOpMoreEqual:
787		ret = left.u.d >= right.u.d;
788		break;
789	    default:
790		break;
791	    }
792	    break;
793	case FcTypeBool:
794	    switch ((int) op) {
795	    case FcOpEqual:
796	    case FcOpContains:
797	    case FcOpListing:
798		ret = left.u.b == right.u.b;
799		break;
800	    case FcOpNotEqual:
801	    case FcOpNotContains:
802		ret = left.u.b != right.u.b;
803		break;
804	    default:
805		break;
806	    }
807	    break;
808	case FcTypeString:
809	    switch ((int) op) {
810	    case FcOpEqual:
811	    case FcOpListing:
812		if (flags & FcOpFlagIgnoreBlanks)
813		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
814		else
815		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
816		break;
817	    case FcOpContains:
818		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
819		break;
820	    case FcOpNotEqual:
821		if (flags & FcOpFlagIgnoreBlanks)
822		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
823		else
824		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
825		break;
826	    case FcOpNotContains:
827		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
828		break;
829	    default:
830		break;
831	    }
832	    break;
833	case FcTypeMatrix:
834	    switch ((int) op) {
835	    case FcOpEqual:
836	    case FcOpContains:
837	    case FcOpListing:
838		ret = FcMatrixEqual (left.u.m, right.u.m);
839		break;
840	    case FcOpNotEqual:
841	    case FcOpNotContains:
842		ret = !FcMatrixEqual (left.u.m, right.u.m);
843		break;
844	    default:
845		break;
846	    }
847	    break;
848	case FcTypeCharSet:
849	    switch ((int) op) {
850	    case FcOpContains:
851	    case FcOpListing:
852		/* left contains right if right is a subset of left */
853		ret = FcCharSetIsSubset (right.u.c, left.u.c);
854		break;
855	    case FcOpNotContains:
856		/* left contains right if right is a subset of left */
857		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
858		break;
859	    case FcOpEqual:
860		ret = FcCharSetEqual (left.u.c, right.u.c);
861		break;
862	    case FcOpNotEqual:
863		ret = !FcCharSetEqual (left.u.c, right.u.c);
864		break;
865	    default:
866		break;
867	    }
868	    break;
869	case FcTypeLangSet:
870	    switch ((int) op) {
871	    case FcOpContains:
872	    case FcOpListing:
873		ret = FcLangSetContains (left.u.l, right.u.l);
874		break;
875	    case FcOpNotContains:
876		ret = !FcLangSetContains (left.u.l, right.u.l);
877		break;
878	    case FcOpEqual:
879		ret = FcLangSetEqual (left.u.l, right.u.l);
880		break;
881	    case FcOpNotEqual:
882		ret = !FcLangSetEqual (left.u.l, right.u.l);
883		break;
884	    default:
885		break;
886	    }
887	    break;
888	case FcTypeVoid:
889	    switch ((int) op) {
890	    case FcOpEqual:
891	    case FcOpContains:
892	    case FcOpListing:
893		ret = FcTrue;
894		break;
895	    default:
896		break;
897	    }
898	    break;
899	case FcTypeFTFace:
900	    switch ((int) op) {
901	    case FcOpEqual:
902	    case FcOpContains:
903	    case FcOpListing:
904		ret = left.u.f == right.u.f;
905		break;
906	    case FcOpNotEqual:
907	    case FcOpNotContains:
908		ret = left.u.f != right.u.f;
909		break;
910	    default:
911		break;
912	    }
913	    break;
914	case FcTypeRange:
915	    ret = FcRangeCompare (op, left.u.r, right.u.r);
916	    break;
917	}
918    }
919    else
920    {
921	if (op == FcOpNotEqual || op == FcOpNotContains)
922	    ret = FcTrue;
923    }
924    return ret;
925}
926
927
928#define _FcDoubleFloor(d)	((int) (d))
929#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
930#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
931#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
932#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
933#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
934
935static FcValue
936FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
937{
938    FcValue	v, vl, vr, vle, vre;
939    FcMatrix	*m;
940    FcChar8     *str;
941    FcOp	op = FC_OP_GET_OP (e->op);
942    FcValuePromotionBuffer buf1, buf2;
943
944    switch ((int) op) {
945    case FcOpInteger:
946	v.type = FcTypeInteger;
947	v.u.i = e->u.ival;
948	break;
949    case FcOpDouble:
950	v.type = FcTypeDouble;
951	v.u.d = e->u.dval;
952	break;
953    case FcOpString:
954	v.type = FcTypeString;
955	v.u.s = e->u.sval;
956	v = FcValueSave (v);
957	break;
958    case FcOpMatrix:
959	{
960	  FcMatrix m;
961	  FcValue xx, xy, yx, yy;
962	  v.type = FcTypeMatrix;
963	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
964	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
965	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
966	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
967	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
968	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
969	  {
970	    m.xx = xx.u.d;
971	    m.xy = xy.u.d;
972	    m.yx = yx.u.d;
973	    m.yy = yy.u.d;
974	    v.u.m = &m;
975	  }
976	  else
977	    v.type = FcTypeVoid;
978	  v = FcValueSave (v);
979	}
980	break;
981    case FcOpCharSet:
982	v.type = FcTypeCharSet;
983	v.u.c = e->u.cval;
984	v = FcValueSave (v);
985	break;
986    case FcOpLangSet:
987	v.type = FcTypeLangSet;
988	v.u.l = e->u.lval;
989	v = FcValueSave (v);
990	break;
991    case FcOpRange:
992	v.type = FcTypeRange;
993	v.u.r = e->u.rval;
994	v = FcValueSave (v);
995	break;
996    case FcOpBool:
997	v.type = FcTypeBool;
998	v.u.b = e->u.bval;
999	break;
1000    case FcOpField:
1001	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
1002	{
1003	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
1004		v.type = FcTypeVoid;
1005	}
1006	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
1007	{
1008	    fprintf (stderr,
1009                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
1010	    v.type = FcTypeVoid;
1011	}
1012	else
1013	{
1014	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
1015		v.type = FcTypeVoid;
1016	}
1017	v = FcValueSave (v);
1018	break;
1019    case FcOpConst:
1020	if (FcNameConstant (e->u.constant, &v.u.i))
1021	    v.type = FcTypeInteger;
1022	else
1023	    v.type = FcTypeVoid;
1024	break;
1025    case FcOpQuest:
1026	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1027	if (vl.type == FcTypeBool)
1028	{
1029	    if (vl.u.b)
1030		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
1031	    else
1032		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
1033	}
1034	else
1035	    v.type = FcTypeVoid;
1036	FcValueDestroy (vl);
1037	break;
1038    case FcOpEqual:
1039    case FcOpNotEqual:
1040    case FcOpLess:
1041    case FcOpLessEqual:
1042    case FcOpMore:
1043    case FcOpMoreEqual:
1044    case FcOpContains:
1045    case FcOpNotContains:
1046    case FcOpListing:
1047	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1048	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1049	v.type = FcTypeBool;
1050	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
1051	FcValueDestroy (vl);
1052	FcValueDestroy (vr);
1053	break;
1054    case FcOpOr:
1055    case FcOpAnd:
1056    case FcOpPlus:
1057    case FcOpMinus:
1058    case FcOpTimes:
1059    case FcOpDivide:
1060	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1061	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1062	vle = FcConfigPromote (vl, vr, &buf1);
1063	vre = FcConfigPromote (vr, vle, &buf2);
1064	if (vle.type == vre.type)
1065	{
1066	    switch ((int) vle.type) {
1067	    case FcTypeDouble:
1068		switch ((int) op) {
1069		case FcOpPlus:
1070		    v.type = FcTypeDouble;
1071		    v.u.d = vle.u.d + vre.u.d;
1072		    break;
1073		case FcOpMinus:
1074		    v.type = FcTypeDouble;
1075		    v.u.d = vle.u.d - vre.u.d;
1076		    break;
1077		case FcOpTimes:
1078		    v.type = FcTypeDouble;
1079		    v.u.d = vle.u.d * vre.u.d;
1080		    break;
1081		case FcOpDivide:
1082		    v.type = FcTypeDouble;
1083		    v.u.d = vle.u.d / vre.u.d;
1084		    break;
1085		default:
1086		    v.type = FcTypeVoid;
1087		    break;
1088		}
1089		if (v.type == FcTypeDouble &&
1090		    v.u.d == (double) (int) v.u.d)
1091		{
1092		    v.type = FcTypeInteger;
1093		    v.u.i = (int) v.u.d;
1094		}
1095		break;
1096	    case FcTypeBool:
1097		switch ((int) op) {
1098		case FcOpOr:
1099		    v.type = FcTypeBool;
1100		    v.u.b = vle.u.b || vre.u.b;
1101		    break;
1102		case FcOpAnd:
1103		    v.type = FcTypeBool;
1104		    v.u.b = vle.u.b && vre.u.b;
1105		    break;
1106		default:
1107		    v.type = FcTypeVoid;
1108		    break;
1109		}
1110		break;
1111	    case FcTypeString:
1112		switch ((int) op) {
1113		case FcOpPlus:
1114		    v.type = FcTypeString;
1115		    str = FcStrPlus (vle.u.s, vre.u.s);
1116		    v.u.s = FcStrdup (str);
1117		    FcStrFree (str);
1118
1119		    if (!v.u.s)
1120			v.type = FcTypeVoid;
1121		    break;
1122		default:
1123		    v.type = FcTypeVoid;
1124		    break;
1125		}
1126		break;
1127	    case FcTypeMatrix:
1128		switch ((int) op) {
1129		case FcOpTimes:
1130		    v.type = FcTypeMatrix;
1131		    m = malloc (sizeof (FcMatrix));
1132		    if (m)
1133		    {
1134			FcMatrixMultiply (m, vle.u.m, vre.u.m);
1135			v.u.m = m;
1136		    }
1137		    else
1138		    {
1139			v.type = FcTypeVoid;
1140		    }
1141		    break;
1142		default:
1143		    v.type = FcTypeVoid;
1144		    break;
1145		}
1146		break;
1147	    case FcTypeCharSet:
1148		switch ((int) op) {
1149		case FcOpPlus:
1150		    v.type = FcTypeCharSet;
1151		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1152		    if (!v.u.c)
1153			v.type = FcTypeVoid;
1154		    break;
1155		case FcOpMinus:
1156		    v.type = FcTypeCharSet;
1157		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1158		    if (!v.u.c)
1159			v.type = FcTypeVoid;
1160		    break;
1161		default:
1162		    v.type = FcTypeVoid;
1163		    break;
1164		}
1165		break;
1166	    case FcTypeLangSet:
1167		switch ((int) op) {
1168		case FcOpPlus:
1169		    v.type = FcTypeLangSet;
1170		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1171		    if (!v.u.l)
1172			v.type = FcTypeVoid;
1173		    break;
1174		case FcOpMinus:
1175		    v.type = FcTypeLangSet;
1176		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1177		    if (!v.u.l)
1178			v.type = FcTypeVoid;
1179		    break;
1180		default:
1181		    v.type = FcTypeVoid;
1182		    break;
1183		}
1184		break;
1185	    default:
1186		v.type = FcTypeVoid;
1187		break;
1188	    }
1189	}
1190	else
1191	    v.type = FcTypeVoid;
1192	FcValueDestroy (vl);
1193	FcValueDestroy (vr);
1194	break;
1195    case FcOpNot:
1196	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1197	switch ((int) vl.type) {
1198	case FcTypeBool:
1199	    v.type = FcTypeBool;
1200	    v.u.b = !vl.u.b;
1201	    break;
1202	default:
1203	    v.type = FcTypeVoid;
1204	    break;
1205	}
1206	FcValueDestroy (vl);
1207	break;
1208    case FcOpFloor:
1209	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1210	switch ((int) vl.type) {
1211	case FcTypeInteger:
1212	    v = vl;
1213	    break;
1214	case FcTypeDouble:
1215	    v.type = FcTypeInteger;
1216	    v.u.i = FcDoubleFloor (vl.u.d);
1217	    break;
1218	default:
1219	    v.type = FcTypeVoid;
1220	    break;
1221	}
1222	FcValueDestroy (vl);
1223	break;
1224    case FcOpCeil:
1225	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1226	switch ((int) vl.type) {
1227	case FcTypeInteger:
1228	    v = vl;
1229	    break;
1230	case FcTypeDouble:
1231	    v.type = FcTypeInteger;
1232	    v.u.i = FcDoubleCeil (vl.u.d);
1233	    break;
1234	default:
1235	    v.type = FcTypeVoid;
1236	    break;
1237	}
1238	FcValueDestroy (vl);
1239	break;
1240    case FcOpRound:
1241	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1242	switch ((int) vl.type) {
1243	case FcTypeInteger:
1244	    v = vl;
1245	    break;
1246	case FcTypeDouble:
1247	    v.type = FcTypeInteger;
1248	    v.u.i = FcDoubleRound (vl.u.d);
1249	    break;
1250	default:
1251	    v.type = FcTypeVoid;
1252	    break;
1253	}
1254	FcValueDestroy (vl);
1255	break;
1256    case FcOpTrunc:
1257	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1258	switch ((int) vl.type) {
1259	case FcTypeInteger:
1260	    v = vl;
1261	    break;
1262	case FcTypeDouble:
1263	    v.type = FcTypeInteger;
1264	    v.u.i = FcDoubleTrunc (vl.u.d);
1265	    break;
1266	default:
1267	    v.type = FcTypeVoid;
1268	    break;
1269	}
1270	FcValueDestroy (vl);
1271	break;
1272    default:
1273	v.type = FcTypeVoid;
1274	break;
1275    }
1276    return v;
1277}
1278
1279static FcValueList *
1280FcConfigMatchValueList (FcPattern	*p,
1281			FcPattern	*p_pat,
1282			FcMatchKind      kind,
1283			FcTest		*t,
1284			FcValueList	*values)
1285{
1286    FcValueList	    *ret = 0;
1287    FcExpr	    *e = t->expr;
1288    FcValue	    value;
1289    FcValueList	    *v;
1290
1291    while (e)
1292    {
1293	/* Compute the value of the match expression */
1294	if (FC_OP_GET_OP (e->op) == FcOpComma)
1295	{
1296	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1297	    e = e->u.tree.right;
1298	}
1299	else
1300	{
1301	    value = FcConfigEvaluate (p, p_pat, kind, e);
1302	    e = 0;
1303	}
1304
1305	for (v = values; v; v = FcValueListNext(v))
1306	{
1307	    /* Compare the pattern value to the match expression value */
1308	    if (FcConfigCompareValue (&v->value, t->op, &value))
1309	    {
1310		if (!ret)
1311		    ret = v;
1312	    }
1313	    else
1314	    {
1315		if (t->qual == FcQualAll)
1316		{
1317		    ret = 0;
1318		    break;
1319		}
1320	    }
1321	}
1322	FcValueDestroy (value);
1323    }
1324    return ret;
1325}
1326
1327static FcValueList *
1328FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
1329{
1330    FcValueList	*l;
1331
1332    if (!e)
1333	return 0;
1334    l = (FcValueList *) malloc (sizeof (FcValueList));
1335    if (!l)
1336	return 0;
1337    if (FC_OP_GET_OP (e->op) == FcOpComma)
1338    {
1339	l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1340	l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
1341    }
1342    else
1343    {
1344	l->value = FcConfigEvaluate (p, p_pat, kind, e);
1345	l->next = NULL;
1346    }
1347    l->binding = binding;
1348    if (l->value.type == FcTypeVoid)
1349    {
1350	FcValueList  *next = FcValueListNext(l);
1351
1352	free (l);
1353	l = next;
1354    }
1355
1356    return l;
1357}
1358
1359static FcBool
1360FcConfigAdd (FcValueListPtr *head,
1361	     FcValueList    *position,
1362	     FcBool	    append,
1363	     FcValueList    *new,
1364	     FcObject        object)
1365{
1366    FcValueListPtr  *prev, l, last, v;
1367    FcValueBinding  sameBinding;
1368
1369    /*
1370     * Make sure the stored type is valid for built-in objects
1371     */
1372    for (l = new; l != NULL; l = FcValueListNext (l))
1373    {
1374	if (!FcObjectValidType (object, l->value.type))
1375	{
1376	    fprintf (stderr,
1377		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1378	    FcValuePrintFile (stderr, l->value);
1379	    fprintf (stderr, "\n");
1380
1381	    if (FcDebug () & FC_DBG_EDIT)
1382	    {
1383		printf ("Not adding\n");
1384	    }
1385
1386	    return FcFalse;
1387	}
1388    }
1389
1390    if (position)
1391	sameBinding = position->binding;
1392    else
1393	sameBinding = FcValueBindingWeak;
1394    for (v = new; v != NULL; v = FcValueListNext(v))
1395	if (v->binding == FcValueBindingSame)
1396	    v->binding = sameBinding;
1397    if (append)
1398    {
1399	if (position)
1400	    prev = &position->next;
1401	else
1402	    for (prev = head; *prev != NULL;
1403		 prev = &(*prev)->next)
1404		;
1405    }
1406    else
1407    {
1408	if (position)
1409	{
1410	    for (prev = head; *prev != NULL;
1411		 prev = &(*prev)->next)
1412	    {
1413		if (*prev == position)
1414		    break;
1415	    }
1416	}
1417	else
1418	    prev = head;
1419
1420	if (FcDebug () & FC_DBG_EDIT)
1421	{
1422	    if (*prev == NULL)
1423		printf ("position not on list\n");
1424	}
1425    }
1426
1427    if (FcDebug () & FC_DBG_EDIT)
1428    {
1429	printf ("%s list before ", append ? "Append" : "Prepend");
1430	FcValueListPrintWithPosition (*head, *prev);
1431	printf ("\n");
1432    }
1433
1434    if (new)
1435    {
1436	last = new;
1437	while (last->next != NULL)
1438	    last = last->next;
1439
1440	last->next = *prev;
1441	*prev = new;
1442    }
1443
1444    if (FcDebug () & FC_DBG_EDIT)
1445    {
1446	printf ("%s list after ", append ? "Append" : "Prepend");
1447	FcValueListPrint (*head);
1448	printf ("\n");
1449    }
1450
1451    return FcTrue;
1452}
1453
1454static void
1455FcConfigDel (FcValueListPtr *head,
1456	     FcValueList    *position)
1457{
1458    FcValueListPtr *prev;
1459
1460    for (prev = head; *prev != NULL; prev = &(*prev)->next)
1461    {
1462	if (*prev == position)
1463	{
1464	    *prev = position->next;
1465	    position->next = NULL;
1466	    FcValueListDestroy (position);
1467	    break;
1468	}
1469    }
1470}
1471
1472static void
1473FcConfigPatternAdd (FcPattern	*p,
1474		    FcObject	object,
1475		    FcValueList	*list,
1476		    FcBool	append)
1477{
1478    if (list)
1479    {
1480	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1481
1482	if (!e)
1483	    return;
1484	FcConfigAdd (&e->values, 0, append, list, object);
1485    }
1486}
1487
1488/*
1489 * Delete all values associated with a field
1490 */
1491static void
1492FcConfigPatternDel (FcPattern	*p,
1493		    FcObject	object)
1494{
1495    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1496    if (!e)
1497	return;
1498    while (e->values != NULL)
1499	FcConfigDel (&e->values, e->values);
1500}
1501
1502static void
1503FcConfigPatternCanon (FcPattern	    *p,
1504		      FcObject	    object)
1505{
1506    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1507    if (!e)
1508	return;
1509    if (e->values == NULL)
1510	FcPatternObjectDel (p, object);
1511}
1512
1513FcBool
1514FcConfigSubstituteWithPat (FcConfig    *config,
1515			   FcPattern   *p,
1516			   FcPattern   *p_pat,
1517			   FcMatchKind kind)
1518{
1519    FcValue v;
1520    FcSubst	    *s;
1521    FcRule          *r;
1522    FcValueList	    *l, **value = NULL, *vl;
1523    FcPattern	    *m;
1524    FcStrSet	    *strs;
1525    FcObject	    object = FC_INVALID_OBJECT;
1526    FcPatternElt    **elt = NULL, *e;
1527    int		    i, nobjs;
1528    FcBool	    retval = FcTrue;
1529    FcTest	    **tst = NULL;
1530
1531    if (!config)
1532    {
1533	config = FcConfigGetCurrent ();
1534	if (!config)
1535	    return FcFalse;
1536    }
1537
1538    switch (kind) {
1539    case FcMatchPattern:
1540	s = config->substPattern;
1541	strs = FcGetDefaultLangs ();
1542	if (strs)
1543	{
1544	    FcStrList *l = FcStrListCreate (strs);
1545	    FcChar8 *lang;
1546	    FcValue v;
1547	    FcLangSet *lsund = FcLangSetCreate ();
1548
1549	    FcLangSetAdd (lsund, (const FcChar8 *)"und");
1550	    FcStrSetDestroy (strs);
1551	    while (l && (lang = FcStrListNext (l)))
1552	    {
1553		FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
1554
1555		if (e)
1556		{
1557		    FcValueListPtr ll;
1558
1559		    for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
1560		    {
1561			FcValue vv = FcValueCanonicalize (&ll->value);
1562
1563			if (vv.type == FcTypeLangSet)
1564			{
1565			    FcLangSet *ls = FcLangSetCreate ();
1566			    FcBool b;
1567
1568			    FcLangSetAdd (ls, lang);
1569			    b = FcLangSetContains (vv.u.l, ls);
1570			    FcLangSetDestroy (ls);
1571			    if (b)
1572				goto bail_lang;
1573			    if (FcLangSetContains (vv.u.l, lsund))
1574				goto bail_lang;
1575			}
1576			else
1577			{
1578			    if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
1579				goto bail_lang;
1580			    if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
1581				goto bail_lang;
1582			}
1583		    }
1584		}
1585		v.type = FcTypeString;
1586		v.u.s = lang;
1587
1588		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1589	    }
1590	bail_lang:
1591	    FcStrListDone (l);
1592	    FcLangSetDestroy (lsund);
1593	}
1594	if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1595	{
1596	    FcChar8 *prgname = FcGetPrgname ();
1597	    if (prgname)
1598		FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1599	}
1600	break;
1601    case FcMatchFont:
1602	s = config->substFont;
1603	break;
1604    case FcMatchScan:
1605	s = config->substScan;
1606	break;
1607    default:
1608	return FcFalse;
1609    }
1610
1611    nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
1612    value = (FcValueList **) malloc (sizeof(void *) * nobjs);
1613    if (!value)
1614    {
1615	retval = FcFalse;
1616	goto bail1;
1617    }
1618    elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs);
1619    if (!elt)
1620    {
1621	retval = FcFalse;
1622	goto bail1;
1623    }
1624    tst = (FcTest **) malloc (sizeof(void *) * nobjs);
1625    if (!tst)
1626    {
1627	retval = FcFalse;
1628	goto bail1;
1629    }
1630
1631    if (FcDebug () & FC_DBG_EDIT)
1632    {
1633	printf ("FcConfigSubstitute ");
1634	FcPatternPrint (p);
1635    }
1636    for (; s; s = s->next)
1637    {
1638	r = s->rule;
1639	for (i = 0; i < nobjs; i++)
1640	{
1641	    elt[i] = NULL;
1642	    value[i] = NULL;
1643	    tst[i] = NULL;
1644	}
1645	for (; r; r = r->next)
1646	{
1647	    switch (r->type) {
1648	    case FcRuleUnknown:
1649		/* shouldn't be reached */
1650		break;
1651	    case FcRuleTest:
1652		object = FC_OBJ_ID (r->u.test->object);
1653		/*
1654		 * Check the tests to see if
1655		 * they all match the pattern
1656		 */
1657		if (FcDebug () & FC_DBG_EDIT)
1658		{
1659		    printf ("FcConfigSubstitute test ");
1660		    FcTestPrint (r->u.test);
1661		}
1662		if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
1663		    m = p_pat;
1664		else
1665		    m = p;
1666		if (m)
1667		    e = FcPatternObjectFindElt (m, r->u.test->object);
1668		else
1669		    e = NULL;
1670		/* different 'kind' won't be the target of edit */
1671		if (!elt[object] && kind == r->u.test->kind)
1672		{
1673		    elt[object] = e;
1674		    tst[object] = r->u.test;
1675		}
1676		/*
1677		 * If there's no such field in the font,
1678		 * then FcQualAll matches while FcQualAny does not
1679		 */
1680		if (!e)
1681		{
1682		    if (r->u.test->qual == FcQualAll)
1683		    {
1684			value[object] = NULL;
1685			continue;
1686		    }
1687		    else
1688		    {
1689			if (FcDebug () & FC_DBG_EDIT)
1690			    printf ("No match\n");
1691			goto bail;
1692		    }
1693		}
1694		/*
1695		 * Check to see if there is a match, mark the location
1696		 * to apply match-relative edits
1697		 */
1698		vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
1699		/* different 'kind' won't be the target of edit */
1700		if (!value[object] && kind == r->u.test->kind)
1701		    value[object] = vl;
1702		if (!vl ||
1703		    (r->u.test->qual == FcQualFirst && vl != e->values) ||
1704		    (r->u.test->qual == FcQualNotFirst && vl == e->values))
1705		{
1706		    if (FcDebug () & FC_DBG_EDIT)
1707			printf ("No match\n");
1708		    goto bail;
1709		}
1710		break;
1711	    case FcRuleEdit:
1712		object = FC_OBJ_ID (r->u.edit->object);
1713		if (FcDebug () & FC_DBG_EDIT)
1714		{
1715		    printf ("Substitute ");
1716		    FcEditPrint (r->u.edit);
1717		    printf ("\n\n");
1718		}
1719		/*
1720		 * Evaluate the list of expressions
1721		 */
1722		l = FcConfigValues (p, p_pat,kind,  r->u.edit->expr, r->u.edit->binding);
1723		if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
1724		    elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
1725
1726		switch (FC_OP_GET_OP (r->u.edit->op)) {
1727		case FcOpAssign:
1728		    /*
1729		     * If there was a test, then replace the matched
1730		     * value with the new list of values
1731		     */
1732		    if (value[object])
1733		    {
1734			FcValueList	*thisValue = value[object];
1735			FcValueList	*nextValue = l;
1736
1737			/*
1738			 * Append the new list of values after the current value
1739			 */
1740			FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
1741			/*
1742			 * Delete the marked value
1743			 */
1744			if (thisValue)
1745			    FcConfigDel (&elt[object]->values, thisValue);
1746			/*
1747			 * Adjust a pointer into the value list to ensure
1748			 * future edits occur at the same place
1749			 */
1750			value[object] = nextValue;
1751			break;
1752		    }
1753		    /* fall through ... */
1754		case FcOpAssignReplace:
1755		    /*
1756		     * Delete all of the values and insert
1757		     * the new set
1758		     */
1759		    FcConfigPatternDel (p, r->u.edit->object);
1760		    FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1761		    /*
1762		     * Adjust a pointer into the value list as they no
1763		     * longer point to anything valid
1764		     */
1765		    value[object] = NULL;
1766		    break;
1767		case FcOpPrepend:
1768		    if (value[object])
1769		    {
1770			FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
1771			break;
1772		    }
1773		    /* fall through ... */
1774		case FcOpPrependFirst:
1775		    FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
1776		    break;
1777		case FcOpAppend:
1778		    if (value[object])
1779		    {
1780			FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
1781			break;
1782		    }
1783		    /* fall through ... */
1784		case FcOpAppendLast:
1785		    FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
1786		    break;
1787		case FcOpDelete:
1788		    if (value[object])
1789		    {
1790			FcConfigDel (&elt[object]->values, value[object]);
1791			break;
1792		    }
1793		    /* fall through ... */
1794		case FcOpDeleteAll:
1795		    FcConfigPatternDel (p, r->u.edit->object);
1796		    break;
1797		default:
1798		    FcValueListDestroy (l);
1799		    break;
1800		}
1801		/*
1802		 * Now go through the pattern and eliminate
1803		 * any properties without data
1804		 */
1805		FcConfigPatternCanon (p, r->u.edit->object);
1806
1807		if (FcDebug () & FC_DBG_EDIT)
1808		{
1809		    printf ("FcConfigSubstitute edit");
1810		    FcPatternPrint (p);
1811		}
1812		break;
1813	    }
1814	}
1815    bail:;
1816    }
1817    if (FcDebug () & FC_DBG_EDIT)
1818    {
1819	printf ("FcConfigSubstitute done");
1820	FcPatternPrint (p);
1821    }
1822bail1:
1823    if (elt)
1824	free (elt);
1825    if (value)
1826	free (value);
1827    if (tst)
1828	free (tst);
1829
1830    return retval;
1831}
1832
1833FcBool
1834FcConfigSubstitute (FcConfig	*config,
1835		    FcPattern	*p,
1836		    FcMatchKind	kind)
1837{
1838    return FcConfigSubstituteWithPat (config, p, 0, kind);
1839}
1840
1841#if defined (_WIN32)
1842
1843static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
1844FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
1845
1846#  if (defined (PIC) || defined (DLL_EXPORT))
1847
1848BOOL WINAPI
1849DllMain (HINSTANCE hinstDLL,
1850	 DWORD     fdwReason,
1851	 LPVOID    lpvReserved);
1852
1853BOOL WINAPI
1854DllMain (HINSTANCE hinstDLL,
1855	 DWORD     fdwReason,
1856	 LPVOID    lpvReserved)
1857{
1858  FcChar8 *p;
1859
1860  switch (fdwReason) {
1861  case DLL_PROCESS_ATTACH:
1862      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
1863			      sizeof (fontconfig_path)))
1864	  break;
1865
1866      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1867       * assume it's a Unix-style installation tree, and use
1868       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1869       * folder where the DLL is as FONTCONFIG_PATH.
1870       */
1871      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1872      if (p)
1873      {
1874	  *p = '\0';
1875	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1876	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1877		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
1878	      *p = '\0';
1879	  strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
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
1902static FcChar8 *
1903FcConfigFileExists (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
1947static FcChar8 **
1948FcConfigGetPath (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
2010bail1:
2011    for (i = 0; path[i]; i++)
2012	free (path[i]);
2013    free (path);
2014bail0:
2015    return 0;
2016}
2017
2018static void
2019FcConfigFreePath (FcChar8 **path)
2020{
2021    FcChar8    **p;
2022
2023    for (p = path; *p; p++)
2024	free (*p);
2025    free (path);
2026}
2027
2028static FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
2029
2030FcChar8 *
2031FcConfigHome (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
2047FcChar8 *
2048FcConfigXdgCacheHome (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
2074FcChar8 *
2075FcConfigXdgConfigHome (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
2101FcChar8 *
2102FcConfigXdgDataHome (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
2128FcBool
2129FcConfigEnableHome (FcBool enable)
2130{
2131    FcBool  prev = _FcConfigHomeEnabled;
2132    _FcConfigHomeEnabled = enable;
2133    return prev;
2134}
2135
2136FcChar8 *
2137FcConfigFilename (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
2192FcBool
2193FcConfigAppFontAddFile (FcConfig    *config,
2194			const FcChar8  *file)
2195{
2196    FcFontSet	*set;
2197    FcStrSet	*subdirs;
2198    FcStrList	*sublist;
2199    FcChar8	*subdir;
2200
2201    if (!config)
2202    {
2203	config = FcConfigGetCurrent ();
2204	if (!config)
2205	    return FcFalse;
2206    }
2207
2208    subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
2209    if (!subdirs)
2210	return FcFalse;
2211
2212    set = FcConfigGetFonts (config, FcSetApplication);
2213    if (!set)
2214    {
2215	set = FcFontSetCreate ();
2216	if (!set)
2217	{
2218	    FcStrSetDestroy (subdirs);
2219	    return FcFalse;
2220	}
2221	FcConfigSetFonts (config, set, FcSetApplication);
2222    }
2223
2224    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
2225    {
2226	FcStrSetDestroy (subdirs);
2227	return FcFalse;
2228    }
2229    if ((sublist = FcStrListCreate (subdirs)))
2230    {
2231	while ((subdir = FcStrListNext (sublist)))
2232	{
2233	    FcConfigAppFontAddDir (config, subdir);
2234	}
2235	FcStrListDone (sublist);
2236    }
2237    FcStrSetDestroy (subdirs);
2238    return FcTrue;
2239}
2240
2241FcBool
2242FcConfigAppFontAddDir (FcConfig	    *config,
2243		       const FcChar8   *dir)
2244{
2245    FcFontSet	*set;
2246    FcStrSet	*dirs;
2247
2248    if (!config)
2249    {
2250	config = FcConfigGetCurrent ();
2251	if (!config)
2252	    return FcFalse;
2253    }
2254
2255    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
2256    if (!dirs)
2257	return FcFalse;
2258
2259    set = FcConfigGetFonts (config, FcSetApplication);
2260    if (!set)
2261    {
2262	set = FcFontSetCreate ();
2263	if (!set)
2264	{
2265	    FcStrSetDestroy (dirs);
2266	    return FcFalse;
2267	}
2268	FcConfigSetFonts (config, set, FcSetApplication);
2269    }
2270
2271    FcStrSetAddFilename (dirs, dir);
2272
2273    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
2274    {
2275	FcStrSetDestroy (dirs);
2276	return FcFalse;
2277    }
2278    FcStrSetDestroy (dirs);
2279    return FcTrue;
2280}
2281
2282void
2283FcConfigAppFontClear (FcConfig	    *config)
2284{
2285    if (!config)
2286    {
2287	config = FcConfigGetCurrent ();
2288	if (!config)
2289	    return;
2290    }
2291
2292    FcConfigSetFonts (config, 0, FcSetApplication);
2293}
2294
2295/*
2296 * Manage filename-based font source selectors
2297 */
2298
2299FcBool
2300FcConfigGlobAdd (FcConfig	*config,
2301		 const FcChar8  *glob,
2302		 FcBool		accept)
2303{
2304    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
2305
2306    return FcStrSetAdd (set, glob);
2307}
2308
2309static FcBool
2310FcConfigGlobsMatch (const FcStrSet	*globs,
2311		    const FcChar8	*string)
2312{
2313    int	i;
2314
2315    for (i = 0; i < globs->num; i++)
2316	if (FcStrGlobMatch (globs->strs[i], string))
2317	    return FcTrue;
2318    return FcFalse;
2319}
2320
2321FcBool
2322FcConfigAcceptFilename (FcConfig	*config,
2323			const FcChar8	*filename)
2324{
2325    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2326	return FcTrue;
2327    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2328	return FcFalse;
2329    return FcTrue;
2330}
2331
2332/*
2333 * Manage font-pattern based font source selectors
2334 */
2335
2336FcBool
2337FcConfigPatternsAdd (FcConfig	*config,
2338		     FcPattern	*pattern,
2339		     FcBool	accept)
2340{
2341    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
2342
2343    return FcFontSetAdd (set, pattern);
2344}
2345
2346static FcBool
2347FcConfigPatternsMatch (const FcFontSet	*patterns,
2348		       const FcPattern	*font)
2349{
2350    int i;
2351
2352    for (i = 0; i < patterns->nfont; i++)
2353	if (FcListPatternMatchAny (patterns->fonts[i], font))
2354	    return FcTrue;
2355    return FcFalse;
2356}
2357
2358FcBool
2359FcConfigAcceptFont (FcConfig	    *config,
2360		    const FcPattern *font)
2361{
2362    if (FcConfigPatternsMatch (config->acceptPatterns, font))
2363	return FcTrue;
2364    if (FcConfigPatternsMatch (config->rejectPatterns, font))
2365	return FcFalse;
2366    return FcTrue;
2367}
2368
2369const FcChar8 *
2370FcConfigGetSysRoot (const FcConfig *config)
2371{
2372    if (!config)
2373    {
2374	config = FcConfigGetCurrent ();
2375	if (!config)
2376	    return NULL;
2377    }
2378
2379    return config->sysRoot;
2380}
2381
2382void
2383FcConfigSetSysRoot (FcConfig      *config,
2384		    const FcChar8 *sysroot)
2385{
2386    FcChar8 *s = NULL;
2387    FcBool init = FcFalse;
2388
2389    if (!config)
2390    {
2391	/* We can't use FcConfigGetCurrent() here to ensure
2392	 * the sysroot is set prior to initialize FcConfig,
2393	 * to avoid loading caches from non-sysroot dirs.
2394	 * So postpone the initialization later.
2395	 */
2396	config = fc_atomic_ptr_get (&_fcConfig);
2397	if (!config)
2398	{
2399	    config = FcConfigCreate ();
2400	    if (!config)
2401		return;
2402	    init = FcTrue;
2403	}
2404    }
2405
2406    if (sysroot)
2407    {
2408	s = FcStrCopyFilename (sysroot);
2409	if (!s)
2410	    return;
2411    }
2412
2413    if (config->sysRoot)
2414	FcStrFree (config->sysRoot);
2415
2416    config->sysRoot = s;
2417    if (init)
2418    {
2419	config = FcInitLoadOwnConfigAndFonts (config);
2420	FcConfigSetCurrent (config);
2421	/* FcConfigSetCurrent() increases the refcount.
2422	 * decrease it here to avoid the memory leak.
2423	 */
2424	FcConfigDestroy (config);
2425    }
2426}
2427
2428#define __fccfg__
2429#include "fcaliastail.h"
2430#undef __fccfg__
2431