fccfg.c revision 18bd4a06
12c393a42Smrg/*
2a6844aabSmrg * fontconfig/src/fccfg.c
32c393a42Smrg *
42c393a42Smrg * Copyright © 2000 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
25c9710b42Smrg/* Objects MT-safe for readonly access. */
26c9710b42Smrg
272c393a42Smrg#include "fcint.h"
282c393a42Smrg#include <dirent.h>
292c393a42Smrg#include <sys/types.h>
3018bd4a06Smrg#include "../fc-blanks/fcblanks.h"
312c393a42Smrg
322c393a42Smrg#if defined (_WIN32) && !defined (R_OK)
332c393a42Smrg#define R_OK 4
342c393a42Smrg#endif
352c393a42Smrg
36c9710b42Smrgstatic FcConfig    *_fcConfig; /* MT-safe */
37c9710b42Smrg
38c9710b42Smrgstatic FcConfig *
39c9710b42SmrgFcConfigEnsure (void)
40c9710b42Smrg{
41c9710b42Smrg    FcConfig	*config;
42c9710b42Smrgretry:
43c9710b42Smrg    config = fc_atomic_ptr_get (&_fcConfig);
44c9710b42Smrg    if (!config)
45c9710b42Smrg    {
46c9710b42Smrg	config = FcInitLoadConfigAndFonts ();
47c9710b42Smrg
48c9710b42Smrg	if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
49c9710b42Smrg	    FcConfigDestroy (config);
50c9710b42Smrg	    goto retry;
51c9710b42Smrg	}
52c9710b42Smrg    }
53c9710b42Smrg    return config;
54c9710b42Smrg}
55c9710b42Smrg
56c9710b42SmrgFcBool
57c9710b42SmrgFcConfigInit (void)
58c9710b42Smrg{
59c9710b42Smrg  return FcConfigEnsure () ? FcTrue : FcFalse;
60c9710b42Smrg}
61c9710b42Smrg
62c9710b42Smrgvoid
63c9710b42SmrgFcConfigFini (void)
64c9710b42Smrg{
65c9710b42Smrg    FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
66c9710b42Smrg    if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
67c9710b42Smrg	FcConfigDestroy (cfg);
68c9710b42Smrg}
69c9710b42Smrg
702c393a42Smrg
712c393a42SmrgFcConfig *
722c393a42SmrgFcConfigCreate (void)
732c393a42Smrg{
742c393a42Smrg    FcSetName	set;
752c393a42Smrg    FcConfig	*config;
762c393a42Smrg
772c393a42Smrg    config = malloc (sizeof (FcConfig));
782c393a42Smrg    if (!config)
792c393a42Smrg	goto bail0;
80ca08ab68Smrg
812c393a42Smrg    config->configDirs = FcStrSetCreate ();
822c393a42Smrg    if (!config->configDirs)
832c393a42Smrg	goto bail1;
84ca08ab68Smrg
852c393a42Smrg    config->configFiles = FcStrSetCreate ();
862c393a42Smrg    if (!config->configFiles)
872c393a42Smrg	goto bail2;
88ca08ab68Smrg
892c393a42Smrg    config->fontDirs = FcStrSetCreate ();
902c393a42Smrg    if (!config->fontDirs)
912c393a42Smrg	goto bail3;
92ca08ab68Smrg
932c393a42Smrg    config->acceptGlobs = FcStrSetCreate ();
942c393a42Smrg    if (!config->acceptGlobs)
952c393a42Smrg	goto bail4;
962c393a42Smrg
972c393a42Smrg    config->rejectGlobs = FcStrSetCreate ();
982c393a42Smrg    if (!config->rejectGlobs)
992c393a42Smrg	goto bail5;
1002c393a42Smrg
1012c393a42Smrg    config->acceptPatterns = FcFontSetCreate ();
1022c393a42Smrg    if (!config->acceptPatterns)
1032c393a42Smrg	goto bail6;
104ca08ab68Smrg
1052c393a42Smrg    config->rejectPatterns = FcFontSetCreate ();
1062c393a42Smrg    if (!config->rejectPatterns)
1072c393a42Smrg	goto bail7;
1082c393a42Smrg
1092c393a42Smrg    config->cacheDirs = FcStrSetCreate ();
1102c393a42Smrg    if (!config->cacheDirs)
1112c393a42Smrg	goto bail8;
112ca08ab68Smrg
11318bd4a06Smrg    config->blanks = &fcBlanks;
1142c393a42Smrg
1152c393a42Smrg    config->substPattern = 0;
1162c393a42Smrg    config->substFont = 0;
1172c393a42Smrg    config->substScan = 0;
1182c393a42Smrg    config->maxObjects = 0;
1192c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
1202c393a42Smrg	config->fonts[set] = 0;
1212c393a42Smrg
1222c393a42Smrg    config->rescanTime = time(0);
123ca08ab68Smrg    config->rescanInterval = 30;
124a6844aabSmrg
125a6844aabSmrg    config->expr_pool = NULL;
126a6844aabSmrg
127c9710b42Smrg    config->sysRoot = NULL;
128c9710b42Smrg
129c9710b42Smrg    FcRefInit (&config->ref, 1);
130ca08ab68Smrg
1312c393a42Smrg    return config;
1322c393a42Smrg
1332c393a42Smrgbail8:
1342c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
1352c393a42Smrgbail7:
1362c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
1372c393a42Smrgbail6:
1382c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
1392c393a42Smrgbail5:
1402c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
1412c393a42Smrgbail4:
1422c393a42Smrg    FcStrSetDestroy (config->fontDirs);
1432c393a42Smrgbail3:
1442c393a42Smrg    FcStrSetDestroy (config->configFiles);
1452c393a42Smrgbail2:
1462c393a42Smrg    FcStrSetDestroy (config->configDirs);
1472c393a42Smrgbail1:
1482c393a42Smrg    free (config);
1492c393a42Smrgbail0:
1502c393a42Smrg    return 0;
1512c393a42Smrg}
1522c393a42Smrg
1532c393a42Smrgstatic FcFileTime
1542c393a42SmrgFcConfigNewestFile (FcStrSet *files)
1552c393a42Smrg{
1562c393a42Smrg    FcStrList	    *list = FcStrListCreate (files);
1572c393a42Smrg    FcFileTime	    newest = { 0, FcFalse };
1582c393a42Smrg    FcChar8	    *file;
1592c393a42Smrg    struct  stat    statb;
1602c393a42Smrg
1612c393a42Smrg    if (list)
1622c393a42Smrg    {
1632c393a42Smrg	while ((file = FcStrListNext (list)))
164ca08ab68Smrg	    if (FcStat (file, &statb) == 0)
1652c393a42Smrg		if (!newest.set || statb.st_mtime - newest.time > 0)
1662c393a42Smrg		{
1672c393a42Smrg		    newest.set = FcTrue;
1682c393a42Smrg		    newest.time = statb.st_mtime;
1692c393a42Smrg		}
1702c393a42Smrg	FcStrListDone (list);
1712c393a42Smrg    }
1722c393a42Smrg    return newest;
1732c393a42Smrg}
1742c393a42Smrg
1752c393a42SmrgFcBool
1762c393a42SmrgFcConfigUptoDate (FcConfig *config)
1772c393a42Smrg{
1782c393a42Smrg    FcFileTime	config_time, config_dir_time, font_time;
1792c393a42Smrg    time_t	now = time(0);
1802c393a42Smrg    if (!config)
1812c393a42Smrg    {
1822c393a42Smrg	config = FcConfigGetCurrent ();
1832c393a42Smrg	if (!config)
1842c393a42Smrg	    return FcFalse;
1852c393a42Smrg    }
1862c393a42Smrg    config_time = FcConfigNewestFile (config->configFiles);
1872c393a42Smrg    config_dir_time = FcConfigNewestFile (config->configDirs);
1882c393a42Smrg    font_time = FcConfigNewestFile (config->fontDirs);
1892c393a42Smrg    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
1902c393a42Smrg	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
1912c393a42Smrg	(font_time.set && (font_time.time - config->rescanTime) > 0))
1922c393a42Smrg    {
1932c393a42Smrg	/* We need to check for potential clock problems here (OLPC ticket #6046) */
1942c393a42Smrg	if ((config_time.set && (config_time.time - now) > 0) ||
1952c393a42Smrg    	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
1962c393a42Smrg        (font_time.set && (font_time.time - now) > 0))
1972c393a42Smrg	{
1982c393a42Smrg	    fprintf (stderr,
199c9710b42Smrg                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
2002c393a42Smrg	    config->rescanTime = now;
2012c393a42Smrg	    return FcTrue;
2022c393a42Smrg	}
2032c393a42Smrg	else
2042c393a42Smrg	    return FcFalse;
2052c393a42Smrg    }
2062c393a42Smrg    config->rescanTime = now;
2072c393a42Smrg    return FcTrue;
2082c393a42Smrg}
2092c393a42Smrg
2102c393a42Smrgstatic void
2112c393a42SmrgFcSubstDestroy (FcSubst *s)
2122c393a42Smrg{
2132c393a42Smrg    FcSubst *n;
214ca08ab68Smrg
2152c393a42Smrg    while (s)
2162c393a42Smrg    {
2172c393a42Smrg	n = s->next;
2186fc018e4Smrg	if (s->rule)
2196fc018e4Smrg	    FcRuleDestroy (s->rule);
2202c393a42Smrg	free (s);
2212c393a42Smrg	s = n;
2222c393a42Smrg    }
2232c393a42Smrg}
2242c393a42Smrg
225a6844aabSmrgFcExpr *
226a6844aabSmrgFcConfigAllocExpr (FcConfig *config)
227a6844aabSmrg{
2286fc018e4Smrg    if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
2296fc018e4Smrg    {
2306fc018e4Smrg	FcExprPage *new_page;
231a6844aabSmrg
2326fc018e4Smrg	new_page = malloc (sizeof (FcExprPage));
2336fc018e4Smrg	if (!new_page)
2346fc018e4Smrg	    return 0;
235a6844aabSmrg
2366fc018e4Smrg	new_page->next_page = config->expr_pool;
2376fc018e4Smrg	new_page->next = new_page->exprs;
2386fc018e4Smrg	config->expr_pool = new_page;
2396fc018e4Smrg    }
240a6844aabSmrg
2416fc018e4Smrg    return config->expr_pool->next++;
242a6844aabSmrg}
243a6844aabSmrg
244a6844aabSmrgFcConfig *
245a6844aabSmrgFcConfigReference (FcConfig *config)
246a6844aabSmrg{
247a6844aabSmrg    if (!config)
248a6844aabSmrg    {
249a6844aabSmrg	config = FcConfigGetCurrent ();
250a6844aabSmrg	if (!config)
251a6844aabSmrg	    return 0;
252a6844aabSmrg    }
253a6844aabSmrg
254c9710b42Smrg    FcRefInc (&config->ref);
255a6844aabSmrg
256a6844aabSmrg    return config;
257a6844aabSmrg}
258a6844aabSmrg
2592c393a42Smrgvoid
2602c393a42SmrgFcConfigDestroy (FcConfig *config)
2612c393a42Smrg{
2622c393a42Smrg    FcSetName	set;
263a6844aabSmrg    FcExprPage	*page;
264a6844aabSmrg
265c9710b42Smrg    if (FcRefDec (&config->ref) != 1)
266a6844aabSmrg	return;
2672c393a42Smrg
268c9710b42Smrg    (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
2692c393a42Smrg
2702c393a42Smrg    FcStrSetDestroy (config->configDirs);
2712c393a42Smrg    FcStrSetDestroy (config->fontDirs);
2722c393a42Smrg    FcStrSetDestroy (config->cacheDirs);
2732c393a42Smrg    FcStrSetDestroy (config->configFiles);
2742c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
2752c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
2762c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
2772c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
2782c393a42Smrg
2792c393a42Smrg    if (config->blanks)
2802c393a42Smrg	FcBlanksDestroy (config->blanks);
2812c393a42Smrg
2822c393a42Smrg    FcSubstDestroy (config->substPattern);
2832c393a42Smrg    FcSubstDestroy (config->substFont);
2842c393a42Smrg    FcSubstDestroy (config->substScan);
2852c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
2862c393a42Smrg	if (config->fonts[set])
2872c393a42Smrg	    FcFontSetDestroy (config->fonts[set]);
2882c393a42Smrg
289a6844aabSmrg    page = config->expr_pool;
290a6844aabSmrg    while (page)
291a6844aabSmrg    {
292a6844aabSmrg      FcExprPage *next = page->next_page;
293a6844aabSmrg      free (page);
294a6844aabSmrg      page = next;
295a6844aabSmrg    }
296c9710b42Smrg    if (config->sysRoot)
297c9710b42Smrg	FcStrFree (config->sysRoot);
298a6844aabSmrg
2992c393a42Smrg    free (config);
3002c393a42Smrg}
3012c393a42Smrg
3022c393a42Smrg/*
3032c393a42Smrg * Add cache to configuration, adding fonts and directories
3042c393a42Smrg */
3052c393a42Smrg
3062c393a42SmrgFcBool
307ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache,
3082c393a42Smrg		  FcSetName set, FcStrSet *dirSet)
3092c393a42Smrg{
3102c393a42Smrg    FcFontSet	*fs;
3112c393a42Smrg    intptr_t	*dirs;
3122c393a42Smrg    int		i;
3132c393a42Smrg
3142c393a42Smrg    /*
3152c393a42Smrg     * Add fonts
3162c393a42Smrg     */
3172c393a42Smrg    fs = FcCacheSet (cache);
3182c393a42Smrg    if (fs)
3192c393a42Smrg    {
3202c393a42Smrg	int	nref = 0;
3212c393a42Smrg
3222c393a42Smrg	for (i = 0; i < fs->nfont; i++)
3232c393a42Smrg	{
3242c393a42Smrg	    FcPattern	*font = FcFontSetFont (fs, i);
3252c393a42Smrg	    FcChar8	*font_file;
3262c393a42Smrg
3272c393a42Smrg	    /*
3282c393a42Smrg	     * Check to see if font is banned by filename
3292c393a42Smrg	     */
3302c393a42Smrg	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
3312c393a42Smrg					  0, &font_file) == FcResultMatch &&
3322c393a42Smrg		!FcConfigAcceptFilename (config, font_file))
3332c393a42Smrg	    {
3342c393a42Smrg		continue;
3352c393a42Smrg	    }
3362c393a42Smrg
3372c393a42Smrg	    /*
3382c393a42Smrg	     * Check to see if font is banned by pattern
3392c393a42Smrg	     */
3402c393a42Smrg	    if (!FcConfigAcceptFont (config, font))
3412c393a42Smrg		continue;
3422c393a42Smrg
343c9710b42Smrg	    if (FcFontSetAdd (config->fonts[set], font))
344c9710b42Smrg		nref++;
3452c393a42Smrg	}
3462c393a42Smrg	FcDirCacheReference (cache, nref);
3472c393a42Smrg    }
3482c393a42Smrg
3492c393a42Smrg    /*
3502c393a42Smrg     * Add directories
3512c393a42Smrg     */
3522c393a42Smrg    dirs = FcCacheDirs (cache);
3532c393a42Smrg    if (dirs)
3542c393a42Smrg    {
3552c393a42Smrg	for (i = 0; i < cache->dirs_count; i++)
3562c393a42Smrg	{
3572c393a42Smrg	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
3582c393a42Smrg	    if (FcConfigAcceptFilename (config, dir))
3592c393a42Smrg		FcStrSetAddFilename (dirSet, dir);
3602c393a42Smrg	}
3612c393a42Smrg    }
3622c393a42Smrg    return FcTrue;
3632c393a42Smrg}
3642c393a42Smrg
3652c393a42Smrgstatic FcBool
3662c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
3672c393a42Smrg{
3682c393a42Smrg    FcStrList	    *dirlist;
3692c393a42Smrg    FcChar8	    *dir;
3702c393a42Smrg    FcCache	    *cache;
371ca08ab68Smrg
3722c393a42Smrg    dirlist = FcStrListCreate (dirSet);
3732c393a42Smrg    if (!dirlist)
3742c393a42Smrg        return FcFalse;
3752c393a42Smrg
3762c393a42Smrg    while ((dir = FcStrListNext (dirlist)))
3772c393a42Smrg    {
3782c393a42Smrg	if (FcDebug () & FC_DBG_FONTSET)
37918bd4a06Smrg	    printf ("adding fonts from %s\n", dir);
3802c393a42Smrg	cache = FcDirCacheRead (dir, FcFalse, config);
3812c393a42Smrg	if (!cache)
3822c393a42Smrg	    continue;
3832c393a42Smrg	FcConfigAddCache (config, cache, set, dirSet);
3842c393a42Smrg	FcDirCacheUnload (cache);
3852c393a42Smrg    }
3862c393a42Smrg    FcStrListDone (dirlist);
3872c393a42Smrg    return FcTrue;
3882c393a42Smrg}
3892c393a42Smrg
3902c393a42Smrg/*
3912c393a42Smrg * Scan the current list of directories in the configuration
3922c393a42Smrg * and build the set of available fonts.
3932c393a42Smrg */
3942c393a42Smrg
3952c393a42SmrgFcBool
3962c393a42SmrgFcConfigBuildFonts (FcConfig *config)
3972c393a42Smrg{
3982c393a42Smrg    FcFontSet	    *fonts;
3992c393a42Smrg
4002c393a42Smrg    if (!config)
4012c393a42Smrg    {
4022c393a42Smrg	config = FcConfigGetCurrent ();
4032c393a42Smrg	if (!config)
4042c393a42Smrg	    return FcFalse;
4052c393a42Smrg    }
4062c393a42Smrg
4072c393a42Smrg    fonts = FcFontSetCreate ();
4082c393a42Smrg    if (!fonts)
4092c393a42Smrg	return FcFalse;
410ca08ab68Smrg
4112c393a42Smrg    FcConfigSetFonts (config, fonts, FcSetSystem);
412ca08ab68Smrg
4132c393a42Smrg    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
4142c393a42Smrg	return FcFalse;
4152c393a42Smrg    if (FcDebug () & FC_DBG_FONTSET)
4162c393a42Smrg	FcFontSetPrint (fonts);
4172c393a42Smrg    return FcTrue;
4182c393a42Smrg}
4192c393a42Smrg
4202c393a42SmrgFcBool
4212c393a42SmrgFcConfigSetCurrent (FcConfig *config)
4222c393a42Smrg{
423c9710b42Smrg    FcConfig *cfg;
424c9710b42Smrg
425c9710b42Smrgretry:
426c9710b42Smrg    cfg = fc_atomic_ptr_get (&_fcConfig);
427c9710b42Smrg
428c9710b42Smrg    if (config == cfg)
4292c393a42Smrg	return FcTrue;
4302c393a42Smrg
431c9710b42Smrg    if (config && !config->fonts[FcSetSystem])
4322c393a42Smrg	if (!FcConfigBuildFonts (config))
4332c393a42Smrg	    return FcFalse;
4342c393a42Smrg
435c9710b42Smrg    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
436c9710b42Smrg	goto retry;
437c9710b42Smrg
43818bd4a06Smrg    FcConfigReference (config);
439c9710b42Smrg    if (cfg)
440c9710b42Smrg	FcConfigDestroy (cfg);
441c9710b42Smrg
4422c393a42Smrg    return FcTrue;
4432c393a42Smrg}
4442c393a42Smrg
4452c393a42SmrgFcConfig *
4462c393a42SmrgFcConfigGetCurrent (void)
4472c393a42Smrg{
448c9710b42Smrg    return FcConfigEnsure ();
4492c393a42Smrg}
4502c393a42Smrg
4512c393a42SmrgFcBool
4522c393a42SmrgFcConfigAddConfigDir (FcConfig	    *config,
4532c393a42Smrg		      const FcChar8 *d)
4542c393a42Smrg{
4552c393a42Smrg    return FcStrSetAddFilename (config->configDirs, d);
4562c393a42Smrg}
4572c393a42Smrg
4582c393a42SmrgFcStrList *
4592c393a42SmrgFcConfigGetConfigDirs (FcConfig   *config)
4602c393a42Smrg{
4612c393a42Smrg    if (!config)
4622c393a42Smrg    {
4632c393a42Smrg	config = FcConfigGetCurrent ();
4642c393a42Smrg	if (!config)
4652c393a42Smrg	    return 0;
4662c393a42Smrg    }
4672c393a42Smrg    return FcStrListCreate (config->configDirs);
4682c393a42Smrg}
4692c393a42Smrg
4702c393a42SmrgFcBool
4712c393a42SmrgFcConfigAddFontDir (FcConfig	    *config,
4722c393a42Smrg		    const FcChar8   *d)
4732c393a42Smrg{
4742c393a42Smrg    return FcStrSetAddFilename (config->fontDirs, d);
4752c393a42Smrg}
4762c393a42Smrg
4772c393a42SmrgFcBool
4782c393a42SmrgFcConfigAddDir (FcConfig	    *config,
4792c393a42Smrg		const FcChar8	    *d)
4802c393a42Smrg{
481ca08ab68Smrg    return (FcConfigAddConfigDir (config, d) &&
4822c393a42Smrg	    FcConfigAddFontDir (config, d));
4832c393a42Smrg}
4842c393a42Smrg
4852c393a42SmrgFcStrList *
4862c393a42SmrgFcConfigGetFontDirs (FcConfig	*config)
4872c393a42Smrg{
4882c393a42Smrg    if (!config)
4892c393a42Smrg    {
4902c393a42Smrg	config = FcConfigGetCurrent ();
4912c393a42Smrg	if (!config)
4922c393a42Smrg	    return 0;
4932c393a42Smrg    }
4942c393a42Smrg    return FcStrListCreate (config->fontDirs);
4952c393a42Smrg}
4962c393a42Smrg
4972c393a42SmrgFcBool
4982c393a42SmrgFcConfigAddCacheDir (FcConfig	    *config,
4992c393a42Smrg		     const FcChar8  *d)
5002c393a42Smrg{
5012c393a42Smrg    return FcStrSetAddFilename (config->cacheDirs, d);
5022c393a42Smrg}
5032c393a42Smrg
5042c393a42SmrgFcStrList *
505ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config)
5062c393a42Smrg{
5072c393a42Smrg    if (!config)
5082c393a42Smrg    {
5092c393a42Smrg	config = FcConfigGetCurrent ();
5102c393a42Smrg	if (!config)
5112c393a42Smrg	    return 0;
5122c393a42Smrg    }
5132c393a42Smrg    return FcStrListCreate (config->cacheDirs);
5142c393a42Smrg}
515ca08ab68Smrg
5162c393a42SmrgFcBool
5172c393a42SmrgFcConfigAddConfigFile (FcConfig	    *config,
5182c393a42Smrg		       const FcChar8   *f)
5192c393a42Smrg{
5202c393a42Smrg    FcBool	ret;
5212c393a42Smrg    FcChar8	*file = FcConfigFilename (f);
522ca08ab68Smrg
5232c393a42Smrg    if (!file)
5242c393a42Smrg	return FcFalse;
525ca08ab68Smrg
5262c393a42Smrg    ret = FcStrSetAdd (config->configFiles, file);
5272c393a42Smrg    FcStrFree (file);
5282c393a42Smrg    return ret;
5292c393a42Smrg}
5302c393a42Smrg
5312c393a42SmrgFcStrList *
5322c393a42SmrgFcConfigGetConfigFiles (FcConfig    *config)
5332c393a42Smrg{
5342c393a42Smrg    if (!config)
5352c393a42Smrg    {
5362c393a42Smrg	config = FcConfigGetCurrent ();
5372c393a42Smrg	if (!config)
5382c393a42Smrg	    return 0;
5392c393a42Smrg    }
5402c393a42Smrg    return FcStrListCreate (config->configFiles);
5412c393a42Smrg}
5422c393a42Smrg
5432c393a42SmrgFcChar8 *
544c9710b42SmrgFcConfigGetCache (FcConfig  *config FC_UNUSED)
5452c393a42Smrg{
5462c393a42Smrg    return NULL;
5472c393a42Smrg}
5482c393a42Smrg
5492c393a42SmrgFcFontSet *
5502c393a42SmrgFcConfigGetFonts (FcConfig	*config,
5512c393a42Smrg		  FcSetName	set)
5522c393a42Smrg{
5532c393a42Smrg    if (!config)
5542c393a42Smrg    {
5552c393a42Smrg	config = FcConfigGetCurrent ();
5562c393a42Smrg	if (!config)
5572c393a42Smrg	    return 0;
5582c393a42Smrg    }
5592c393a42Smrg    return config->fonts[set];
5602c393a42Smrg}
5612c393a42Smrg
5622c393a42Smrgvoid
5632c393a42SmrgFcConfigSetFonts (FcConfig	*config,
5642c393a42Smrg		  FcFontSet	*fonts,
5652c393a42Smrg		  FcSetName	set)
5662c393a42Smrg{
5672c393a42Smrg    if (config->fonts[set])
5682c393a42Smrg	FcFontSetDestroy (config->fonts[set]);
5692c393a42Smrg    config->fonts[set] = fonts;
5702c393a42Smrg}
5712c393a42Smrg
5722c393a42SmrgFcBlanks *
5732c393a42SmrgFcConfigGetBlanks (FcConfig	*config)
5742c393a42Smrg{
5752c393a42Smrg    if (!config)
5762c393a42Smrg    {
5772c393a42Smrg	config = FcConfigGetCurrent ();
5782c393a42Smrg	if (!config)
5792c393a42Smrg	    return 0;
5802c393a42Smrg    }
5812c393a42Smrg    return config->blanks;
5822c393a42Smrg}
5832c393a42Smrg
5842c393a42SmrgFcBool
5852c393a42SmrgFcConfigAddBlank (FcConfig	*config,
5862c393a42Smrg		  FcChar32    	blank)
5872c393a42Smrg{
5882c393a42Smrg    FcBlanks	*b, *freeme = 0;
589ca08ab68Smrg
5902c393a42Smrg    b = config->blanks;
5912c393a42Smrg    if (!b)
5922c393a42Smrg    {
5932c393a42Smrg	freeme = b = FcBlanksCreate ();
5942c393a42Smrg	if (!b)
5952c393a42Smrg	    return FcFalse;
5962c393a42Smrg    }
5972c393a42Smrg    if (!FcBlanksAdd (b, blank))
5982c393a42Smrg    {
5992c393a42Smrg        if (freeme)
6002c393a42Smrg            FcBlanksDestroy (freeme);
6012c393a42Smrg	return FcFalse;
6022c393a42Smrg    }
6032c393a42Smrg    config->blanks = b;
6042c393a42Smrg    return FcTrue;
6052c393a42Smrg}
6062c393a42Smrg
6072c393a42Smrgint
6082c393a42SmrgFcConfigGetRescanInterval (FcConfig *config)
6092c393a42Smrg{
6102c393a42Smrg    if (!config)
6112c393a42Smrg    {
6122c393a42Smrg	config = FcConfigGetCurrent ();
6132c393a42Smrg	if (!config)
6142c393a42Smrg	    return 0;
6152c393a42Smrg    }
6162c393a42Smrg    return config->rescanInterval;
6172c393a42Smrg}
6182c393a42Smrg
6192c393a42SmrgFcBool
6202c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
6212c393a42Smrg{
6222c393a42Smrg    if (!config)
6232c393a42Smrg    {
6242c393a42Smrg	config = FcConfigGetCurrent ();
6252c393a42Smrg	if (!config)
6262c393a42Smrg	    return FcFalse;
6272c393a42Smrg    }
6282c393a42Smrg    config->rescanInterval = rescanInterval;
6292c393a42Smrg    return FcTrue;
6302c393a42Smrg}
6312c393a42Smrg
6322c393a42Smrg/*
6332c393a42Smrg * A couple of typos escaped into the library
6342c393a42Smrg */
6352c393a42Smrgint
6362c393a42SmrgFcConfigGetRescanInverval (FcConfig *config)
6372c393a42Smrg{
6382c393a42Smrg    return FcConfigGetRescanInterval (config);
6392c393a42Smrg}
6402c393a42Smrg
6412c393a42SmrgFcBool
6422c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
6432c393a42Smrg{
6442c393a42Smrg    return FcConfigSetRescanInterval (config, rescanInterval);
6452c393a42Smrg}
6462c393a42Smrg
6472c393a42SmrgFcBool
6486fc018e4SmrgFcConfigAddRule (FcConfig	*config,
6496fc018e4Smrg		 FcRule		*rule,
6502c393a42Smrg		 FcMatchKind	kind)
6512c393a42Smrg{
6522c393a42Smrg    FcSubst	*subst, **prev;
6536fc018e4Smrg    FcRule	*r;
6546fc018e4Smrg    int		n = 0;
6552c393a42Smrg
6566fc018e4Smrg    if (!rule)
6576fc018e4Smrg	return FcFalse;
6582c393a42Smrg    switch (kind) {
6592c393a42Smrg    case FcMatchPattern:
6602c393a42Smrg	prev = &config->substPattern;
6612c393a42Smrg	break;
6622c393a42Smrg    case FcMatchFont:
6632c393a42Smrg	prev = &config->substFont;
6642c393a42Smrg	break;
6652c393a42Smrg    case FcMatchScan:
6662c393a42Smrg	prev = &config->substScan;
6672c393a42Smrg	break;
6682c393a42Smrg    default:
6692c393a42Smrg	return FcFalse;
6702c393a42Smrg    }
6712c393a42Smrg    subst = (FcSubst *) malloc (sizeof (FcSubst));
6722c393a42Smrg    if (!subst)
6732c393a42Smrg	return FcFalse;
6742c393a42Smrg    for (; *prev; prev = &(*prev)->next);
6752c393a42Smrg    *prev = subst;
6766fc018e4Smrg    subst->next = NULL;
6776fc018e4Smrg    subst->rule = rule;
6786fc018e4Smrg    for (r = rule; r; r = r->next)
6792c393a42Smrg    {
6806fc018e4Smrg	switch (r->type)
6816fc018e4Smrg	{
6826fc018e4Smrg	case FcRuleTest:
6836fc018e4Smrg	    if (r->u.test &&
6846fc018e4Smrg		r->u.test->kind == FcMatchDefault)
6856fc018e4Smrg		r->u.test->kind = kind;
6866fc018e4Smrg
6876fc018e4Smrg	    if (n < r->u.test->object)
6886fc018e4Smrg		n = r->u.test->object;
6896fc018e4Smrg	    break;
6906fc018e4Smrg	case FcRuleEdit:
6916fc018e4Smrg	    if (n < r->u.edit->object)
6926fc018e4Smrg		n = r->u.edit->object;
6936fc018e4Smrg	    break;
6946fc018e4Smrg	default:
6956fc018e4Smrg	    break;
6966fc018e4Smrg	}
6972c393a42Smrg    }
6986fc018e4Smrg    n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
6996fc018e4Smrg    if (config->maxObjects < n)
7006fc018e4Smrg	config->maxObjects = n;
7012c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
7022c393a42Smrg    {
7032c393a42Smrg	printf ("Add Subst ");
7042c393a42Smrg	FcSubstPrint (subst);
7052c393a42Smrg    }
7062c393a42Smrg    return FcTrue;
7072c393a42Smrg}
7082c393a42Smrg
7092c393a42Smrgstatic FcValue
710c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
7112c393a42Smrg{
7122c393a42Smrg    if (v.type == FcTypeInteger)
7132c393a42Smrg    {
7142c393a42Smrg	v.type = FcTypeDouble;
7152c393a42Smrg	v.u.d = (double) v.u.i;
7162c393a42Smrg    }
7172c393a42Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
7182c393a42Smrg    {
7192c393a42Smrg	v.u.m = &FcIdentityMatrix;
7202c393a42Smrg	v.type = FcTypeMatrix;
7212c393a42Smrg    }
722c9710b42Smrg    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
7232c393a42Smrg    {
724c9710b42Smrg	v.u.l = FcLangSetPromote (v.u.s, buf);
7252c393a42Smrg	v.type = FcTypeLangSet;
7262c393a42Smrg    }
72718bd4a06Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeLangSet)
72818bd4a06Smrg    {
72918bd4a06Smrg	v.u.l = FcLangSetPromote (NULL, buf);
73018bd4a06Smrg	v.type = FcTypeLangSet;
73118bd4a06Smrg    }
73218bd4a06Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeCharSet)
73318bd4a06Smrg    {
73418bd4a06Smrg	v.u.c = FcCharSetPromote (buf);
73518bd4a06Smrg	v.type = FcTypeCharSet;
73618bd4a06Smrg    }
73718bd4a06Smrg    if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
73818bd4a06Smrg    {
73918bd4a06Smrg	v.u.r = FcRangePromote (v.u.d, buf);
74018bd4a06Smrg	v.type = FcTypeRange;
74118bd4a06Smrg    }
7422c393a42Smrg    return v;
7432c393a42Smrg}
7442c393a42Smrg
7452c393a42SmrgFcBool
7462c393a42SmrgFcConfigCompareValue (const FcValue	*left_o,
7476fc018e4Smrg		      unsigned int      op_,
7482c393a42Smrg		      const FcValue	*right_o)
7492c393a42Smrg{
7502c393a42Smrg    FcValue	left = FcValueCanonicalize(left_o);
7512c393a42Smrg    FcValue	right = FcValueCanonicalize(right_o);
7522c393a42Smrg    FcBool	ret = FcFalse;
753ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (op_);
754ca08ab68Smrg    int		flags = FC_OP_GET_FLAGS (op_);
755c9710b42Smrg    FcValuePromotionBuffer buf1, buf2;
756ca08ab68Smrg
757c9710b42Smrg    left = FcConfigPromote (left, right, &buf1);
758c9710b42Smrg    right = FcConfigPromote (right, left, &buf2);
759ca08ab68Smrg    if (left.type == right.type)
7602c393a42Smrg    {
7612c393a42Smrg	switch (left.type) {
7626fc018e4Smrg	case FcTypeUnknown:
7636fc018e4Smrg	    break;	/* No way to guess how to compare for this object */
7642c393a42Smrg	case FcTypeInteger:
7652c393a42Smrg	    break;	/* FcConfigPromote prevents this from happening */
7662c393a42Smrg	case FcTypeDouble:
767c9710b42Smrg	    switch ((int) op) {
7682c393a42Smrg	    case FcOpEqual:
7692c393a42Smrg	    case FcOpContains:
7702c393a42Smrg	    case FcOpListing:
7712c393a42Smrg		ret = left.u.d == right.u.d;
7722c393a42Smrg		break;
7732c393a42Smrg	    case FcOpNotEqual:
7742c393a42Smrg	    case FcOpNotContains:
7752c393a42Smrg		ret = left.u.d != right.u.d;
7762c393a42Smrg		break;
777ca08ab68Smrg	    case FcOpLess:
7782c393a42Smrg		ret = left.u.d < right.u.d;
7792c393a42Smrg		break;
780ca08ab68Smrg	    case FcOpLessEqual:
7812c393a42Smrg		ret = left.u.d <= right.u.d;
7822c393a42Smrg		break;
783ca08ab68Smrg	    case FcOpMore:
7842c393a42Smrg		ret = left.u.d > right.u.d;
7852c393a42Smrg		break;
786ca08ab68Smrg	    case FcOpMoreEqual:
7872c393a42Smrg		ret = left.u.d >= right.u.d;
7882c393a42Smrg		break;
7892c393a42Smrg	    default:
7902c393a42Smrg		break;
7912c393a42Smrg	    }
7922c393a42Smrg	    break;
7932c393a42Smrg	case FcTypeBool:
794c9710b42Smrg	    switch ((int) op) {
795ca08ab68Smrg	    case FcOpEqual:
7962c393a42Smrg	    case FcOpContains:
7972c393a42Smrg	    case FcOpListing:
7982c393a42Smrg		ret = left.u.b == right.u.b;
7992c393a42Smrg		break;
8002c393a42Smrg	    case FcOpNotEqual:
8012c393a42Smrg	    case FcOpNotContains:
8022c393a42Smrg		ret = left.u.b != right.u.b;
8032c393a42Smrg		break;
8042c393a42Smrg	    default:
8052c393a42Smrg		break;
8062c393a42Smrg	    }
8072c393a42Smrg	    break;
8082c393a42Smrg	case FcTypeString:
809c9710b42Smrg	    switch ((int) op) {
810ca08ab68Smrg	    case FcOpEqual:
8112c393a42Smrg	    case FcOpListing:
812ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
813ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
814ca08ab68Smrg		else
815ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
8162c393a42Smrg		break;
8172c393a42Smrg	    case FcOpContains:
8182c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
8192c393a42Smrg		break;
8202c393a42Smrg	    case FcOpNotEqual:
821ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
822ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
823ca08ab68Smrg		else
824ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
8252c393a42Smrg		break;
8262c393a42Smrg	    case FcOpNotContains:
8272c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
8282c393a42Smrg		break;
8292c393a42Smrg	    default:
8302c393a42Smrg		break;
8312c393a42Smrg	    }
8322c393a42Smrg	    break;
8332c393a42Smrg	case FcTypeMatrix:
834c9710b42Smrg	    switch ((int) op) {
8352c393a42Smrg	    case FcOpEqual:
8362c393a42Smrg	    case FcOpContains:
8372c393a42Smrg	    case FcOpListing:
8382c393a42Smrg		ret = FcMatrixEqual (left.u.m, right.u.m);
8392c393a42Smrg		break;
8402c393a42Smrg	    case FcOpNotEqual:
8412c393a42Smrg	    case FcOpNotContains:
8422c393a42Smrg		ret = !FcMatrixEqual (left.u.m, right.u.m);
8432c393a42Smrg		break;
8442c393a42Smrg	    default:
8452c393a42Smrg		break;
8462c393a42Smrg	    }
8472c393a42Smrg	    break;
8482c393a42Smrg	case FcTypeCharSet:
849c9710b42Smrg	    switch ((int) op) {
8502c393a42Smrg	    case FcOpContains:
8512c393a42Smrg	    case FcOpListing:
8522c393a42Smrg		/* left contains right if right is a subset of left */
8532c393a42Smrg		ret = FcCharSetIsSubset (right.u.c, left.u.c);
8542c393a42Smrg		break;
8552c393a42Smrg	    case FcOpNotContains:
8562c393a42Smrg		/* left contains right if right is a subset of left */
8572c393a42Smrg		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
8582c393a42Smrg		break;
8592c393a42Smrg	    case FcOpEqual:
8602c393a42Smrg		ret = FcCharSetEqual (left.u.c, right.u.c);
8612c393a42Smrg		break;
8622c393a42Smrg	    case FcOpNotEqual:
8632c393a42Smrg		ret = !FcCharSetEqual (left.u.c, right.u.c);
8642c393a42Smrg		break;
8652c393a42Smrg	    default:
8662c393a42Smrg		break;
8672c393a42Smrg	    }
8682c393a42Smrg	    break;
8692c393a42Smrg	case FcTypeLangSet:
870c9710b42Smrg	    switch ((int) op) {
8712c393a42Smrg	    case FcOpContains:
8722c393a42Smrg	    case FcOpListing:
8732c393a42Smrg		ret = FcLangSetContains (left.u.l, right.u.l);
8742c393a42Smrg		break;
8752c393a42Smrg	    case FcOpNotContains:
8762c393a42Smrg		ret = !FcLangSetContains (left.u.l, right.u.l);
8772c393a42Smrg		break;
8782c393a42Smrg	    case FcOpEqual:
8792c393a42Smrg		ret = FcLangSetEqual (left.u.l, right.u.l);
8802c393a42Smrg		break;
8812c393a42Smrg	    case FcOpNotEqual:
8822c393a42Smrg		ret = !FcLangSetEqual (left.u.l, right.u.l);
8832c393a42Smrg		break;
8842c393a42Smrg	    default:
8852c393a42Smrg		break;
8862c393a42Smrg	    }
8872c393a42Smrg	    break;
8882c393a42Smrg	case FcTypeVoid:
889c9710b42Smrg	    switch ((int) op) {
8902c393a42Smrg	    case FcOpEqual:
8912c393a42Smrg	    case FcOpContains:
8922c393a42Smrg	    case FcOpListing:
8932c393a42Smrg		ret = FcTrue;
8942c393a42Smrg		break;
8952c393a42Smrg	    default:
8962c393a42Smrg		break;
8972c393a42Smrg	    }
8982c393a42Smrg	    break;
8992c393a42Smrg	case FcTypeFTFace:
900c9710b42Smrg	    switch ((int) op) {
9012c393a42Smrg	    case FcOpEqual:
9022c393a42Smrg	    case FcOpContains:
9032c393a42Smrg	    case FcOpListing:
9042c393a42Smrg		ret = left.u.f == right.u.f;
9052c393a42Smrg		break;
9062c393a42Smrg	    case FcOpNotEqual:
9072c393a42Smrg	    case FcOpNotContains:
9082c393a42Smrg		ret = left.u.f != right.u.f;
9092c393a42Smrg		break;
9102c393a42Smrg	    default:
9112c393a42Smrg		break;
9122c393a42Smrg	    }
9132c393a42Smrg	    break;
91418bd4a06Smrg	case FcTypeRange:
91518bd4a06Smrg	    ret = FcRangeCompare (op, left.u.r, right.u.r);
91618bd4a06Smrg	    break;
9172c393a42Smrg	}
9182c393a42Smrg    }
9192c393a42Smrg    else
9202c393a42Smrg    {
9212c393a42Smrg	if (op == FcOpNotEqual || op == FcOpNotContains)
9222c393a42Smrg	    ret = FcTrue;
9232c393a42Smrg    }
9242c393a42Smrg    return ret;
9252c393a42Smrg}
9262c393a42Smrg
9272c393a42Smrg
9282c393a42Smrg#define _FcDoubleFloor(d)	((int) (d))
9292c393a42Smrg#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
9302c393a42Smrg#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
9312c393a42Smrg#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
9322c393a42Smrg#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
9332c393a42Smrg#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
9342c393a42Smrg
9352c393a42Smrgstatic FcValue
936c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
9372c393a42Smrg{
93818bd4a06Smrg    FcValue	v, vl, vr, vle, vre;
9392c393a42Smrg    FcMatrix	*m;
9402c393a42Smrg    FcChar8     *str;
941ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (e->op);
94218bd4a06Smrg    FcValuePromotionBuffer buf1, buf2;
943ca08ab68Smrg
944c9710b42Smrg    switch ((int) op) {
9452c393a42Smrg    case FcOpInteger:
9462c393a42Smrg	v.type = FcTypeInteger;
9472c393a42Smrg	v.u.i = e->u.ival;
9482c393a42Smrg	break;
9492c393a42Smrg    case FcOpDouble:
9502c393a42Smrg	v.type = FcTypeDouble;
9512c393a42Smrg	v.u.d = e->u.dval;
9522c393a42Smrg	break;
9532c393a42Smrg    case FcOpString:
9542c393a42Smrg	v.type = FcTypeString;
955a6844aabSmrg	v.u.s = e->u.sval;
956a6844aabSmrg	v = FcValueSave (v);
9572c393a42Smrg	break;
9582c393a42Smrg    case FcOpMatrix:
959c9710b42Smrg	{
960c9710b42Smrg	  FcMatrix m;
961c9710b42Smrg	  FcValue xx, xy, yx, yy;
962c9710b42Smrg	  v.type = FcTypeMatrix;
963c9710b42Smrg	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
964c9710b42Smrg	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
965c9710b42Smrg	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
966c9710b42Smrg	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
967c9710b42Smrg	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
968c9710b42Smrg	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
969c9710b42Smrg	  {
970c9710b42Smrg	    m.xx = xx.u.d;
971c9710b42Smrg	    m.xy = xy.u.d;
972c9710b42Smrg	    m.yx = yx.u.d;
973c9710b42Smrg	    m.yy = yy.u.d;
974c9710b42Smrg	    v.u.m = &m;
975c9710b42Smrg	  }
976c9710b42Smrg	  else
977c9710b42Smrg	    v.type = FcTypeVoid;
978c9710b42Smrg	  v = FcValueSave (v);
979c9710b42Smrg	}
9802c393a42Smrg	break;
9812c393a42Smrg    case FcOpCharSet:
9822c393a42Smrg	v.type = FcTypeCharSet;
9832c393a42Smrg	v.u.c = e->u.cval;
9842c393a42Smrg	v = FcValueSave (v);
9852c393a42Smrg	break;
986ca08ab68Smrg    case FcOpLangSet:
987ca08ab68Smrg	v.type = FcTypeLangSet;
988ca08ab68Smrg	v.u.l = e->u.lval;
989ca08ab68Smrg	v = FcValueSave (v);
990ca08ab68Smrg	break;
99118bd4a06Smrg    case FcOpRange:
99218bd4a06Smrg	v.type = FcTypeRange;
99318bd4a06Smrg	v.u.r = e->u.rval;
99418bd4a06Smrg	v = FcValueSave (v);
99518bd4a06Smrg	break;
9962c393a42Smrg    case FcOpBool:
9972c393a42Smrg	v.type = FcTypeBool;
9982c393a42Smrg	v.u.b = e->u.bval;
9992c393a42Smrg	break;
10002c393a42Smrg    case FcOpField:
1001c9710b42Smrg	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
1002c9710b42Smrg	{
1003c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
1004c9710b42Smrg		v.type = FcTypeVoid;
1005c9710b42Smrg	}
1006c9710b42Smrg	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
1007c9710b42Smrg	{
1008c9710b42Smrg	    fprintf (stderr,
1009c9710b42Smrg                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
10102c393a42Smrg	    v.type = FcTypeVoid;
1011c9710b42Smrg	}
1012c9710b42Smrg	else
1013c9710b42Smrg	{
1014c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
1015c9710b42Smrg		v.type = FcTypeVoid;
1016c9710b42Smrg	}
10172c393a42Smrg	v = FcValueSave (v);
10182c393a42Smrg	break;
10192c393a42Smrg    case FcOpConst:
10202c393a42Smrg	if (FcNameConstant (e->u.constant, &v.u.i))
10212c393a42Smrg	    v.type = FcTypeInteger;
10222c393a42Smrg	else
10232c393a42Smrg	    v.type = FcTypeVoid;
10242c393a42Smrg	break;
10252c393a42Smrg    case FcOpQuest:
1026c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
10272c393a42Smrg	if (vl.type == FcTypeBool)
10282c393a42Smrg	{
10292c393a42Smrg	    if (vl.u.b)
1030c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
10312c393a42Smrg	    else
1032c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
10332c393a42Smrg	}
10342c393a42Smrg	else
10352c393a42Smrg	    v.type = FcTypeVoid;
10362c393a42Smrg	FcValueDestroy (vl);
10372c393a42Smrg	break;
10382c393a42Smrg    case FcOpEqual:
10392c393a42Smrg    case FcOpNotEqual:
10402c393a42Smrg    case FcOpLess:
10412c393a42Smrg    case FcOpLessEqual:
10422c393a42Smrg    case FcOpMore:
10432c393a42Smrg    case FcOpMoreEqual:
10442c393a42Smrg    case FcOpContains:
10452c393a42Smrg    case FcOpNotContains:
10462c393a42Smrg    case FcOpListing:
1047c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1048c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
10492c393a42Smrg	v.type = FcTypeBool;
10502c393a42Smrg	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
10512c393a42Smrg	FcValueDestroy (vl);
10522c393a42Smrg	FcValueDestroy (vr);
10532c393a42Smrg	break;
10542c393a42Smrg    case FcOpOr:
10552c393a42Smrg    case FcOpAnd:
10562c393a42Smrg    case FcOpPlus:
10572c393a42Smrg    case FcOpMinus:
10582c393a42Smrg    case FcOpTimes:
10592c393a42Smrg    case FcOpDivide:
1060c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1061c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
106218bd4a06Smrg	vle = FcConfigPromote (vl, vr, &buf1);
106318bd4a06Smrg	vre = FcConfigPromote (vr, vle, &buf2);
106418bd4a06Smrg	if (vle.type == vre.type)
10652c393a42Smrg	{
106618bd4a06Smrg	    switch ((int) vle.type) {
10672c393a42Smrg	    case FcTypeDouble:
1068c9710b42Smrg		switch ((int) op) {
1069ca08ab68Smrg		case FcOpPlus:
10702c393a42Smrg		    v.type = FcTypeDouble;
107118bd4a06Smrg		    v.u.d = vle.u.d + vre.u.d;
10722c393a42Smrg		    break;
10732c393a42Smrg		case FcOpMinus:
10742c393a42Smrg		    v.type = FcTypeDouble;
107518bd4a06Smrg		    v.u.d = vle.u.d - vre.u.d;
10762c393a42Smrg		    break;
10772c393a42Smrg		case FcOpTimes:
10782c393a42Smrg		    v.type = FcTypeDouble;
107918bd4a06Smrg		    v.u.d = vle.u.d * vre.u.d;
10802c393a42Smrg		    break;
10812c393a42Smrg		case FcOpDivide:
10822c393a42Smrg		    v.type = FcTypeDouble;
108318bd4a06Smrg		    v.u.d = vle.u.d / vre.u.d;
10842c393a42Smrg		    break;
10852c393a42Smrg		default:
1086ca08ab68Smrg		    v.type = FcTypeVoid;
10872c393a42Smrg		    break;
10882c393a42Smrg		}
10892c393a42Smrg		if (v.type == FcTypeDouble &&
10902c393a42Smrg		    v.u.d == (double) (int) v.u.d)
10912c393a42Smrg		{
10922c393a42Smrg		    v.type = FcTypeInteger;
10932c393a42Smrg		    v.u.i = (int) v.u.d;
10942c393a42Smrg		}
10952c393a42Smrg		break;
10962c393a42Smrg	    case FcTypeBool:
1097c9710b42Smrg		switch ((int) op) {
10982c393a42Smrg		case FcOpOr:
10992c393a42Smrg		    v.type = FcTypeBool;
110018bd4a06Smrg		    v.u.b = vle.u.b || vre.u.b;
11012c393a42Smrg		    break;
11022c393a42Smrg		case FcOpAnd:
11032c393a42Smrg		    v.type = FcTypeBool;
110418bd4a06Smrg		    v.u.b = vle.u.b && vre.u.b;
11052c393a42Smrg		    break;
11062c393a42Smrg		default:
1107ca08ab68Smrg		    v.type = FcTypeVoid;
11082c393a42Smrg		    break;
11092c393a42Smrg		}
11102c393a42Smrg		break;
11112c393a42Smrg	    case FcTypeString:
1112c9710b42Smrg		switch ((int) op) {
11132c393a42Smrg		case FcOpPlus:
11142c393a42Smrg		    v.type = FcTypeString;
111518bd4a06Smrg		    str = FcStrPlus (vle.u.s, vre.u.s);
1116c9710b42Smrg		    v.u.s = FcStrdup (str);
11172c393a42Smrg		    FcStrFree (str);
1118ca08ab68Smrg
11192c393a42Smrg		    if (!v.u.s)
11202c393a42Smrg			v.type = FcTypeVoid;
11212c393a42Smrg		    break;
11222c393a42Smrg		default:
11232c393a42Smrg		    v.type = FcTypeVoid;
11242c393a42Smrg		    break;
11252c393a42Smrg		}
11262c393a42Smrg		break;
11272c393a42Smrg	    case FcTypeMatrix:
1128c9710b42Smrg		switch ((int) op) {
11292c393a42Smrg		case FcOpTimes:
11302c393a42Smrg		    v.type = FcTypeMatrix;
11312c393a42Smrg		    m = malloc (sizeof (FcMatrix));
11322c393a42Smrg		    if (m)
11332c393a42Smrg		    {
113418bd4a06Smrg			FcMatrixMultiply (m, vle.u.m, vre.u.m);
11352c393a42Smrg			v.u.m = m;
11362c393a42Smrg		    }
11372c393a42Smrg		    else
11382c393a42Smrg		    {
11392c393a42Smrg			v.type = FcTypeVoid;
11402c393a42Smrg		    }
11412c393a42Smrg		    break;
11422c393a42Smrg		default:
11432c393a42Smrg		    v.type = FcTypeVoid;
11442c393a42Smrg		    break;
11452c393a42Smrg		}
11462c393a42Smrg		break;
1147ca08ab68Smrg	    case FcTypeCharSet:
1148c9710b42Smrg		switch ((int) op) {
1149ca08ab68Smrg		case FcOpPlus:
1150ca08ab68Smrg		    v.type = FcTypeCharSet;
115118bd4a06Smrg		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1152ca08ab68Smrg		    if (!v.u.c)
1153ca08ab68Smrg			v.type = FcTypeVoid;
1154ca08ab68Smrg		    break;
1155ca08ab68Smrg		case FcOpMinus:
1156ca08ab68Smrg		    v.type = FcTypeCharSet;
115718bd4a06Smrg		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1158ca08ab68Smrg		    if (!v.u.c)
1159ca08ab68Smrg			v.type = FcTypeVoid;
1160ca08ab68Smrg		    break;
1161ca08ab68Smrg		default:
1162ca08ab68Smrg		    v.type = FcTypeVoid;
1163ca08ab68Smrg		    break;
1164ca08ab68Smrg		}
1165ca08ab68Smrg		break;
1166ca08ab68Smrg	    case FcTypeLangSet:
1167c9710b42Smrg		switch ((int) op) {
1168ca08ab68Smrg		case FcOpPlus:
1169ca08ab68Smrg		    v.type = FcTypeLangSet;
117018bd4a06Smrg		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1171ca08ab68Smrg		    if (!v.u.l)
1172ca08ab68Smrg			v.type = FcTypeVoid;
1173ca08ab68Smrg		    break;
1174ca08ab68Smrg		case FcOpMinus:
1175ca08ab68Smrg		    v.type = FcTypeLangSet;
117618bd4a06Smrg		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1177ca08ab68Smrg		    if (!v.u.l)
1178ca08ab68Smrg			v.type = FcTypeVoid;
1179ca08ab68Smrg		    break;
1180ca08ab68Smrg		default:
1181ca08ab68Smrg		    v.type = FcTypeVoid;
1182ca08ab68Smrg		    break;
1183ca08ab68Smrg		}
1184ca08ab68Smrg		break;
11852c393a42Smrg	    default:
11862c393a42Smrg		v.type = FcTypeVoid;
11872c393a42Smrg		break;
11882c393a42Smrg	    }
11892c393a42Smrg	}
11902c393a42Smrg	else
11912c393a42Smrg	    v.type = FcTypeVoid;
11922c393a42Smrg	FcValueDestroy (vl);
11932c393a42Smrg	FcValueDestroy (vr);
11942c393a42Smrg	break;
11952c393a42Smrg    case FcOpNot:
1196c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1197c9710b42Smrg	switch ((int) vl.type) {
11982c393a42Smrg	case FcTypeBool:
11992c393a42Smrg	    v.type = FcTypeBool;
12002c393a42Smrg	    v.u.b = !vl.u.b;
12012c393a42Smrg	    break;
12022c393a42Smrg	default:
12032c393a42Smrg	    v.type = FcTypeVoid;
12042c393a42Smrg	    break;
12052c393a42Smrg	}
12062c393a42Smrg	FcValueDestroy (vl);
12072c393a42Smrg	break;
12082c393a42Smrg    case FcOpFloor:
1209c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1210c9710b42Smrg	switch ((int) vl.type) {
12112c393a42Smrg	case FcTypeInteger:
12122c393a42Smrg	    v = vl;
12132c393a42Smrg	    break;
12142c393a42Smrg	case FcTypeDouble:
12152c393a42Smrg	    v.type = FcTypeInteger;
12162c393a42Smrg	    v.u.i = FcDoubleFloor (vl.u.d);
12172c393a42Smrg	    break;
12182c393a42Smrg	default:
12192c393a42Smrg	    v.type = FcTypeVoid;
12202c393a42Smrg	    break;
12212c393a42Smrg	}
12222c393a42Smrg	FcValueDestroy (vl);
12232c393a42Smrg	break;
12242c393a42Smrg    case FcOpCeil:
1225c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1226c9710b42Smrg	switch ((int) vl.type) {
12272c393a42Smrg	case FcTypeInteger:
12282c393a42Smrg	    v = vl;
12292c393a42Smrg	    break;
12302c393a42Smrg	case FcTypeDouble:
12312c393a42Smrg	    v.type = FcTypeInteger;
12322c393a42Smrg	    v.u.i = FcDoubleCeil (vl.u.d);
12332c393a42Smrg	    break;
12342c393a42Smrg	default:
12352c393a42Smrg	    v.type = FcTypeVoid;
12362c393a42Smrg	    break;
12372c393a42Smrg	}
12382c393a42Smrg	FcValueDestroy (vl);
12392c393a42Smrg	break;
12402c393a42Smrg    case FcOpRound:
1241c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1242c9710b42Smrg	switch ((int) vl.type) {
12432c393a42Smrg	case FcTypeInteger:
12442c393a42Smrg	    v = vl;
12452c393a42Smrg	    break;
12462c393a42Smrg	case FcTypeDouble:
12472c393a42Smrg	    v.type = FcTypeInteger;
12482c393a42Smrg	    v.u.i = FcDoubleRound (vl.u.d);
12492c393a42Smrg	    break;
12502c393a42Smrg	default:
12512c393a42Smrg	    v.type = FcTypeVoid;
12522c393a42Smrg	    break;
12532c393a42Smrg	}
12542c393a42Smrg	FcValueDestroy (vl);
12552c393a42Smrg	break;
12562c393a42Smrg    case FcOpTrunc:
1257c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1258c9710b42Smrg	switch ((int) vl.type) {
12592c393a42Smrg	case FcTypeInteger:
12602c393a42Smrg	    v = vl;
12612c393a42Smrg	    break;
12622c393a42Smrg	case FcTypeDouble:
12632c393a42Smrg	    v.type = FcTypeInteger;
12642c393a42Smrg	    v.u.i = FcDoubleTrunc (vl.u.d);
12652c393a42Smrg	    break;
12662c393a42Smrg	default:
12672c393a42Smrg	    v.type = FcTypeVoid;
12682c393a42Smrg	    break;
12692c393a42Smrg	}
12702c393a42Smrg	FcValueDestroy (vl);
12712c393a42Smrg	break;
12722c393a42Smrg    default:
12732c393a42Smrg	v.type = FcTypeVoid;
12742c393a42Smrg	break;
12752c393a42Smrg    }
12762c393a42Smrg    return v;
12772c393a42Smrg}
12782c393a42Smrg
12792c393a42Smrgstatic FcValueList *
12802c393a42SmrgFcConfigMatchValueList (FcPattern	*p,
1281c9710b42Smrg			FcPattern	*p_pat,
1282c9710b42Smrg			FcMatchKind      kind,
12832c393a42Smrg			FcTest		*t,
12842c393a42Smrg			FcValueList	*values)
12852c393a42Smrg{
12862c393a42Smrg    FcValueList	    *ret = 0;
12872c393a42Smrg    FcExpr	    *e = t->expr;
12882c393a42Smrg    FcValue	    value;
12892c393a42Smrg    FcValueList	    *v;
1290ca08ab68Smrg
12912c393a42Smrg    while (e)
12922c393a42Smrg    {
12932c393a42Smrg	/* Compute the value of the match expression */
1294ca08ab68Smrg	if (FC_OP_GET_OP (e->op) == FcOpComma)
12952c393a42Smrg	{
1296c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
12972c393a42Smrg	    e = e->u.tree.right;
12982c393a42Smrg	}
12992c393a42Smrg	else
13002c393a42Smrg	{
1301c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e);
13022c393a42Smrg	    e = 0;
13032c393a42Smrg	}
13042c393a42Smrg
13052c393a42Smrg	for (v = values; v; v = FcValueListNext(v))
13062c393a42Smrg	{
13072c393a42Smrg	    /* Compare the pattern value to the match expression value */
13082c393a42Smrg	    if (FcConfigCompareValue (&v->value, t->op, &value))
13092c393a42Smrg	    {
13102c393a42Smrg		if (!ret)
13112c393a42Smrg		    ret = v;
13122c393a42Smrg	    }
13132c393a42Smrg	    else
13142c393a42Smrg	    {
13152c393a42Smrg		if (t->qual == FcQualAll)
13162c393a42Smrg		{
13172c393a42Smrg		    ret = 0;
13182c393a42Smrg		    break;
13192c393a42Smrg		}
13202c393a42Smrg	    }
13212c393a42Smrg	}
13222c393a42Smrg	FcValueDestroy (value);
13232c393a42Smrg    }
13242c393a42Smrg    return ret;
13252c393a42Smrg}
13262c393a42Smrg
13272c393a42Smrgstatic FcValueList *
1328c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
13292c393a42Smrg{
13302c393a42Smrg    FcValueList	*l;
1331ca08ab68Smrg
13322c393a42Smrg    if (!e)
13332c393a42Smrg	return 0;
13342c393a42Smrg    l = (FcValueList *) malloc (sizeof (FcValueList));
13352c393a42Smrg    if (!l)
13362c393a42Smrg	return 0;
1337ca08ab68Smrg    if (FC_OP_GET_OP (e->op) == FcOpComma)
13382c393a42Smrg    {
1339c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1340c9710b42Smrg	l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
13412c393a42Smrg    }
13422c393a42Smrg    else
13432c393a42Smrg    {
1344c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e);
13452c393a42Smrg	l->next = NULL;
13462c393a42Smrg    }
13472c393a42Smrg    l->binding = binding;
13482c393a42Smrg    if (l->value.type == FcTypeVoid)
13492c393a42Smrg    {
13502c393a42Smrg	FcValueList  *next = FcValueListNext(l);
13512c393a42Smrg
13522c393a42Smrg	free (l);
13532c393a42Smrg	l = next;
13542c393a42Smrg    }
13552c393a42Smrg
13562c393a42Smrg    return l;
13572c393a42Smrg}
13582c393a42Smrg
13592c393a42Smrgstatic FcBool
13602c393a42SmrgFcConfigAdd (FcValueListPtr *head,
13612c393a42Smrg	     FcValueList    *position,
13622c393a42Smrg	     FcBool	    append,
1363c9710b42Smrg	     FcValueList    *new,
1364c9710b42Smrg	     FcObject        object)
13652c393a42Smrg{
1366c9710b42Smrg    FcValueListPtr  *prev, l, last, v;
13672c393a42Smrg    FcValueBinding  sameBinding;
1368ca08ab68Smrg
1369c9710b42Smrg    /*
1370c9710b42Smrg     * Make sure the stored type is valid for built-in objects
1371c9710b42Smrg     */
1372c9710b42Smrg    for (l = new; l != NULL; l = FcValueListNext (l))
1373c9710b42Smrg    {
1374c9710b42Smrg	if (!FcObjectValidType (object, l->value.type))
1375c9710b42Smrg	{
1376c9710b42Smrg	    fprintf (stderr,
1377c9710b42Smrg		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1378c9710b42Smrg	    FcValuePrintFile (stderr, l->value);
1379c9710b42Smrg	    fprintf (stderr, "\n");
1380c9710b42Smrg
1381c9710b42Smrg	    if (FcDebug () & FC_DBG_EDIT)
1382c9710b42Smrg	    {
1383c9710b42Smrg		printf ("Not adding\n");
1384c9710b42Smrg	    }
1385c9710b42Smrg
1386c9710b42Smrg	    return FcFalse;
1387c9710b42Smrg	}
1388c9710b42Smrg    }
1389c9710b42Smrg
13902c393a42Smrg    if (position)
13912c393a42Smrg	sameBinding = position->binding;
13922c393a42Smrg    else
13932c393a42Smrg	sameBinding = FcValueBindingWeak;
13942c393a42Smrg    for (v = new; v != NULL; v = FcValueListNext(v))
13952c393a42Smrg	if (v->binding == FcValueBindingSame)
13962c393a42Smrg	    v->binding = sameBinding;
13972c393a42Smrg    if (append)
13982c393a42Smrg    {
13992c393a42Smrg	if (position)
14002c393a42Smrg	    prev = &position->next;
14012c393a42Smrg	else
1402ca08ab68Smrg	    for (prev = head; *prev != NULL;
14032c393a42Smrg		 prev = &(*prev)->next)
14042c393a42Smrg		;
14052c393a42Smrg    }
14062c393a42Smrg    else
14072c393a42Smrg    {
14082c393a42Smrg	if (position)
14092c393a42Smrg	{
1410ca08ab68Smrg	    for (prev = head; *prev != NULL;
14112c393a42Smrg		 prev = &(*prev)->next)
14122c393a42Smrg	    {
14132c393a42Smrg		if (*prev == position)
14142c393a42Smrg		    break;
14152c393a42Smrg	    }
14162c393a42Smrg	}
14172c393a42Smrg	else
14182c393a42Smrg	    prev = head;
14192c393a42Smrg
14202c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
14212c393a42Smrg	{
14222c393a42Smrg	    if (*prev == NULL)
14232c393a42Smrg		printf ("position not on list\n");
14242c393a42Smrg	}
14252c393a42Smrg    }
14262c393a42Smrg
14272c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14282c393a42Smrg    {
14292c393a42Smrg	printf ("%s list before ", append ? "Append" : "Prepend");
1430ca08ab68Smrg	FcValueListPrintWithPosition (*head, *prev);
14312c393a42Smrg	printf ("\n");
14322c393a42Smrg    }
1433ca08ab68Smrg
14342c393a42Smrg    if (new)
14352c393a42Smrg    {
14362c393a42Smrg	last = new;
14372c393a42Smrg	while (last->next != NULL)
14382c393a42Smrg	    last = last->next;
1439ca08ab68Smrg
14402c393a42Smrg	last->next = *prev;
14412c393a42Smrg	*prev = new;
14422c393a42Smrg    }
1443ca08ab68Smrg
14442c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14452c393a42Smrg    {
14462c393a42Smrg	printf ("%s list after ", append ? "Append" : "Prepend");
14472c393a42Smrg	FcValueListPrint (*head);
14482c393a42Smrg	printf ("\n");
14492c393a42Smrg    }
1450ca08ab68Smrg
14512c393a42Smrg    return FcTrue;
14522c393a42Smrg}
14532c393a42Smrg
14542c393a42Smrgstatic void
14552c393a42SmrgFcConfigDel (FcValueListPtr *head,
14562c393a42Smrg	     FcValueList    *position)
14572c393a42Smrg{
14582c393a42Smrg    FcValueListPtr *prev;
14592c393a42Smrg
14602c393a42Smrg    for (prev = head; *prev != NULL; prev = &(*prev)->next)
14612c393a42Smrg    {
14622c393a42Smrg	if (*prev == position)
14632c393a42Smrg	{
14642c393a42Smrg	    *prev = position->next;
14652c393a42Smrg	    position->next = NULL;
14662c393a42Smrg	    FcValueListDestroy (position);
14672c393a42Smrg	    break;
14682c393a42Smrg	}
14692c393a42Smrg    }
14702c393a42Smrg}
14712c393a42Smrg
14722c393a42Smrgstatic void
14732c393a42SmrgFcConfigPatternAdd (FcPattern	*p,
14742c393a42Smrg		    FcObject	object,
14752c393a42Smrg		    FcValueList	*list,
14762c393a42Smrg		    FcBool	append)
14772c393a42Smrg{
14782c393a42Smrg    if (list)
14792c393a42Smrg    {
14802c393a42Smrg	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1481ca08ab68Smrg
14822c393a42Smrg	if (!e)
14832c393a42Smrg	    return;
1484c9710b42Smrg	FcConfigAdd (&e->values, 0, append, list, object);
14852c393a42Smrg    }
14862c393a42Smrg}
14872c393a42Smrg
14882c393a42Smrg/*
14892c393a42Smrg * Delete all values associated with a field
14902c393a42Smrg */
14912c393a42Smrgstatic void
14922c393a42SmrgFcConfigPatternDel (FcPattern	*p,
14932c393a42Smrg		    FcObject	object)
14942c393a42Smrg{
14952c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
14962c393a42Smrg    if (!e)
14972c393a42Smrg	return;
14982c393a42Smrg    while (e->values != NULL)
14992c393a42Smrg	FcConfigDel (&e->values, e->values);
15002c393a42Smrg}
15012c393a42Smrg
15022c393a42Smrgstatic void
15032c393a42SmrgFcConfigPatternCanon (FcPattern	    *p,
15042c393a42Smrg		      FcObject	    object)
15052c393a42Smrg{
15062c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
15072c393a42Smrg    if (!e)
15082c393a42Smrg	return;
15092c393a42Smrg    if (e->values == NULL)
15102c393a42Smrg	FcPatternObjectDel (p, object);
15112c393a42Smrg}
15122c393a42Smrg
15132c393a42SmrgFcBool
15142c393a42SmrgFcConfigSubstituteWithPat (FcConfig    *config,
15152c393a42Smrg			   FcPattern   *p,
15162c393a42Smrg			   FcPattern   *p_pat,
15172c393a42Smrg			   FcMatchKind kind)
15182c393a42Smrg{
1519c9710b42Smrg    FcValue v;
15202c393a42Smrg    FcSubst	    *s;
15216fc018e4Smrg    FcRule          *r;
15226fc018e4Smrg    FcValueList	    *l, **value = NULL, *vl;
15232c393a42Smrg    FcPattern	    *m;
1524ca08ab68Smrg    FcStrSet	    *strs;
15256fc018e4Smrg    FcObject	    object = FC_INVALID_OBJECT;
15266fc018e4Smrg    FcPatternElt    **elt = NULL, *e;
15276fc018e4Smrg    int		    i, nobjs;
15286fc018e4Smrg    FcBool	    retval = FcTrue;
15296fc018e4Smrg    FcTest	    **tst = NULL;
15302c393a42Smrg
15312c393a42Smrg    if (!config)
15322c393a42Smrg    {
15332c393a42Smrg	config = FcConfigGetCurrent ();
15342c393a42Smrg	if (!config)
15352c393a42Smrg	    return FcFalse;
15362c393a42Smrg    }
15372c393a42Smrg
15382c393a42Smrg    switch (kind) {
15392c393a42Smrg    case FcMatchPattern:
15402c393a42Smrg	s = config->substPattern;
1541ca08ab68Smrg	strs = FcGetDefaultLangs ();
1542ca08ab68Smrg	if (strs)
1543ca08ab68Smrg	{
1544ca08ab68Smrg	    FcStrList *l = FcStrListCreate (strs);
1545ca08ab68Smrg	    FcChar8 *lang;
1546ca08ab68Smrg	    FcValue v;
154718bd4a06Smrg	    FcLangSet *lsund = FcLangSetCreate ();
1548ca08ab68Smrg
154918bd4a06Smrg	    FcLangSetAdd (lsund, (const FcChar8 *)"und");
1550ca08ab68Smrg	    FcStrSetDestroy (strs);
1551ca08ab68Smrg	    while (l && (lang = FcStrListNext (l)))
1552ca08ab68Smrg	    {
155318bd4a06Smrg		FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
155418bd4a06Smrg
155518bd4a06Smrg		if (e)
155618bd4a06Smrg		{
155718bd4a06Smrg		    FcValueListPtr ll;
155818bd4a06Smrg
155918bd4a06Smrg		    for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
156018bd4a06Smrg		    {
156118bd4a06Smrg			FcValue vv = FcValueCanonicalize (&ll->value);
156218bd4a06Smrg
156318bd4a06Smrg			if (vv.type == FcTypeLangSet)
156418bd4a06Smrg			{
156518bd4a06Smrg			    FcLangSet *ls = FcLangSetCreate ();
156618bd4a06Smrg			    FcBool b;
156718bd4a06Smrg
156818bd4a06Smrg			    FcLangSetAdd (ls, lang);
156918bd4a06Smrg			    b = FcLangSetContains (vv.u.l, ls);
157018bd4a06Smrg			    FcLangSetDestroy (ls);
157118bd4a06Smrg			    if (b)
157218bd4a06Smrg				goto bail_lang;
157318bd4a06Smrg			    if (FcLangSetContains (vv.u.l, lsund))
157418bd4a06Smrg				goto bail_lang;
157518bd4a06Smrg			}
157618bd4a06Smrg			else
157718bd4a06Smrg			{
157818bd4a06Smrg			    if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
157918bd4a06Smrg				goto bail_lang;
158018bd4a06Smrg			    if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
158118bd4a06Smrg				goto bail_lang;
158218bd4a06Smrg			}
158318bd4a06Smrg		    }
158418bd4a06Smrg		}
1585ca08ab68Smrg		v.type = FcTypeString;
1586ca08ab68Smrg		v.u.s = lang;
158718bd4a06Smrg
1588ca08ab68Smrg		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1589ca08ab68Smrg	    }
159018bd4a06Smrg	bail_lang:
1591ca08ab68Smrg	    FcStrListDone (l);
159218bd4a06Smrg	    FcLangSetDestroy (lsund);
1593ca08ab68Smrg	}
1594c9710b42Smrg	if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1595c9710b42Smrg	{
1596c9710b42Smrg	    FcChar8 *prgname = FcGetPrgname ();
1597c9710b42Smrg	    if (prgname)
1598c9710b42Smrg		FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1599c9710b42Smrg	}
16002c393a42Smrg	break;
16012c393a42Smrg    case FcMatchFont:
16022c393a42Smrg	s = config->substFont;
16032c393a42Smrg	break;
16042c393a42Smrg    case FcMatchScan:
16052c393a42Smrg	s = config->substScan;
16062c393a42Smrg	break;
16072c393a42Smrg    default:
16082c393a42Smrg	return FcFalse;
16092c393a42Smrg    }
16102c393a42Smrg
16116fc018e4Smrg    nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
1612cc1bebd6Smrg    value = (FcValueList **) malloc (sizeof(void *) * nobjs);
16136fc018e4Smrg    if (!value)
16146fc018e4Smrg    {
16156fc018e4Smrg	retval = FcFalse;
16166fc018e4Smrg	goto bail1;
16176fc018e4Smrg    }
1618cc1bebd6Smrg    elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs);
16196fc018e4Smrg    if (!elt)
16206fc018e4Smrg    {
16216fc018e4Smrg	retval = FcFalse;
16226fc018e4Smrg	goto bail1;
16236fc018e4Smrg    }
1624cc1bebd6Smrg    tst = (FcTest **) malloc (sizeof(void *) * nobjs);
16256fc018e4Smrg    if (!tst)
16266fc018e4Smrg    {
16276fc018e4Smrg	retval = FcFalse;
16286fc018e4Smrg	goto bail1;
16296fc018e4Smrg    }
16302c393a42Smrg
16312c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
16322c393a42Smrg    {
16332c393a42Smrg	printf ("FcConfigSubstitute ");
16342c393a42Smrg	FcPatternPrint (p);
16352c393a42Smrg    }
16362c393a42Smrg    for (; s; s = s->next)
16372c393a42Smrg    {
16386fc018e4Smrg	r = s->rule;
16396fc018e4Smrg	for (i = 0; i < nobjs; i++)
16402c393a42Smrg	{
16416fc018e4Smrg	    elt[i] = NULL;
16426fc018e4Smrg	    value[i] = NULL;
16436fc018e4Smrg	    tst[i] = NULL;
16446fc018e4Smrg	}
16456fc018e4Smrg	for (; r; r = r->next)
16466fc018e4Smrg	{
16476fc018e4Smrg	    switch (r->type) {
16486fc018e4Smrg	    case FcRuleUnknown:
16496fc018e4Smrg		/* shouldn't be reached */
16506fc018e4Smrg		break;
16516fc018e4Smrg	    case FcRuleTest:
16526fc018e4Smrg		object = FC_OBJ_ID (r->u.test->object);
16536fc018e4Smrg		/*
16546fc018e4Smrg		 * Check the tests to see if
16556fc018e4Smrg		 * they all match the pattern
16566fc018e4Smrg		 */
16576fc018e4Smrg		if (FcDebug () & FC_DBG_EDIT)
16582c393a42Smrg		{
16596fc018e4Smrg		    printf ("FcConfigSubstitute test ");
16606fc018e4Smrg		    FcTestPrint (r->u.test);
16612c393a42Smrg		}
16626fc018e4Smrg		if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
16636fc018e4Smrg		    m = p_pat;
16642c393a42Smrg		else
16656fc018e4Smrg		    m = p;
16666fc018e4Smrg		if (m)
16676fc018e4Smrg		    e = FcPatternObjectFindElt (m, r->u.test->object);
16686fc018e4Smrg		else
16696fc018e4Smrg		    e = NULL;
16706fc018e4Smrg		/* different 'kind' won't be the target of edit */
16716fc018e4Smrg		if (!elt[object] && kind == r->u.test->kind)
16722c393a42Smrg		{
16736fc018e4Smrg		    elt[object] = e;
16746fc018e4Smrg		    tst[object] = r->u.test;
16752c393a42Smrg		}
16762c393a42Smrg		/*
16776fc018e4Smrg		 * If there's no such field in the font,
16786fc018e4Smrg		 * then FcQualAll matches while FcQualAny does not
16792c393a42Smrg		 */
16806fc018e4Smrg		if (!e)
16812c393a42Smrg		{
16826fc018e4Smrg		    if (r->u.test->qual == FcQualAll)
16836fc018e4Smrg		    {
16846fc018e4Smrg			value[object] = NULL;
16856fc018e4Smrg			continue;
16866fc018e4Smrg		    }
16876fc018e4Smrg		    else
16886fc018e4Smrg		    {
16896fc018e4Smrg			if (FcDebug () & FC_DBG_EDIT)
16906fc018e4Smrg			    printf ("No match\n");
16916fc018e4Smrg			goto bail;
16926fc018e4Smrg		    }
16936fc018e4Smrg		}
16946fc018e4Smrg		/*
16956fc018e4Smrg		 * Check to see if there is a match, mark the location
16966fc018e4Smrg		 * to apply match-relative edits
16976fc018e4Smrg		 */
16986fc018e4Smrg		vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
16996fc018e4Smrg		/* different 'kind' won't be the target of edit */
17006fc018e4Smrg		if (!value[object] && kind == r->u.test->kind)
17016fc018e4Smrg		    value[object] = vl;
17026fc018e4Smrg		if (!vl ||
17036fc018e4Smrg		    (r->u.test->qual == FcQualFirst && vl != e->values) ||
17046fc018e4Smrg		    (r->u.test->qual == FcQualNotFirst && vl == e->values))
17056fc018e4Smrg		{
17066fc018e4Smrg		    if (FcDebug () & FC_DBG_EDIT)
17076fc018e4Smrg			printf ("No match\n");
17086fc018e4Smrg		    goto bail;
17096fc018e4Smrg		}
17106fc018e4Smrg		break;
17116fc018e4Smrg	    case FcRuleEdit:
17126fc018e4Smrg		object = FC_OBJ_ID (r->u.edit->object);
17136fc018e4Smrg		if (FcDebug () & FC_DBG_EDIT)
17146fc018e4Smrg		{
17156fc018e4Smrg		    printf ("Substitute ");
17166fc018e4Smrg		    FcEditPrint (r->u.edit);
17176fc018e4Smrg		    printf ("\n\n");
17186fc018e4Smrg		}
17196fc018e4Smrg		/*
17206fc018e4Smrg		 * Evaluate the list of expressions
17216fc018e4Smrg		 */
17226fc018e4Smrg		l = FcConfigValues (p, p_pat,kind,  r->u.edit->expr, r->u.edit->binding);
17236fc018e4Smrg		if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
17246fc018e4Smrg		    elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
17256fc018e4Smrg
17266fc018e4Smrg		switch (FC_OP_GET_OP (r->u.edit->op)) {
17276fc018e4Smrg		case FcOpAssign:
17282c393a42Smrg		    /*
17296fc018e4Smrg		     * If there was a test, then replace the matched
17306fc018e4Smrg		     * value with the new list of values
17312c393a42Smrg		     */
17326fc018e4Smrg		    if (value[object])
17336fc018e4Smrg		    {
17346fc018e4Smrg			FcValueList	*thisValue = value[object];
17356fc018e4Smrg			FcValueList	*nextValue = l;
17366fc018e4Smrg
17376fc018e4Smrg			/*
17386fc018e4Smrg			 * Append the new list of values after the current value
17396fc018e4Smrg			 */
17406fc018e4Smrg			FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
17416fc018e4Smrg			/*
17426fc018e4Smrg			 * Delete the marked value
17436fc018e4Smrg			 */
17446fc018e4Smrg			if (thisValue)
17456fc018e4Smrg			    FcConfigDel (&elt[object]->values, thisValue);
17466fc018e4Smrg			/*
17476fc018e4Smrg			 * Adjust a pointer into the value list to ensure
17486fc018e4Smrg			 * future edits occur at the same place
17496fc018e4Smrg			 */
17506fc018e4Smrg			value[object] = nextValue;
17516fc018e4Smrg			break;
17526fc018e4Smrg		    }
17536fc018e4Smrg		    /* fall through ... */
17546fc018e4Smrg		case FcOpAssignReplace:
17552c393a42Smrg		    /*
17566fc018e4Smrg		     * Delete all of the values and insert
17576fc018e4Smrg		     * the new set
17582c393a42Smrg		     */
17596fc018e4Smrg		    FcConfigPatternDel (p, r->u.edit->object);
17606fc018e4Smrg		    FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
17612c393a42Smrg		    /*
17626fc018e4Smrg		     * Adjust a pointer into the value list as they no
17636fc018e4Smrg		     * longer point to anything valid
17642c393a42Smrg		     */
17656fc018e4Smrg		    value[object] = NULL;
17666fc018e4Smrg		    break;
17676fc018e4Smrg		case FcOpPrepend:
17686fc018e4Smrg		    if (value[object])
17692c393a42Smrg		    {
17706fc018e4Smrg			FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
17716fc018e4Smrg			break;
17722c393a42Smrg		    }
17736fc018e4Smrg		    /* fall through ... */
17746fc018e4Smrg		case FcOpPrependFirst:
17756fc018e4Smrg		    FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
17762c393a42Smrg		    break;
17776fc018e4Smrg		case FcOpAppend:
17786fc018e4Smrg		    if (value[object])
17792c393a42Smrg		    {
17806fc018e4Smrg			FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
17816fc018e4Smrg			break;
17822c393a42Smrg		    }
17836fc018e4Smrg		    /* fall through ... */
17846fc018e4Smrg		case FcOpAppendLast:
17856fc018e4Smrg		    FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
17862c393a42Smrg		    break;
17876fc018e4Smrg		case FcOpDelete:
17886fc018e4Smrg		    if (value[object])
17896fc018e4Smrg		    {
17906fc018e4Smrg			FcConfigDel (&elt[object]->values, value[object]);
17916fc018e4Smrg			break;
17926fc018e4Smrg		    }
17936fc018e4Smrg		    /* fall through ... */
17946fc018e4Smrg		case FcOpDeleteAll:
17956fc018e4Smrg		    FcConfigPatternDel (p, r->u.edit->object);
17966fc018e4Smrg		    break;
17976fc018e4Smrg		default:
17986fc018e4Smrg		    FcValueListDestroy (l);
17992c393a42Smrg		    break;
18002c393a42Smrg		}
18016fc018e4Smrg		/*
18026fc018e4Smrg		 * Now go through the pattern and eliminate
18036fc018e4Smrg		 * any properties without data
18046fc018e4Smrg		 */
18056fc018e4Smrg		FcConfigPatternCanon (p, r->u.edit->object);
18066fc018e4Smrg
18076fc018e4Smrg		if (FcDebug () & FC_DBG_EDIT)
1808c9710b42Smrg		{
18096fc018e4Smrg		    printf ("FcConfigSubstitute edit");
18106fc018e4Smrg		    FcPatternPrint (p);
1811c9710b42Smrg		}
18122c393a42Smrg		break;
18132c393a42Smrg	    }
18142c393a42Smrg	}
18156fc018e4Smrg    bail:;
18162c393a42Smrg    }
18172c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
18182c393a42Smrg    {
18192c393a42Smrg	printf ("FcConfigSubstitute done");
18202c393a42Smrg	FcPatternPrint (p);
18212c393a42Smrg    }
18226fc018e4Smrgbail1:
18236fc018e4Smrg    if (elt)
18246fc018e4Smrg	free (elt);
18256fc018e4Smrg    if (value)
18266fc018e4Smrg	free (value);
18276fc018e4Smrg    if (tst)
18286fc018e4Smrg	free (tst);
18296fc018e4Smrg
18306fc018e4Smrg    return retval;
18312c393a42Smrg}
18322c393a42Smrg
18332c393a42SmrgFcBool
18342c393a42SmrgFcConfigSubstitute (FcConfig	*config,
18352c393a42Smrg		    FcPattern	*p,
18362c393a42Smrg		    FcMatchKind	kind)
18372c393a42Smrg{
18382c393a42Smrg    return FcConfigSubstituteWithPat (config, p, 0, kind);
18392c393a42Smrg}
18402c393a42Smrg
18412c393a42Smrg#if defined (_WIN32)
18422c393a42Smrg
1843c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
184418bd4a06SmrgFcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
18452c393a42Smrg
18462c393a42Smrg#  if (defined (PIC) || defined (DLL_EXPORT))
18472c393a42Smrg
1848c9710b42SmrgBOOL WINAPI
1849c9710b42SmrgDllMain (HINSTANCE hinstDLL,
1850c9710b42Smrg	 DWORD     fdwReason,
1851c9710b42Smrg	 LPVOID    lpvReserved);
1852c9710b42Smrg
18532c393a42SmrgBOOL WINAPI
18542c393a42SmrgDllMain (HINSTANCE hinstDLL,
18552c393a42Smrg	 DWORD     fdwReason,
18562c393a42Smrg	 LPVOID    lpvReserved)
18572c393a42Smrg{
18582c393a42Smrg  FcChar8 *p;
18592c393a42Smrg
18602c393a42Smrg  switch (fdwReason) {
18612c393a42Smrg  case DLL_PROCESS_ATTACH:
1862ca08ab68Smrg      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
18632c393a42Smrg			      sizeof (fontconfig_path)))
18642c393a42Smrg	  break;
18652c393a42Smrg
18662c393a42Smrg      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
18672c393a42Smrg       * assume it's a Unix-style installation tree, and use
18682c393a42Smrg       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
18692c393a42Smrg       * folder where the DLL is as FONTCONFIG_PATH.
18702c393a42Smrg       */
1871ca08ab68Smrg      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
18722c393a42Smrg      if (p)
18732c393a42Smrg      {
18742c393a42Smrg	  *p = '\0';
1875ca08ab68Smrg	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1876ca08ab68Smrg	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1877ca08ab68Smrg		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
18782c393a42Smrg	      *p = '\0';
187918bd4a06Smrg	  strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
1880ca08ab68Smrg	  strcat ((char *) fontconfig_path, "\\etc\\fonts");
18812c393a42Smrg      }
18822c393a42Smrg      else
18832c393a42Smrg          fontconfig_path[0] = '\0';
1884ca08ab68Smrg
18852c393a42Smrg      break;
18862c393a42Smrg  }
18872c393a42Smrg
18882c393a42Smrg  return TRUE;
18892c393a42Smrg}
18902c393a42Smrg
18912c393a42Smrg#  endif /* !PIC */
18922c393a42Smrg
18932c393a42Smrg#undef FONTCONFIG_PATH
18942c393a42Smrg#define FONTCONFIG_PATH fontconfig_path
18952c393a42Smrg
18962c393a42Smrg#endif /* !_WIN32 */
18972c393a42Smrg
18982c393a42Smrg#ifndef FONTCONFIG_FILE
18992c393a42Smrg#define FONTCONFIG_FILE	"fonts.conf"
19002c393a42Smrg#endif
19012c393a42Smrg
19022c393a42Smrgstatic FcChar8 *
19032c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
19042c393a42Smrg{
19052c393a42Smrg    FcChar8    *path;
1906ca08ab68Smrg    int         size, osize;
19072c393a42Smrg
19082c393a42Smrg    if (!dir)
19092c393a42Smrg	dir = (FcChar8 *) "";
1910ca08ab68Smrg
1911ca08ab68Smrg    osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1912ca08ab68Smrg    /*
1913ca08ab68Smrg     * workaround valgrind warning because glibc takes advantage of how it knows memory is
1914ca08ab68Smrg     * allocated to implement strlen by reading in groups of 4
1915ca08ab68Smrg     */
1916ca08ab68Smrg    size = (osize + 3) & ~3;
1917ca08ab68Smrg
1918ca08ab68Smrg    path = malloc (size);
19192c393a42Smrg    if (!path)
19202c393a42Smrg	return 0;
19212c393a42Smrg
19222c393a42Smrg    strcpy ((char *) path, (const char *) dir);
19232c393a42Smrg    /* make sure there's a single separator */
19242c393a42Smrg#ifdef _WIN32
19252c393a42Smrg    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
19262c393a42Smrg		      path[strlen((char *) path)-1] != '\\')) &&
19272c393a42Smrg	!(file[0] == '/' ||
19282c393a42Smrg	  file[0] == '\\' ||
19292c393a42Smrg	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
19302c393a42Smrg	strcat ((char *) path, "\\");
19312c393a42Smrg#else
19322c393a42Smrg    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
19332c393a42Smrg	strcat ((char *) path, "/");
1934c9710b42Smrg    else
1935c9710b42Smrg	osize--;
19362c393a42Smrg#endif
19372c393a42Smrg    strcat ((char *) path, (char *) file);
19382c393a42Smrg
19392c393a42Smrg    if (access ((char *) path, R_OK) == 0)
19402c393a42Smrg	return path;
1941ca08ab68Smrg
19422c393a42Smrg    FcStrFree (path);
1943ca08ab68Smrg
19442c393a42Smrg    return 0;
19452c393a42Smrg}
19462c393a42Smrg
19472c393a42Smrgstatic FcChar8 **
19482c393a42SmrgFcConfigGetPath (void)
19492c393a42Smrg{
19502c393a42Smrg    FcChar8    **path;
19512c393a42Smrg    FcChar8    *env, *e, *colon;
19522c393a42Smrg    FcChar8    *dir;
19532c393a42Smrg    int	    npath;
19542c393a42Smrg    int	    i;
19552c393a42Smrg
19562c393a42Smrg    npath = 2;	/* default dir + null */
19572c393a42Smrg    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
19582c393a42Smrg    if (env)
19592c393a42Smrg    {
19602c393a42Smrg	e = env;
19612c393a42Smrg	npath++;
19622c393a42Smrg	while (*e)
19632c393a42Smrg	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
19642c393a42Smrg		npath++;
19652c393a42Smrg    }
19662c393a42Smrg    path = calloc (npath, sizeof (FcChar8 *));
19672c393a42Smrg    if (!path)
19682c393a42Smrg	goto bail0;
19692c393a42Smrg    i = 0;
19702c393a42Smrg
19712c393a42Smrg    if (env)
19722c393a42Smrg    {
19732c393a42Smrg	e = env;
1974ca08ab68Smrg	while (*e)
19752c393a42Smrg	{
19762c393a42Smrg	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
19772c393a42Smrg	    if (!colon)
19782c393a42Smrg		colon = e + strlen ((char *) e);
19792c393a42Smrg	    path[i] = malloc (colon - e + 1);
19802c393a42Smrg	    if (!path[i])
19812c393a42Smrg		goto bail1;
19822c393a42Smrg	    strncpy ((char *) path[i], (const char *) e, colon - e);
19832c393a42Smrg	    path[i][colon - e] = '\0';
19842c393a42Smrg	    if (*colon)
19852c393a42Smrg		e = colon + 1;
19862c393a42Smrg	    else
19872c393a42Smrg		e = colon;
19882c393a42Smrg	    i++;
19892c393a42Smrg	}
19902c393a42Smrg    }
1991ca08ab68Smrg
19922c393a42Smrg#ifdef _WIN32
19932c393a42Smrg	if (fontconfig_path[0] == '\0')
19942c393a42Smrg	{
1995a6844aabSmrg		char *p;
1996ca08ab68Smrg		if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
19972c393a42Smrg			goto bail1;
1998ca08ab68Smrg		p = strrchr ((const char *) fontconfig_path, '\\');
19992c393a42Smrg		if (p) *p = '\0';
2000ca08ab68Smrg		strcat ((char *) fontconfig_path, "\\fonts");
20012c393a42Smrg	}
20022c393a42Smrg#endif
20032c393a42Smrg    dir = (FcChar8 *) FONTCONFIG_PATH;
20042c393a42Smrg    path[i] = malloc (strlen ((char *) dir) + 1);
20052c393a42Smrg    if (!path[i])
20062c393a42Smrg	goto bail1;
20072c393a42Smrg    strcpy ((char *) path[i], (const char *) dir);
20082c393a42Smrg    return path;
20092c393a42Smrg
20102c393a42Smrgbail1:
20112c393a42Smrg    for (i = 0; path[i]; i++)
20122c393a42Smrg	free (path[i]);
20132c393a42Smrg    free (path);
20142c393a42Smrgbail0:
20152c393a42Smrg    return 0;
20162c393a42Smrg}
20172c393a42Smrg
20182c393a42Smrgstatic void
20192c393a42SmrgFcConfigFreePath (FcChar8 **path)
20202c393a42Smrg{
20212c393a42Smrg    FcChar8    **p;
20222c393a42Smrg
20232c393a42Smrg    for (p = path; *p; p++)
20242c393a42Smrg	free (*p);
20252c393a42Smrg    free (path);
20262c393a42Smrg}
20272c393a42Smrg
2028c9710b42Smrgstatic FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
20292c393a42Smrg
20302c393a42SmrgFcChar8 *
20312c393a42SmrgFcConfigHome (void)
20322c393a42Smrg{
20332c393a42Smrg    if (_FcConfigHomeEnabled)
20342c393a42Smrg    {
20352c393a42Smrg        char *home = getenv ("HOME");
20362c393a42Smrg
20372c393a42Smrg#ifdef _WIN32
20382c393a42Smrg	if (home == NULL)
20392c393a42Smrg	    home = getenv ("USERPROFILE");
20402c393a42Smrg#endif
20412c393a42Smrg
20422c393a42Smrg	return (FcChar8 *) home;
20432c393a42Smrg    }
20442c393a42Smrg    return 0;
20452c393a42Smrg}
20462c393a42Smrg
2047ca08ab68SmrgFcChar8 *
2048ca08ab68SmrgFcConfigXdgCacheHome (void)
2049ca08ab68Smrg{
2050ca08ab68Smrg    const char *env = getenv ("XDG_CACHE_HOME");
2051ca08ab68Smrg    FcChar8 *ret = NULL;
2052ca08ab68Smrg
205318bd4a06Smrg    if (!_FcConfigHomeEnabled)
205418bd4a06Smrg	return NULL;
2055ca08ab68Smrg    if (env)
2056ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2057ca08ab68Smrg    else
2058ca08ab68Smrg    {
2059ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2060ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2061ca08ab68Smrg
2062ca08ab68Smrg	ret = malloc (len + 7 + 1);
2063ca08ab68Smrg	if (ret)
2064ca08ab68Smrg	{
2065ca08ab68Smrg	    memcpy (ret, home, len);
2066ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
2067ca08ab68Smrg	    ret[len + 7] = 0;
2068ca08ab68Smrg	}
2069ca08ab68Smrg    }
2070ca08ab68Smrg
2071ca08ab68Smrg    return ret;
2072ca08ab68Smrg}
2073ca08ab68Smrg
2074ca08ab68SmrgFcChar8 *
2075ca08ab68SmrgFcConfigXdgConfigHome (void)
2076ca08ab68Smrg{
2077ca08ab68Smrg    const char *env = getenv ("XDG_CONFIG_HOME");
2078ca08ab68Smrg    FcChar8 *ret = NULL;
2079ca08ab68Smrg
208018bd4a06Smrg    if (!_FcConfigHomeEnabled)
208118bd4a06Smrg	return NULL;
2082ca08ab68Smrg    if (env)
2083ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2084ca08ab68Smrg    else
2085ca08ab68Smrg    {
2086ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2087ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2088ca08ab68Smrg
2089ca08ab68Smrg	ret = malloc (len + 8 + 1);
2090ca08ab68Smrg	if (ret)
2091ca08ab68Smrg	{
2092ca08ab68Smrg	    memcpy (ret, home, len);
2093ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2094ca08ab68Smrg	    ret[len + 8] = 0;
2095ca08ab68Smrg	}
2096ca08ab68Smrg    }
2097ca08ab68Smrg
2098ca08ab68Smrg    return ret;
2099ca08ab68Smrg}
2100ca08ab68Smrg
2101ca08ab68SmrgFcChar8 *
2102ca08ab68SmrgFcConfigXdgDataHome (void)
2103ca08ab68Smrg{
2104ca08ab68Smrg    const char *env = getenv ("XDG_DATA_HOME");
2105ca08ab68Smrg    FcChar8 *ret = NULL;
2106ca08ab68Smrg
210718bd4a06Smrg    if (!_FcConfigHomeEnabled)
210818bd4a06Smrg	return NULL;
2109ca08ab68Smrg    if (env)
2110ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2111ca08ab68Smrg    else
2112ca08ab68Smrg    {
2113ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2114ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2115ca08ab68Smrg
2116ca08ab68Smrg	ret = malloc (len + 13 + 1);
2117ca08ab68Smrg	if (ret)
2118ca08ab68Smrg	{
2119ca08ab68Smrg	    memcpy (ret, home, len);
2120ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2121ca08ab68Smrg	    ret[len + 13] = 0;
2122ca08ab68Smrg	}
2123ca08ab68Smrg    }
2124ca08ab68Smrg
2125ca08ab68Smrg    return ret;
2126ca08ab68Smrg}
2127ca08ab68Smrg
21282c393a42SmrgFcBool
21292c393a42SmrgFcConfigEnableHome (FcBool enable)
21302c393a42Smrg{
21312c393a42Smrg    FcBool  prev = _FcConfigHomeEnabled;
21322c393a42Smrg    _FcConfigHomeEnabled = enable;
21332c393a42Smrg    return prev;
21342c393a42Smrg}
21352c393a42Smrg
21362c393a42SmrgFcChar8 *
21372c393a42SmrgFcConfigFilename (const FcChar8 *url)
21382c393a42Smrg{
21392c393a42Smrg    FcChar8    *file, *dir, **path, **p;
21402c393a42Smrg
21412c393a42Smrg    if (!url || !*url)
21422c393a42Smrg    {
21432c393a42Smrg	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
21442c393a42Smrg	if (!url)
21452c393a42Smrg	    url = (FcChar8 *) FONTCONFIG_FILE;
21462c393a42Smrg    }
21472c393a42Smrg    file = 0;
21482c393a42Smrg
21492c393a42Smrg#ifdef _WIN32
21502c393a42Smrg    if (isalpha (*url) &&
21512c393a42Smrg	url[1] == ':' &&
21522c393a42Smrg	(url[2] == '/' || url[2] == '\\'))
21532c393a42Smrg	goto absolute_path;
21542c393a42Smrg#endif
21552c393a42Smrg
21562c393a42Smrg    switch (*url) {
21572c393a42Smrg    case '~':
21582c393a42Smrg	dir = FcConfigHome ();
21592c393a42Smrg	if (dir)
21602c393a42Smrg	    file = FcConfigFileExists (dir, url + 1);
21612c393a42Smrg	else
21622c393a42Smrg	    file = 0;
21632c393a42Smrg	break;
21642c393a42Smrg#ifdef _WIN32
21652c393a42Smrg    case '\\':
21662c393a42Smrg    absolute_path:
21672c393a42Smrg#endif
21682c393a42Smrg    case '/':
21692c393a42Smrg	file = FcConfigFileExists (0, url);
21702c393a42Smrg	break;
21712c393a42Smrg    default:
21722c393a42Smrg	path = FcConfigGetPath ();
21732c393a42Smrg	if (!path)
2174ca08ab68Smrg	    return NULL;
21752c393a42Smrg	for (p = path; *p; p++)
21762c393a42Smrg	{
21772c393a42Smrg	    file = FcConfigFileExists (*p, url);
21782c393a42Smrg	    if (file)
21792c393a42Smrg		break;
21802c393a42Smrg	}
21812c393a42Smrg	FcConfigFreePath (path);
21822c393a42Smrg	break;
21832c393a42Smrg    }
2184ca08ab68Smrg
21852c393a42Smrg    return file;
21862c393a42Smrg}
21872c393a42Smrg
21882c393a42Smrg/*
21892c393a42Smrg * Manage the application-specific fonts
21902c393a42Smrg */
21912c393a42Smrg
21922c393a42SmrgFcBool
21932c393a42SmrgFcConfigAppFontAddFile (FcConfig    *config,
21942c393a42Smrg			const FcChar8  *file)
21952c393a42Smrg{
21962c393a42Smrg    FcFontSet	*set;
21972c393a42Smrg    FcStrSet	*subdirs;
21982c393a42Smrg    FcStrList	*sublist;
21992c393a42Smrg    FcChar8	*subdir;
22002c393a42Smrg
22012c393a42Smrg    if (!config)
22022c393a42Smrg    {
22032c393a42Smrg	config = FcConfigGetCurrent ();
22042c393a42Smrg	if (!config)
22052c393a42Smrg	    return FcFalse;
22062c393a42Smrg    }
22072c393a42Smrg
220818bd4a06Smrg    subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
22092c393a42Smrg    if (!subdirs)
22102c393a42Smrg	return FcFalse;
2211ca08ab68Smrg
22122c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
22132c393a42Smrg    if (!set)
22142c393a42Smrg    {
22152c393a42Smrg	set = FcFontSetCreate ();
22162c393a42Smrg	if (!set)
22172c393a42Smrg	{
22182c393a42Smrg	    FcStrSetDestroy (subdirs);
22192c393a42Smrg	    return FcFalse;
22202c393a42Smrg	}
22212c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
22222c393a42Smrg    }
22232c393a42Smrg
22242c393a42Smrg    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
22252c393a42Smrg    {
22262c393a42Smrg	FcStrSetDestroy (subdirs);
22272c393a42Smrg	return FcFalse;
22282c393a42Smrg    }
22292c393a42Smrg    if ((sublist = FcStrListCreate (subdirs)))
22302c393a42Smrg    {
22312c393a42Smrg	while ((subdir = FcStrListNext (sublist)))
22322c393a42Smrg	{
22332c393a42Smrg	    FcConfigAppFontAddDir (config, subdir);
22342c393a42Smrg	}
22352c393a42Smrg	FcStrListDone (sublist);
22362c393a42Smrg    }
22372c393a42Smrg    FcStrSetDestroy (subdirs);
22382c393a42Smrg    return FcTrue;
22392c393a42Smrg}
22402c393a42Smrg
22412c393a42SmrgFcBool
22422c393a42SmrgFcConfigAppFontAddDir (FcConfig	    *config,
22432c393a42Smrg		       const FcChar8   *dir)
22442c393a42Smrg{
22452c393a42Smrg    FcFontSet	*set;
22462c393a42Smrg    FcStrSet	*dirs;
2247ca08ab68Smrg
22482c393a42Smrg    if (!config)
22492c393a42Smrg    {
22502c393a42Smrg	config = FcConfigGetCurrent ();
22512c393a42Smrg	if (!config)
22522c393a42Smrg	    return FcFalse;
22532c393a42Smrg    }
22542c393a42Smrg
225518bd4a06Smrg    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
22562c393a42Smrg    if (!dirs)
22572c393a42Smrg	return FcFalse;
2258ca08ab68Smrg
22592c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
22602c393a42Smrg    if (!set)
22612c393a42Smrg    {
22622c393a42Smrg	set = FcFontSetCreate ();
22632c393a42Smrg	if (!set)
22642c393a42Smrg	{
22652c393a42Smrg	    FcStrSetDestroy (dirs);
22662c393a42Smrg	    return FcFalse;
22672c393a42Smrg	}
22682c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
22692c393a42Smrg    }
2270ca08ab68Smrg
22712c393a42Smrg    FcStrSetAddFilename (dirs, dir);
2272ca08ab68Smrg
22732c393a42Smrg    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
22742c393a42Smrg    {
22752c393a42Smrg	FcStrSetDestroy (dirs);
22762c393a42Smrg	return FcFalse;
22772c393a42Smrg    }
22782c393a42Smrg    FcStrSetDestroy (dirs);
22792c393a42Smrg    return FcTrue;
22802c393a42Smrg}
22812c393a42Smrg
22822c393a42Smrgvoid
22832c393a42SmrgFcConfigAppFontClear (FcConfig	    *config)
22842c393a42Smrg{
22852c393a42Smrg    if (!config)
22862c393a42Smrg    {
22872c393a42Smrg	config = FcConfigGetCurrent ();
22882c393a42Smrg	if (!config)
22892c393a42Smrg	    return;
22902c393a42Smrg    }
22912c393a42Smrg
22922c393a42Smrg    FcConfigSetFonts (config, 0, FcSetApplication);
22932c393a42Smrg}
22942c393a42Smrg
22952c393a42Smrg/*
22962c393a42Smrg * Manage filename-based font source selectors
22972c393a42Smrg */
22982c393a42Smrg
22992c393a42SmrgFcBool
23002c393a42SmrgFcConfigGlobAdd (FcConfig	*config,
23012c393a42Smrg		 const FcChar8  *glob,
23022c393a42Smrg		 FcBool		accept)
23032c393a42Smrg{
23042c393a42Smrg    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
23052c393a42Smrg
23062c393a42Smrg    return FcStrSetAdd (set, glob);
23072c393a42Smrg}
23082c393a42Smrg
23092c393a42Smrgstatic FcBool
23102c393a42SmrgFcConfigGlobsMatch (const FcStrSet	*globs,
23112c393a42Smrg		    const FcChar8	*string)
23122c393a42Smrg{
23132c393a42Smrg    int	i;
23142c393a42Smrg
23152c393a42Smrg    for (i = 0; i < globs->num; i++)
2316c9710b42Smrg	if (FcStrGlobMatch (globs->strs[i], string))
23172c393a42Smrg	    return FcTrue;
23182c393a42Smrg    return FcFalse;
23192c393a42Smrg}
23202c393a42Smrg
23212c393a42SmrgFcBool
23222c393a42SmrgFcConfigAcceptFilename (FcConfig	*config,
23232c393a42Smrg			const FcChar8	*filename)
23242c393a42Smrg{
23252c393a42Smrg    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
23262c393a42Smrg	return FcTrue;
23272c393a42Smrg    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
23282c393a42Smrg	return FcFalse;
23292c393a42Smrg    return FcTrue;
23302c393a42Smrg}
23312c393a42Smrg
23322c393a42Smrg/*
23332c393a42Smrg * Manage font-pattern based font source selectors
23342c393a42Smrg */
23352c393a42Smrg
23362c393a42SmrgFcBool
23372c393a42SmrgFcConfigPatternsAdd (FcConfig	*config,
23382c393a42Smrg		     FcPattern	*pattern,
23392c393a42Smrg		     FcBool	accept)
23402c393a42Smrg{
23412c393a42Smrg    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
23422c393a42Smrg
23432c393a42Smrg    return FcFontSetAdd (set, pattern);
23442c393a42Smrg}
23452c393a42Smrg
23462c393a42Smrgstatic FcBool
23472c393a42SmrgFcConfigPatternsMatch (const FcFontSet	*patterns,
23482c393a42Smrg		       const FcPattern	*font)
23492c393a42Smrg{
23502c393a42Smrg    int i;
2351ca08ab68Smrg
23522c393a42Smrg    for (i = 0; i < patterns->nfont; i++)
23532c393a42Smrg	if (FcListPatternMatchAny (patterns->fonts[i], font))
23542c393a42Smrg	    return FcTrue;
23552c393a42Smrg    return FcFalse;
23562c393a42Smrg}
23572c393a42Smrg
23582c393a42SmrgFcBool
23592c393a42SmrgFcConfigAcceptFont (FcConfig	    *config,
23602c393a42Smrg		    const FcPattern *font)
23612c393a42Smrg{
23622c393a42Smrg    if (FcConfigPatternsMatch (config->acceptPatterns, font))
23632c393a42Smrg	return FcTrue;
23642c393a42Smrg    if (FcConfigPatternsMatch (config->rejectPatterns, font))
23652c393a42Smrg	return FcFalse;
23662c393a42Smrg    return FcTrue;
23672c393a42Smrg}
2368c9710b42Smrg
2369c9710b42Smrgconst FcChar8 *
2370c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config)
2371c9710b42Smrg{
2372c9710b42Smrg    if (!config)
2373c9710b42Smrg    {
2374c9710b42Smrg	config = FcConfigGetCurrent ();
2375c9710b42Smrg	if (!config)
2376c9710b42Smrg	    return NULL;
2377c9710b42Smrg    }
2378c9710b42Smrg
2379c9710b42Smrg    return config->sysRoot;
2380c9710b42Smrg}
2381c9710b42Smrg
2382c9710b42Smrgvoid
2383c9710b42SmrgFcConfigSetSysRoot (FcConfig      *config,
2384c9710b42Smrg		    const FcChar8 *sysroot)
2385c9710b42Smrg{
238618bd4a06Smrg    FcChar8 *s = NULL;
2387c9710b42Smrg    FcBool init = FcFalse;
2388c9710b42Smrg
2389c9710b42Smrg    if (!config)
2390c9710b42Smrg    {
2391c9710b42Smrg	/* We can't use FcConfigGetCurrent() here to ensure
2392c9710b42Smrg	 * the sysroot is set prior to initialize FcConfig,
2393c9710b42Smrg	 * to avoid loading caches from non-sysroot dirs.
2394c9710b42Smrg	 * So postpone the initialization later.
2395c9710b42Smrg	 */
2396c9710b42Smrg	config = fc_atomic_ptr_get (&_fcConfig);
2397c9710b42Smrg	if (!config)
2398c9710b42Smrg	{
2399c9710b42Smrg	    config = FcConfigCreate ();
2400c9710b42Smrg	    if (!config)
2401c9710b42Smrg		return;
2402c9710b42Smrg	    init = FcTrue;
2403c9710b42Smrg	}
2404c9710b42Smrg    }
2405c9710b42Smrg
240618bd4a06Smrg    if (sysroot)
240718bd4a06Smrg    {
240818bd4a06Smrg	s = FcStrCopyFilename (sysroot);
240918bd4a06Smrg	if (!s)
241018bd4a06Smrg	    return;
241118bd4a06Smrg    }
2412c9710b42Smrg
2413c9710b42Smrg    if (config->sysRoot)
2414c9710b42Smrg	FcStrFree (config->sysRoot);
2415c9710b42Smrg
2416c9710b42Smrg    config->sysRoot = s;
2417c9710b42Smrg    if (init)
2418c9710b42Smrg    {
2419c9710b42Smrg	config = FcInitLoadOwnConfigAndFonts (config);
2420c9710b42Smrg	FcConfigSetCurrent (config);
242118bd4a06Smrg	/* FcConfigSetCurrent() increases the refcount.
242218bd4a06Smrg	 * decrease it here to avoid the memory leak.
242318bd4a06Smrg	 */
242418bd4a06Smrg	FcConfigDestroy (config);
2425c9710b42Smrg    }
2426c9710b42Smrg}
2427c9710b42Smrg
24282c393a42Smrg#define __fccfg__
24292c393a42Smrg#include "fcaliastail.h"
24302c393a42Smrg#undef __fccfg__
2431